Split bootsector execution code out into bootsector.c.
authorMichael Brown <mcb30@etherboot.org>
Mon, 29 Jan 2007 04:21:38 +0000 (04:21 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 29 Jan 2007 04:21:38 +0000 (04:21 +0000)
Added basic El Torito ISO image boot capability

src/arch/i386/image/bootsector.c [new file with mode: 0644]
src/arch/i386/image/eltorito.c [new file with mode: 0644]
src/arch/i386/include/bootsector.h [new file with mode: 0644]
src/arch/i386/include/int13.h
src/arch/i386/interface/pcbios/int13.c
src/core/config.c
src/drivers/block/ramdisk.c [new file with mode: 0644]

diff --git a/src/arch/i386/image/bootsector.c b/src/arch/i386/image/bootsector.c
new file mode 100644 (file)
index 0000000..d2711a8
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
+ *
+ * x86 bootsector image format
+ *
+ */
+
+#include <errno.h>
+#include <realmode.h>
+#include <biosint.h>
+#include <bootsector.h>
+
+/** Vector for storing original INT 18 handler
+ *
+ * We do not chain to this vector, so there is no need to place it in
+ * .text16.
+ */
+static struct segoff int18_vector;
+
+/** Vector for storing original INT 19 handler
+ *
+ * We do not chain to this vector, so there is no need to place it in
+ * .text16.
+ */
+static struct segoff int19_vector;
+
+/** Restart point for INT 18 or 19 */
+extern void bootsector_exec_fail ( void );
+
+/**
+ * Jump to preloaded bootsector
+ *
+ * @v segment          Real-mode segment
+ * @v offset           Real-mode offset
+ * @v drive            Drive number to pass to boot sector
+ * @ret rc             Return status code
+ */
+int call_bootsector ( unsigned int segment, unsigned int offset,
+                     unsigned int drive ) {
+       int discard_b, discard_D, discard_d;
+
+       DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
+
+       /* Hook INTs 18 and 19 to capture failure paths */
+       hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
+                             &int18_vector );
+       hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
+                             &int19_vector );
+
+       /* Boot the loaded sector
+        *
+        * We assume that the boot sector may completely destroy our
+        * real-mode stack, so we preserve everything we need in
+        * static storage.
+        */
+       __asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
+                                          "popw %%cs:saved_retaddr\n\t"
+                                          /* Save stack pointer */
+                                          "movw %%ss, %%ax\n\t"
+                                          "movw %%ax, %%cs:saved_ss\n\t"
+                                          "movw %%sp, %%cs:saved_sp\n\t"
+                                          /* Jump to boot sector */
+                                          "pushw %%bx\n\t"
+                                          "pushw %%di\n\t"
+                                          "lret\n\t"
+                                          /* Preserved variables */
+                                          "\nsaved_ss: .word 0\n\t"
+                                          "\nsaved_sp: .word 0\n\t"
+                                          "\nsaved_retaddr: .word 0\n\t"
+                                          /* Boot failure return point */
+                                          "\nbootsector_exec_fail:\n\t"
+                                          /* Restore stack pointer */
+                                          "movw %%cs:saved_ss, %%ax\n\t"
+                                          "movw %%ax, %%ss\n\t"
+                                          "movw %%cs:saved_sp, %%sp\n\t"
+                                          /* Return via saved address */
+                                          "jmp *%%cs:saved_retaddr\n\t" )
+                              : "=b" ( discard_b ), "=D" ( discard_D ),
+                                "=d" ( discard_d )
+                              : "b" ( segment ), "D" ( offset ),
+                                "d" ( drive )
+                              : "eax", "ecx", "esi", "ebp" );
+
+       DBG ( "Booted disk returned via INT 18 or 19\n" );
+
+       /* Unhook INTs 18 and 19 */
+       unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
+                               &int18_vector );
+       unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
+                               &int19_vector );
+       
+       return -ECANCELED;
+}
diff --git a/src/arch/i386/image/eltorito.c b/src/arch/i386/image/eltorito.c
new file mode 100644 (file)
index 0000000..456a510
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
+ *
+ * El Torito bootable ISO image format
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <bootsector.h>
+#include <int13.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/image.h>
+#include <gpxe/segment.h>
+#include <gpxe/ramdisk.h>
+#include <gpxe/shutdown.h>
+
+#define ISO9660_BLKSIZE 2048
+#define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
+
+/** An El Torito Boot Record Volume Descriptor */
+struct eltorito_vol_desc {
+       /** Boot record indicator; must be 0 */
+       uint8_t record_indicator;
+       /** ISO-9660 identifier; must be "CD001" */
+       uint8_t iso9660_id[5];
+       /** Version, must be 1 */
+       uint8_t version;
+       /** Boot system indicator; must be "EL TORITO SPECIFICATION" */
+       uint8_t system_indicator[32];
+       /** Unused */
+       uint8_t unused[32];
+       /** Boot catalog sector */
+       uint32_t sector;
+} __attribute__ (( packed ));
+
+/** An El Torito Boot Catalog Validation Entry */
+struct eltorito_validation_entry {
+       /** Header ID; must be 1 */
+       uint8_t header_id;
+       /** Platform ID
+        *
+        * 0 = 80x86
+        * 1 = PowerPC
+        * 2 = Mac
+        */
+       uint8_t platform_id;
+       /** Reserved */
+       uint16_t reserved;
+       /** ID string */
+       uint8_t id_string[24];
+       /** Checksum word */
+       uint16_t checksum;
+       /** Signature; must be 0xaa55 */
+       uint16_t signature;
+} __attribute__ (( packed ));
+
+/** A bootable entry in the El Torito Boot Catalog */
+struct eltorito_boot_entry {
+       /** Boot indicator
+        *
+        * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
+        */
+       uint8_t indicator;
+       /** Media type
+        *
+        */
+       uint8_t media_type;
+       /** Load segment */
+       uint16_t load_segment;
+       /** System type */
+       uint8_t filesystem;
+       /** Unused */
+       uint8_t reserved_a;
+       /** Sector count */
+       uint16_t length;
+       /** Starting sector */
+       uint32_t start;
+       /** Unused */
+       uint8_t reserved_b[20];
+} __attribute__ (( packed ));
+
+/** Boot indicator for a bootable ISO image */
+#define ELTORITO_BOOTABLE 0x88
+
+/** El Torito media types */
+enum eltorito_media_type {
+       /** No emulation */
+       ELTORITO_NO_EMULATION = 0,
+};
+
+struct image_type eltorito_image_type __image_type ( PROBE_NORMAL );
+
+/**
+ * Calculate 16-bit word checksum
+ *
+ * @v data             Data to checksum
+ * @v len              Length (in bytes, must be even)
+ * @ret sum            Checksum
+ */
+static unsigned int word_checksum ( void *data, size_t len ) {
+       uint16_t *words;
+       uint16_t sum = 0;
+
+       for ( words = data ; len ; words++, len -= 2 ) {
+               sum += *words;
+       }
+       return sum;
+}
+
+/**
+ * Execute El Torito image
+ *
+ * @v image            El Torito image
+ * @ret rc             Return status code
+ */
+static int eltorito_exec ( struct image *image ) {
+       struct ramdisk ramdisk;
+       struct int13_drive int13_drive;
+       unsigned int load_segment = image->priv.ul;
+       unsigned int load_offset = ( load_segment ? 0 : 0x7c00 );
+       int rc;
+
+       memset ( &ramdisk, 0, sizeof ( ramdisk ) );
+       init_ramdisk ( &ramdisk, image->data, image->len, ISO9660_BLKSIZE );
+       
+       memset ( &int13_drive, 0, sizeof ( int13_drive ) );
+       int13_drive.blockdev = &ramdisk.blockdev;
+       register_int13_drive ( &int13_drive );
+
+       if ( ( rc = call_bootsector ( load_segment, load_offset, 
+                                     int13_drive.drive ) ) != 0 ) {
+               DBGC ( image, "ElTorito %p boot failed: %s\n",
+                      image, strerror ( rc ) );
+               goto err;
+       }
+       
+       rc = -ECANCELED; /* -EIMPOSSIBLE */
+ err:
+       unregister_int13_drive ( &int13_drive );
+       return rc;
+}
+
+/**
+ * Read and verify El Torito Boot Record Volume Descriptor
+ *
+ * @v image            El Torito file
+ * @ret catalog_offset Offset of Boot Catalog
+ * @ret rc             Return status code
+ */
+static int eltorito_read_voldesc ( struct image *image,
+                                  unsigned long *catalog_offset ) {
+       static const struct eltorito_vol_desc vol_desc_signature = {
+               .record_indicator = 0,
+               .iso9660_id = "CD001",
+               .version = 1,
+               .system_indicator = "EL TORITO SPECIFICATION",
+       };
+       struct eltorito_vol_desc vol_desc;
+
+       /* Sanity check */
+       if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
+               DBGC ( image, "ElTorito %p too short\n", image );
+               return -ENOEXEC;
+       }
+
+       /* Read and verify Boot Record Volume Descriptor */
+       copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
+                        sizeof ( vol_desc ) );
+       if ( memcmp ( &vol_desc, &vol_desc_signature,
+                     offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
+               DBGC ( image, "ElTorito %p invalid Boot Record Volume "
+                      "Descriptor\n", image );
+               return -ENOEXEC;
+       }
+       *catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );
+
+       DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
+              image, *catalog_offset );
+
+       return 0;
+}
+
+/**
+ * Read and verify El Torito Boot Catalog
+ *
+ * @v image            El Torito file
+ * @v catalog_offset   Offset of Boot Catalog
+ * @ret boot_entry     El Torito boot entry
+ * @ret rc             Return status code
+ */
+static int eltorito_read_catalog ( struct image *image,
+                                  unsigned long catalog_offset,
+                                  struct eltorito_boot_entry *boot_entry ) {
+       struct eltorito_validation_entry validation_entry;
+
+       /* Sanity check */
+       if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
+               DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
+                      image, catalog_offset );
+               return -ENOEXEC;
+       }
+
+       /* Read and verify the Validation Entry of the Boot Catalog */
+       copy_from_user ( &validation_entry, image->data, catalog_offset,
+                        sizeof ( validation_entry ) );
+       if ( word_checksum ( &validation_entry,
+                            sizeof ( validation_entry ) ) != 0 ) {
+               DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
+                      image );
+               return -ENOEXEC;
+       }
+
+       /* Read and verify the Initial/Default entry */
+       copy_from_user ( boot_entry, image->data,
+                        ( catalog_offset + sizeof ( validation_entry ) ),
+                        sizeof ( *boot_entry ) );
+       if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
+               DBGC ( image, "ElTorito %p not bootable\n", image );
+               return -ENOEXEC;
+       }
+       if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
+               DBGC ( image, "ElTorito %p cannot support media type %d\n",
+                      image, boot_entry->media_type );
+               return -ENOTSUP;
+       }
+
+       DBGC ( image, "ElTorito %p media type %d segment %04x\n",
+              image, boot_entry->media_type, boot_entry->load_segment );
+
+       return 0;
+}
+
+/**
+ * Load El Torito virtual disk image into memory
+ *
+ * @v image            El Torito file
+ * @v boot_entry       El Torito boot entry
+ * @ret rc             Return status code
+ */
+static int eltorito_load_disk ( struct image *image,
+                               struct eltorito_boot_entry *boot_entry ) {
+       unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
+       unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
+       unsigned int load_segment;
+       userptr_t buffer;
+       int rc;
+
+       /* Sanity check */
+       if ( image->len < ( start + length ) ) {
+               DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
+                      image );
+               return -ENOEXEC;
+       }
+       DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
+              image, start, length );
+
+       /* Calculate load address */
+       load_segment = boot_entry->load_segment;
+       buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );
+
+       /* Verify and prepare segment */
+       if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
+               DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
+                      image, strerror ( rc ) );
+               return rc;
+       }
+
+       /* Copy image to segment */
+       memcpy_user ( buffer, 0, image->data, start, length );
+
+       return 0;
+}
+
+/**
+ * Load El Torito image into memory
+ *
+ * @v image            El Torito file
+ * @ret rc             Return status code
+ */
+int eltorito_load ( struct image *image ) {
+       struct eltorito_boot_entry boot_entry;
+       unsigned long bootcat_offset;
+       int rc;
+
+       /* Read Boot Record Volume Descriptor, if present */
+       if ( ( rc = eltorito_read_voldesc ( image, &bootcat_offset ) ) != 0 )
+               return rc;
+
+       /* This is an El Torito image, valid or otherwise */
+       if ( ! image->type )
+               image->type = &eltorito_image_type;
+
+       /* Read Boot Catalog */
+       if ( ( rc = eltorito_read_catalog ( image, bootcat_offset,
+                                           &boot_entry ) ) != 0 )
+               return rc;
+
+       /* Load Virtual Disk image */
+       if ( ( rc = eltorito_load_disk ( image, &boot_entry ) ) != 0 )
+               return rc;
+
+       /* Record load segment in image private data field */
+       image->priv.ul = boot_entry.load_segment;
+
+       return 0;
+}
+
+/** El Torito image type */
+struct image_type eltorito_image_type __image_type ( PROBE_NORMAL ) = {
+       .name = "El Torito",
+       .load = eltorito_load,
+       .exec = eltorito_exec,
+};
diff --git a/src/arch/i386/include/bootsector.h b/src/arch/i386/include/bootsector.h
new file mode 100644 (file)
index 0000000..e907105
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _BOOTSECTOR_H
+#define _BOOTSECTOR_H
+
+/** @file
+ *
+ * x86 bootsector image format
+ */
+
+extern int call_bootsector ( unsigned int segment, unsigned int offset,
+                            unsigned int drive );
+
+#endif /* _BOOTSECTOR_H */
index 16802a0..c9d7658 100644 (file)
@@ -37,6 +37,8 @@ struct block_device;
 #define INT13_EXTENDED_WRITE           0x43
 /** Get extended drive parameters */
 #define INT13_GET_EXTENDED_PARAMETERS  0x48
+/** Get CD-ROM status / terminate emulation */
+#define INT13_CDROM_STATUS_TERMINATE   0x4b
 
 /** @} */
 
index 8796f9a..b97d066 100644 (file)
@@ -26,6 +26,7 @@
 #include <realmode.h>
 #include <bios.h>
 #include <biosint.h>
+#include <bootsector.h>
 #include <int13.h>
 
 /** @file
@@ -44,23 +45,6 @@ static struct segoff __text16 ( int13_vector );
 /** Assembly wrapper */
 extern void int13_wrapper ( void );
 
-/** Vector for storing original INT 18 handler
- *
- * We do not chain to this vector, so there is no need to place it in
- * .text16.
- */
-static struct segoff int18_vector;
-
-/** Vector for storing original INT 19 handler
- *
- * We do not chain to this vector, so there is no need to place it in
- * .text16.
- */
-static struct segoff int19_vector;
-
-/** Restart point for INT 18 or 19 */
-extern void int13_exec_fail ( void );
-
 /** List of registered emulated drives */
 static LIST_HEAD ( drives );
 
@@ -114,6 +98,13 @@ static int int13_rw_sectors ( struct int13_drive *drive,
        unsigned int count;
        userptr_t buffer;
 
+       /* Validate blocksize */
+       if ( blockdev->blksize != INT13_BLKSIZE ) {
+               DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
+                     blockdev->blksize );
+               return -INT13_STATUS_INVALID;
+       }
+       
        /* Calculate parameters */
        cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
        assert ( cylinder < drive->cylinders );
@@ -129,13 +120,6 @@ static int int13_rw_sectors ( struct int13_drive *drive,
        DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder,
              head, sector, lba, ix86->segs.es, ix86->regs.bx, count );
 
-       /* Validate blocksize */
-       if ( blockdev->blksize != INT13_BLKSIZE ) {
-               DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
-                     blockdev->blksize );
-               return -INT13_STATUS_INVALID;
-       }
-       
        /* Read from / write to block device */
        if ( io ( blockdev, lba, count, buffer ) != 0 )
                return -INT13_STATUS_READ_ERROR;
@@ -333,6 +317,38 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
        return 0;
 }
 
+struct int13_cdrom_specification {
+       /** Size of packet in bytes */
+       uint8_t size;
+       /** Boot media type */
+       uint8_t media_type;
+       /** Drive number */
+       uint8_t drive;
+};
+
+/**
+ * INT 13, 4b - Get CD-ROM status / terminate emulation
+ *
+ * @v drive            Emulated drive
+ * @v ds:si            El Torito specification packet to fill in
+ * @ret status         Status code
+ */
+static int int13_cdrom_status_terminate ( struct int13_drive *drive,
+                                         struct i386_all_regs *ix86 ) {
+       struct int13_cdrom_specification specification;
+
+       DBG ( "Get CD-ROM emulation parameters to %04x:%04x\n",
+             ix86->segs.ds, ix86->regs.di );
+
+       memset ( &specification, 0, sizeof ( specification ) );
+       specification.size = sizeof ( specification );
+       specification.drive = drive->drive;
+
+       copy_to_real ( ix86->segs.ds, ix86->regs.si, &specification,
+                      sizeof ( specification ) );
+       return 0;
+}
+
 /**
  * INT 13 handler
  *
@@ -346,7 +362,7 @@ static void int13 ( struct i386_all_regs *ix86 ) {
                if ( drive->drive != ix86->regs.dl )
                        continue;
                
-               DBG ( "INT 13,%02x (%02x): ", command, drive->drive );
+               DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive );
 
                switch ( command ) {
                case INT13_RESET:
@@ -379,6 +395,9 @@ static void int13 ( struct i386_all_regs *ix86 ) {
                case INT13_GET_EXTENDED_PARAMETERS:
                        status = int13_get_extended_parameters ( drive, ix86 );
                        break;
+               case INT13_CDROM_STATUS_TERMINATE:
+                       status = int13_cdrom_status_terminate ( drive, ix86 );
+                       break;
                default:
                        DBG ( "*** Unrecognised INT 13 ***\n" );
                        status = -INT13_STATUS_INVALID;
@@ -398,6 +417,8 @@ static void int13 ( struct i386_all_regs *ix86 ) {
 
                /* Set OF to indicate to wrapper not to chain this call */
                ix86->flags |= OF;
+
+               break;
        }
 }
 
@@ -453,6 +474,10 @@ static void guess_int13_geometry ( struct int13_drive *drive ) {
        unsigned long blocks_per_cyl;
        unsigned int i;
 
+       /* Don't even try when the blksize is invalid for C/H/S access */
+       if ( drive->blockdev->blksize != INT13_BLKSIZE )
+               return;
+
        /* Scan through partition table and modify guesses for heads
         * and sectors_per_track if we find any used partitions.
         */
@@ -564,6 +589,7 @@ void unregister_int13_drive ( struct int13_drive *drive ) {
 int int13_boot ( unsigned int drive ) {
        int status, signature;
        int discard_c, discard_d;
+       int rc;
 
        DBG ( "Booting from INT 13 drive %02x\n", drive );
 
@@ -593,48 +619,11 @@ int int13_boot ( unsigned int drive ) {
                return -ENOEXEC;
        }
 
-       /* Hook INTs 18 and 19 to capture failure paths */
-       hook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
-                             &int18_vector );
-       hook_bios_interrupt ( 0x19, ( unsigned int ) int13_exec_fail,
-                             &int19_vector );
-
-       /* Boot the loaded sector
-        *
-        * We assume that the boot sector may completely destroy our
-        * real-mode stack, so we preserve everything we need in
-        * static storage.
-        */
-       __asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
-                                          "popw %%cs:int13_saved_retaddr\n\t"
-                                          /* Save stack pointer */
-                                          "movw %%ss, %%ax\n\t"
-                                          "movw %%ax, %%cs:int13_saved_ss\n\t"
-                                          "movw %%sp, %%cs:int13_saved_sp\n\t"
-                                          /* Jump to boot sector */
-                                          "ljmp $0, $0x7c00\n\t"
-                                          /* Preserved variables */
-                                          "\nint13_saved_ss: .word 0\n\t"
-                                          "\nint13_saved_sp: .word 0\n\t"
-                                          "\nint13_saved_retaddr: .word 0\n\t"
-                                          /* Boot failure return point */
-                                          "\nint13_exec_fail:\n\t"
-                                          /* Restore stack pointer */
-                                          "movw %%cs:int13_saved_ss, %%ax\n\t"
-                                          "movw %%ax, %%ss\n\t"
-                                          "movw %%cs:int13_saved_sp, %%sp\n\t"
-                                          /* Return via saved address */
-                                          "jmp *%%cs:int13_saved_retaddr\n\t")
-                              : "=d" ( discard_d ) : "d" ( drive )
-                              : "eax", "ebx", "ecx", "esi", "edi", "ebp" );
-
-       DBG ( "Booted disk returned via INT 18 or 19\n" );
-
-       /* Unhook INTs 18 and 19 */
-       unhook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
-                               &int18_vector );
-       unhook_bios_interrupt ( 0x19, ( unsigned int ) int13_exec_fail,
-                               &int19_vector );
-       
-       return -ECANCELED;
+       /* Jump to boot sector */
+       if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
+               DBG ( "INT 13 drive %02x boot returned\n", drive );
+               return rc;
+       }
+
+       return -ECANCELED; /* -EIMPOSSIBLE */
 }
index e27917a..a4c3168 100644 (file)
@@ -143,6 +143,9 @@ REQUIRE_OBJECT ( script );
 #ifdef IMAGE_BZIMAGE
 REQUIRE_OBJECT ( bzimage );
 #endif
+#ifdef IMAGE_ELTORITO
+REQUIRE_OBJECT ( eltorito );
+#endif
 
 /*
  * Drag in all requested commands
diff --git a/src/drivers/block/ramdisk.c b/src/drivers/block/ramdisk.c
new file mode 100644 (file)
index 0000000..b5324bf
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/blockdev.h>
+#include <gpxe/ramdisk.h>
+
+/**
+ * @file
+ *
+ * RAM disks
+ *
+ */
+
+static inline __attribute__ (( always_inline )) struct ramdisk *
+block_to_ramdisk ( struct block_device *blockdev ) {
+       return container_of ( blockdev, struct ramdisk, blockdev );
+}
+
+/**
+ * Read block
+ *
+ * @v blockdev         Block device
+ * @v block            Block number
+ * @v count            Block count
+ * @v buffer           Data buffer
+ * @ret rc             Return status code
+ */
+static int ramdisk_read ( struct block_device *blockdev, uint64_t block,
+                         unsigned long count, userptr_t buffer ) {
+       struct ramdisk *ramdisk = block_to_ramdisk ( blockdev );
+       unsigned long offset = ( block * blockdev->blksize );
+       unsigned long length = ( count * blockdev->blksize );
+
+       DBGC ( ramdisk, "RAMDISK %p reading [%lx,%lx)\n",
+              ramdisk, offset, length );
+
+       memcpy_user ( buffer, 0, ramdisk->data, offset, length );
+       return 0;
+}
+
+/**
+ * Write block
+ *
+ * @v blockdev         Block device
+ * @v block            Block number
+ * @v count            Block count
+ * @v buffer           Data buffer
+ * @ret rc             Return status code
+ */
+static int ramdisk_write ( struct block_device *blockdev, uint64_t block,
+                          unsigned long count, userptr_t buffer ) {
+       struct ramdisk *ramdisk = block_to_ramdisk ( blockdev );
+       unsigned long offset = ( block * blockdev->blksize );
+       unsigned long length = ( count * blockdev->blksize );
+
+       DBGC ( ramdisk, "RAMDISK %p writing [%lx,%lx)\n",
+              ramdisk, offset, length );
+
+       memcpy_user ( ramdisk->data, offset, buffer, 0, length );
+       return 0;
+}
+
+int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len,
+                  unsigned int blksize ) {
+       
+       if ( ! blksize )
+               blksize = 512;
+
+       ramdisk->data = data;
+       ramdisk->blockdev.read = ramdisk_read;
+       ramdisk->blockdev.write = ramdisk_write;
+       ramdisk->blockdev.blksize = blksize;
+       ramdisk->blockdev.blocks = ( len / blksize );
+
+       return 0;
+}