[memdisk] Add El Torito emulation for .ISO images
authorShao Miller <shao.miller@yrdsb.edu.on.ca>
Tue, 4 Aug 2009 01:45:34 +0000 (21:45 -0400)
committerShao Miller <shao.miller@yrdsb.edu.on.ca>
Tue, 4 Aug 2009 03:50:20 +0000 (23:50 -0400)
With this patch, users can now boot El Torito-bootable .ISO (CD/DVD) images.
The user should specify "iso" on the kernel command-line.

doc/memdisk.txt
memdisk/Makefile
memdisk/eltorito.c [new file with mode: 0644]
memdisk/eltorito.h [new file with mode: 0644]
memdisk/memdisk.inc
memdisk/memdisk_chs_512.asm
memdisk/memdisk_edd_512.asm
memdisk/memdisk_iso_2048.asm
memdisk/memdisk_iso_512.asm
memdisk/setup.c

index 79d7640..274a0b9 100644 (file)
@@ -75,6 +75,7 @@ b) If the disk image is less than 4,194,304 bytes (4096K, 4 MB) it is
    s=#         Specify number of sectors (max 63)
    floppy[=#]  The image is a floppy image[**]
    harddisk[=#]        The image is a hard disk image[**]
+   iso         The image is an El Torito ISO9660 image (drive 0xE0)
 
    # represents a decimal number.
 
index 8e76f3d..f397c97 100644 (file)
@@ -38,11 +38,11 @@ endif
 # Important: init.o16 must be first!!
 OBJS16   = init.o16 init32.o
 OBJS32   = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \
-          memmove.o unzip.o dskprobe.o \
+          memmove.o unzip.o dskprobe.o eltorito.o \
           memdisk_chs_512.o memdisk_edd_512.o \
           memdisk_iso_512.o memdisk_iso_2048.o
 
-CSRC     = setup.c msetup.c e820func.c conio.c unzip.c dskprobe.c
+CSRC     = setup.c msetup.c e820func.c conio.c unzip.c dskprobe.c eltorito.c
 SSRC     = start32.S memcpy.S memset.S memmove.S
 NASMSRC  = memdisk_chs_512.asm memdisk_edd_512.asm \
           memdisk_iso_512.asm memdisk_iso_2048.asm \
diff --git a/memdisk/eltorito.c b/memdisk/eltorito.c
new file mode 100644 (file)
index 0000000..7e0ba89
--- /dev/null
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.c
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
+#include "eltorito.h"
+
+#ifdef DBG_ELTORITO
+void eltorito_dump(uint32_t image)
+{
+    printf("-- El Torito dump --\n", image);
+
+    /* BVD starts at sector 17. */
+    struct edd4_bvd *bvd = (struct edd4_bvd *)(image + 17 * 2048);
+
+    printf("bvd.boot_rec_ind: 0x%02x\n", bvd->boot_rec_ind);
+    printf("bvd.iso9660_id: %c%c%c%c%c\n", bvd->iso9660_id[0],
+          bvd->iso9660_id[1], bvd->iso9660_id[2], bvd->iso9660_id[3],
+          bvd->iso9660_id[4]);
+    printf("bvd.ver: 0x%02x\n", bvd->ver);
+    printf("bvd.eltorito: %s\n", bvd->eltorito);
+    printf("bvd.boot_cat: 0x%08x\n", bvd->boot_cat);
+
+    struct edd4_bootcat *boot_cat =
+       (struct edd4_bootcat *)(image + bvd->boot_cat * 2048);
+
+    printf("boot_cat.validation_entry\n");
+    printf("  .header_id: 0x%02x\n", boot_cat->validation_entry.header_id);
+    printf("  .platform_id: 0x%02x\n", boot_cat->validation_entry.platform_id);
+    printf("  .id_string: %s\n", boot_cat->validation_entry.id_string);
+    printf("  .checksum: 0x%04x\n", boot_cat->validation_entry.checksum);
+    printf("  .key55: 0x%02x\n", boot_cat->validation_entry.key55);
+    printf("  .keyAA: 0x%02x\n", boot_cat->validation_entry.keyAA);
+    printf("boot_cat.initial_entry\n");
+    printf("  .header_id: 0x%02x\n", boot_cat->initial_entry.header_id);
+    printf("  .media_type: 0x%02x\n", boot_cat->initial_entry.media_type);
+    printf("  .load_seg: 0x%04x\n", boot_cat->initial_entry.load_seg);
+    printf("  .system_type: 0x%02x\n", boot_cat->initial_entry.system_type);
+    printf("  .sect_count: %d\n", boot_cat->initial_entry.sect_count);
+    printf("  .load_block: 0x%08x\n", boot_cat->initial_entry.load_block);
+}
+#endif
diff --git a/memdisk/eltorito.h b/memdisk/eltorito.h
new file mode 100644 (file)
index 0000000..7d46e1d
--- /dev/null
@@ -0,0 +1,83 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.h
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+
+/*
+ * Uncomment for El Torito debugging
+ *
+ * #define DBG_ELTORITO 1
+ */
+
+#ifdef DBG_ELTORITO
+extern void eltorito_dump(uint32_t);
+#endif
+
+/* EDD-4 Bootable Optical Disc Drive Boot Volume Descriptor */
+struct edd4_bvd {
+    uint8_t boot_rec_ind;      /* Boot Record Indicator */
+    uint8_t iso9660_id[5];     /* ISO9660 ID            */
+    uint8_t ver;               /* Descriptor Version    */
+    uint8_t eltorito[32];      /* "EL TORITO" etc.      */
+    uint8_t res1[32];          /* Reserved              */
+    uint32_t boot_cat;         /* Boot catalog sector   */
+    uint8_t res2[1973];                /* Reserved              */
+} __attribute__ ((packed));
+
+struct validation_entry {
+    uint8_t header_id;         /* Header ID                      */
+    uint8_t platform_id;       /* Platform ID                    */
+    uint16_t res1;             /* Reserved                       */
+    uint8_t id_string[24];     /* Manufacturer                   */
+    uint16_t checksum;         /* Sums with whole record to zero */
+    uint8_t key55;             /* Key byte 0x55                  */
+    uint8_t keyAA;             /* Key byte 0xAA                  */
+} __attribute__ ((packed));
+
+struct initial_entry {
+    uint8_t header_id;         /* Header ID                */
+    uint8_t media_type;                /* Media type               */
+    uint16_t load_seg;         /* Load segment             */
+    uint8_t system_type;       /* (Filesystem ID)          */
+    uint8_t res1;              /* Reserved                 */
+    uint16_t sect_count;       /* Emulated sectors to load */
+    uint32_t load_block;       /* Starting sector of image */
+    uint8_t res2[4];           /* Reserved                 */
+} __attribute__ ((packed));
+
+/* EDD-4 Bootable Optical Disc Drive Boot Catalog (fixed-size portions) */
+struct edd4_bootcat {
+    struct validation_entry validation_entry;
+    struct initial_entry initial_entry;
+} __attribute__ ((packed));
+
+/* EDD-4 CD Specification Packet */
+struct edd4_cd_pkt {
+    uint8_t size;              /* Packet size                     */
+    uint8_t type;              /* Boot media type (flags)         */
+    uint8_t driveno;           /* INT 13h drive number            */
+    uint8_t controller;                /* Controller index                */
+    uint32_t start;            /* Starting LBA of image           */
+    uint16_t devno;            /* Device number                   */
+    uint16_t userbuf;          /* User buffer segment             */
+    uint16_t load_seg;         /* Load segment                    */
+    uint16_t sect_count;       /* Emulated sectors to load        */
+    uint8_t geom1;             /* Cylinders bits 0 thru 7         */
+    uint8_t geom2;             /* Sects/track 0 thru 5, cyls 8, 9 */
+    uint8_t geom3;             /* Heads                           */
+} __attribute__ ((packed));
index 14f077a..98ad52b 100644 (file)
@@ -8,6 +8,7 @@
 ;
 ;   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
 ;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;   Portions copyright 2009 Shao Miller [El Torito code]
 ;
 ;  This program is free software; you can redistribute it and/or modify
 ;  it under the terms of the GNU General Public License as published by
@@ -135,6 +136,10 @@ Int13Start:
                mov ss,ax
                mov sp,[cs:MyStack]
 
+%if ELTORITO
+               cmp word [cs:SavedAX],4a00h     ; El Torito function?
+               jae our_drive                   ; We grab it
+%endif
                ; See if DL points to our class of device (FD, HD)
                push dx
                push dx
@@ -205,6 +210,14 @@ our_drive:
                ; Note: AX == P_AX here
                cmp ah,Int13FuncsCnt-1
                ja Invalid_jump
+%if ELTORITO
+               mov al,[CD_PKT.type]    ; Check if we are in
+               cmp al,0                ; El Torito no emulation mode
+               ja .emulation           ; No.  We support the function
+               cmp ah,3fh              ; Yes.  We must not support functions
+               jbe Invalid_jump        ; 0 through 3Fh.  Check and decide
+.emulation:
+%endif
                xor al,al               ; AL = 0 is standard entry condition
                mov di,ax
                shr di,7                ; Convert AH to an offset in DI
@@ -393,8 +406,9 @@ EDDPresence:
                jne Invalid
                mov P_BX,0AA55h         ; EDD signature
                mov P_AX,03000h         ; EDD 3.0
-               mov P_CX,0003h          ; Bit 0 - Fixed disk access subset
+               mov P_CX,0007h          ; Bit 0 - Fixed disk access subset
                                        ; Bit 1 - Locking and ejecting subset
+                                       ; Bit 2 - EDD subset
                pop ax                  ; Drop return address
                xor ax,ax               ; Success
                jmp DoneWeird           ; Success, but AH != 0, sigh...
@@ -575,10 +589,31 @@ edd_setup_regs:
 EDDEject:
                mov ax,0B200h           ; Volume Not Removable
                ret
-
+%if ELTORITO
+ElToritoTerminate:
+               TRACER 'T'
+               mov ax,[cs:SavedAX]
+               cmp al,1                ; We only support query, not terminate
+               jne ElToritoErr         ; Fail
+               mov es,P_DS             ; Caller's DS:SI pointed to packet
+               mov di,P_SI             ; We'll use ES:DI
+               mov si,CD_PKT.size      ; First byte is packet size
+               xor cx,0                ; Empty our count
+               ;mov cl,[ds:si]         ; We'll copy that many bytes
+               mov cl,13h
+               rep movsb               ; Copy until CX is zero
+               mov ax,0                ; Success
+               ret
+ElToritoEmulate:
+ElToritoBoot:
+ElToritoCatalog:
+ElToritoErr:
+               TRACER '!'
+               mov ax,100h             ; Invalid parameter
+               ret
+%endif ; ELTORITO
 %endif ; EDD
 
-
 ;
 ; INT 15h intercept routines
 ;
@@ -960,7 +995,14 @@ Int13Funcs dw Reset                ; 00h - RESET
                dw EDDSeek              ; 47h - EDD SEEK
                dw EDDGetParms          ; 48h - EDD GET PARAMETERS
                dw EDDDetectChange      ; 49h - EDD MEDIA CHANGE STATUS
-%endif
+%if ELTORITO                           ; EDD El Torito Functions
+                                       ; ELTORITO _must_ also have EDD
+               dw ElToritoEmulate      ; 4Ah - Initiate Disk Emulation
+               dw ElToritoTerminate    ; 4Bh - Terminate Disk Emulation
+               dw ElToritoBoot         ; 4Ch - Initiate Disk Emu. and Reboot
+               dw ElToritoCatalog      ; 4Dh - Return Boot Catalog
+%endif ; ELTORITO
+%endif ; EDD
 
 Int13FuncsEnd  equ $
 Int13FuncsCnt  equ (Int13FuncsEnd-Int13Funcs) >> 1
@@ -1070,7 +1112,24 @@ EDD_DPT:
 .res3          db 0                    ; Reserved
 .chksum                db 0                    ; DPI checksum
 
-%endif
+%if ELTORITO
+; El Torito CD Specification Packet - mostly filled in by installer
+CD_PKT:
+.size          db 13h  ; Packet size (19 bytes)
+.type          db 0    ; Boot media type (flags)
+.driveno       db 0E0h ; INT 13h drive number
+.controller    db 0    ; Controller index
+.start         dd 0    ; Starting LBA of image
+.devno         dw 0    ; Device number
+.user_buf      dw 0    ; User buffer segment
+.load_seg      dw 0    ; Load segment
+.sect_count    dw 0    ; Emulated sectors to load
+.geom1         db 0    ; Cylinders bits 0 thru 7
+.geom2         db 0    ; Sects/track 0 thru 5, cyls 8, 9
+.geom3         db 0    ; Heads
+%endif ; ELTORITO
+
+%endif ; EDD
 
                ; End patch area
                alignb 4, db 0
index 35acbbd..d4b0f75 100644 (file)
@@ -1,3 +1,4 @@
 %define EDD 0
+%define ELTORITO 0
 %define SECTORSIZE_LG2 9       ; log2(sector size)
 %include "memdisk.inc"
index fbd90c1..02d1737 100644 (file)
@@ -1,3 +1,4 @@
 %define EDD 1
+%define ELTORITO 0
 %define SECTORSIZE_LG2 9       ; log2(sector size)
 %include "memdisk.inc"
index 84a0554..0a44497 100644 (file)
@@ -1,3 +1,4 @@
 %define EDD 1
+%define ELTORITO 1
 %define SECTORSIZE_LG2 11      ; log2(sector size)
 %include "memdisk.inc"
index fbd90c1..e49b449 100644 (file)
@@ -1,3 +1,4 @@
 %define EDD 1
+%define ELTORITO 1
 %define SECTORSIZE_LG2 9       ; log2(sector size)
 %include "memdisk.inc"
index 9fd5c9e..41e87c1 100644 (file)
@@ -2,6 +2,7 @@
  *
  *   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *   Portions copyright 2009 Shao Miller [El Torito code]
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -15,6 +16,7 @@
 #include "bda.h"
 #include "dskprobe.h"
 #include "e820.h"
+#include "eltorito.h"
 #include "conio.h"
 #include "version.h"
 #include "memdisk.h"
@@ -143,8 +145,19 @@ struct patch_area {
 
     dpt_t dpt;
     struct edd_dpt edd_dpt;
+    struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */
 } __attribute__((packed));
 
+/* An EDD disk packet */
+struct edd_dsk_pkt {
+    uint8_t size;              /* Packet size        */
+    uint8_t res1;              /* Reserved           */
+    uint16_t count;            /* Count to transfer  */
+    uint32_t buf;              /* Buffer pointer     */
+    uint64_t start;            /* LBA to start from  */
+    uint64_t buf64;            /* 64-bit buf pointer */
+} __attribute__ ((packed));
+
 /*
  * Routine to seek for a command-line item and return a pointer
  * to the data portion, if present
@@ -322,11 +335,12 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
  * Figure out the "geometry" of the disk in question
  */
 struct geometry {
-    uint32_t sectors;          /* 512-byte sector count */
+    uint32_t sectors;          /* Sector count */
     uint32_t c, h, s;          /* C/H/S geometry */
     uint32_t offset;           /* Byte offset for disk */
     uint8_t type;              /* Type byte for INT 13h AH=08h */
     uint8_t driveno;           /* Drive no */
+    uint16_t sector_size;      /* Sector size in bytes (512 vs. 2048) */
     const char *hsrc, *ssrc;   /* Origins of H and S geometries */
 };
 
@@ -406,6 +420,8 @@ static const struct geometry *get_disk_image_geometry(uint32_t where,
 
     printf("command line: %s\n", shdr->cmdline);
 
+    hd_geometry.sector_size = 512;     /* Assume floppy/HDD at first */
+
     offset = 0;
     if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)))
        offset = v;
@@ -417,6 +433,71 @@ static const struct geometry *get_disk_image_geometry(uint32_t where,
     hd_geometry.sectors = sectors;
     hd_geometry.offset = offset;
 
+    if ((p = getcmditem("iso")) != CMD_NOTFOUND) {
+#ifdef DBG_ELTORITO
+       eltorito_dump(where);
+#endif
+       struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048);
+       /* Tiny sanity check */
+       if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1))
+           printf("El Torito BVD sanity check failed.\n");
+       struct edd4_bootcat *boot_cat =
+           (struct edd4_bootcat *)(where + bvd->boot_cat * 2048);
+       /* Another tiny sanity check */
+       if ((boot_cat->validation_entry.platform_id != 0) ||
+           (boot_cat->validation_entry.key55 != 0x55) ||
+           (boot_cat->validation_entry.keyAA != 0xAA))
+           printf("El Torito boot catalog sanity check failed.\n");
+       /* If we have an emulation mode, set the offset to the image */
+       if (boot_cat->initial_entry.media_type)
+           hd_geometry.offset += boot_cat->initial_entry.load_block * 2048;
+       if (boot_cat->initial_entry.media_type < 4) {
+           /* We're a floppy emulation mode or our params will be
+            * overwritten by the no emulation mode case
+            */
+           hd_geometry.driveno = 0x00;
+           hd_geometry.c = 80;
+           hd_geometry.h = 2;
+       }
+       switch (boot_cat->initial_entry.media_type) {
+       case 0:         /* No emulation   */
+           hd_geometry.driveno = 0xE0;
+           hd_geometry.type = 10;      /* ATAPI removable media device */
+           hd_geometry.c = 65535;
+           hd_geometry.h = 255;
+           hd_geometry.s = 15;
+           /* 2048-byte sectors, so adjust the size and count */
+           hd_geometry.sector_size = 2048;
+           sectors = (size - hd_geometry.offset) >> 11;
+           break;
+       case 1:         /* 1.2 MB floppy  */
+           hd_geometry.s = 15;
+           hd_geometry.type = 2;
+           sectors = 2400;
+           break;
+       case 2:         /* 1.44 MB floppy */
+           hd_geometry.s = 18;
+           hd_geometry.type = 4;
+           sectors = 2880;
+           break;
+       case 3:         /* 2.88 MB floppy */
+           hd_geometry.s = 36;
+           hd_geometry.type = 6;
+           sectors = 5760;
+           break;
+       case 4:
+           hd_geometry.driveno = 0x80;
+           hd_geometry.type = 0;
+           sectors = (size - hd_geometry.offset) >> 9;
+           break;
+       }
+       /* For HDD emulation, we figure out the geometry later. Otherwise: */
+       if (hd_geometry.s) {
+           hd_geometry.hsrc = hd_geometry.ssrc = "El Torito";
+       }
+       hd_geometry.sectors = sectors;
+    }
+
     /* Do we have a DOSEMU header? */
     memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu);
     if (!memcmp("DOSEMU", dosemu.magic, 7)) {
@@ -480,7 +561,7 @@ static const struct geometry *get_disk_image_geometry(uint32_t where,
 
        if (!(max_h | max_s)) {
            /* No FAT filesystem found to steal geometry from... */
-           if (sectors < 4096 * 2) {
+           if ((sectors < 4096 * 2) && (hd_geometry.sector_size == 512)) {
                int ok = 0;
                unsigned int xsectors = sectors;
 
@@ -541,7 +622,9 @@ static const struct geometry *get_disk_image_geometry(uint32_t where,
                const struct ptab_entry *ptab = (const struct ptab_entry *)
                    ((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16));
 
-               hd_geometry.driveno = 0x80;     /* Assume hard disk */
+               /* Assume hard disk */
+               if (!hd_geometry.driveno)
+                   hd_geometry.driveno = 0x80;
 
                if (*(uint16_t *) ((char *)where + 512 - 2) == 0xaa55) {
                    for (i = 0; i < 4; i++) {
@@ -718,12 +801,15 @@ void setup(const struct real_mode_args *rm_args_ptr)
     uint16_t dosmem_k;
     uint32_t stddosmem;
     const struct geometry *geometry;
+    const struct edd4_bvd *bvd;
+    const struct edd4_bootcat *boot_cat = 0;
     int total_size, cmdlinelen;
     com32sys_t regs;
     uint32_t ramdisk_image, ramdisk_size;
     uint32_t boot_base, rm_base;
     int bios_drives;
     int do_edd = 1;            /* 0 = no, 1 = yes, default is yes */
+    int do_eltorito = 0;       /* default is no */
     int no_bpt;                        /* No valid BPT presented */
     uint32_t boot_seg = 0;     /* Meaning 0000:7C00 */
     uint32_t boot_len = 512;   /* One sector */
@@ -762,13 +848,28 @@ void setup(const struct real_mode_args *rm_args_ptr)
     else
        do_edd = (geometry->driveno & 0x80) ? 1 : 0;
 
+    if (getcmditem("iso") != CMD_NOTFOUND) {
+       do_eltorito = 1;
+       do_edd = 1;             /* Mandatory */
+    }
+
     /* Choose the appropriate installable memdisk hook */
-    if (do_edd) {
-       bin_size = (int)&_binary_memdisk_edd_512_bin_size;
-       memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
+    if (do_eltorito) {
+       if (geometry->sector_size == 2048) {
+           bin_size = (int)&_binary_memdisk_iso_2048_bin_size;
+           memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start;
+       } else {
+           bin_size = (int)&_binary_memdisk_iso_512_bin_size;
+           memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start;
+       }
     } else {
-       bin_size = (int)&_binary_memdisk_chs_512_bin_size;
-       memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
+       if (do_edd) {
+           bin_size = (int)&_binary_memdisk_edd_512_bin_size;
+           memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
+       } else {
+           bin_size = (int)&_binary_memdisk_chs_512_bin_size;
+           memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
+       }
     }
 
     /* Reserve the ramdisk memory */
@@ -788,7 +889,7 @@ void setup(const struct real_mode_args *rm_args_ptr)
 
     pptr->driveno = geometry->driveno;
     pptr->drivetype = geometry->type;
-    pptr->cylinders = geometry->c;
+    pptr->cylinders = geometry->c;     /* Possible precision loss */
     pptr->heads = geometry->h;
     pptr->sectors = geometry->s;
     pptr->disksize = geometry->sectors;
@@ -884,7 +985,12 @@ void setup(const struct real_mode_args *rm_args_ptr)
            pptr->edd_dpt.c = geometry->c;
            pptr->edd_dpt.h = geometry->h;
            pptr->edd_dpt.s = geometry->s;
-           pptr->edd_dpt.flags |= 0x0002;      /* Geometry valid */
+           /* EDD-4 states that invalid geometry should be returned
+            * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an
+            * El Torito ODD.  Check for 2048-byte sector size
+            */
+           if (geometry->sector_size != 2048)
+               pptr->edd_dpt.flags |= 0x0002;  /* Geometry valid */
        }
        if (!(geometry->driveno & 0x80)) {
            /* Floppy drive.  Mark it as a removable device with
@@ -896,6 +1002,21 @@ void setup(const struct real_mode_args *rm_args_ptr)
        pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30);
     }
 
+    if (do_eltorito) {
+       bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048);
+       boot_cat =
+           (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048);
+       pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */
+       pptr->cd_pkt.driveno = geometry->driveno;
+       pptr->cd_pkt.start = boot_cat->initial_entry.load_block;
+       pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg;
+       pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count;
+       boot_len = pptr->cd_pkt.sect_count * 2048;
+       pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF;
+       pptr->cd_pkt.geom2 = (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0);
+       pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads);
+    }
+
     /* The size is given by hptr->total_size plus the size of the E820
        map -- 12 bytes per range; we may need as many as 2 additional
        ranges (each insertrange() can worst-case turn 1 area into 3)
@@ -1041,7 +1162,7 @@ void setup(const struct real_mode_args *rm_args_ptr)
        if (nhd > 128)
            nhd = 128;
 
-       wrz_8(BIOS_HD_COUNT, nhd);
+       if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd);
     } else {
        /* Update BIOS floppy disk count */
        uint8_t equip = rdz_8(BIOS_EQUIP);
@@ -1097,6 +1218,10 @@ void setup(const struct real_mode_args *rm_args_ptr)
     /* Reboot into the new "disk" */
     puts("Loading boot sector... ");
 
+    if (do_eltorito) {
+       /* 4 times as many 512-byte sectors in a 2048-byte sector */
+       boot_lba = pptr->cd_pkt.start * 4;
+    }
     memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba * 512, boot_len);
 
     if (getcmditem("pause") != CMD_NOTFOUND) {