From: Anthony Liguori <[EMAIL PROTECTED]>

This patch adds support to QEMU for extboot.  It requires that an extboot.bin
binary be copied into the pc-bios directory or else make install will not
function properly.

To use extboot to boot from an arbitrary block device, simply append a
",boot=on" to the block device to boot from.  For instance, to boot from a SCSI
disk, one would use:

 -drive file=/path/to/image.img,if=scsi,boot=on

Signed-off-by: Anthony Liguori <[EMAIL PROTECTED]>
Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>

diff --git a/qemu/Makefile b/qemu/Makefile
index ce76352..a3c6870 100644
--- a/qemu/Makefile
+++ b/qemu/Makefile
@@ -179,7 +179,7 @@ endif
        mkdir -p "$(DESTDIR)$(datadir)"
        for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
                video.x openbios-sparc32 pxe-ne2k_pci.bin \
-               pxe-rtl8139.bin pxe-pcnet.bin; do \
+               pxe-rtl8139.bin pxe-pcnet.bin extboot.bin; do \
                $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x 
"$(DESTDIR)$(datadir)"; \
        done
 ifndef CONFIG_WIN32
@@ -281,6 +281,7 @@ tarbin:
         $(datadir)/pxe-ne2k_pci.bin \
        $(datadir)/pxe-rtl8139.bin \
         $(datadir)/pxe-pcnet.bin \
+       $(datadir)/extboot.bin \
        $(docdir)/qemu-doc.html \
        $(docdir)/qemu-tech.html \
        $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 0c5ca47..289cd18 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -471,7 +471,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
 VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
+VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o extboot.o
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
 ifeq ($(TARGET_BASE_ARCH), ia64)
diff --git a/qemu/hw/extboot.c b/qemu/hw/extboot.c
new file mode 100644
index 0000000..8759895
--- /dev/null
+++ b/qemu/hw/extboot.c
@@ -0,0 +1,128 @@
+/*
+ * Extended boot option ROM support.
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <[EMAIL PROTECTED]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "block.h"
+
+/* Extended Boot ROM suport */
+
+union extboot_cmd
+{
+    uint16_t type;
+    struct {
+       uint16_t type;
+       uint16_t cylinders;
+       uint16_t heads;
+       uint16_t sectors;
+    } query_geometry;
+    struct {
+       uint16_t type;
+       uint16_t nb_sectors;
+       uint16_t segment;
+       uint16_t offset;
+       uint64_t sector;
+    } xfer;
+};
+
+static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
+{
+    bdrv_get_geometry_hint(bs, c, h, s);
+
+    if (*c <= 1024) {
+       *c >>= 0;
+       *h <<= 0;
+    } else if (*c <= 2048) {
+       *c >>= 1;
+       *h <<= 1;
+    } else if (*c <= 4096) {
+       *c >>= 2;
+       *h <<= 2;
+    } else if (*c <= 8192) {
+       *c >>= 3;
+       *h <<= 3;
+    } else {
+       *c >>= 4;
+       *h <<= 4;
+    }
+
+    /* what is the correct algorithm for this?? */
+    if (*h == 256) {
+       *h = 255;
+       *c = *c + 1;
+    }
+}
+
+static uint32_t extboot_read(void *opaque, uint32_t addr)
+{
+    int *pcmd = opaque;
+    return *pcmd;
+}
+
+static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
+{
+    union extboot_cmd *cmd = (void *)(phys_ram_base + ((value & 0xFFFF) << 4));
+    BlockDriverState *bs = opaque;
+    int cylinders, heads, sectors, err;
+
+    get_translated_chs(bs, &cylinders, &heads, &sectors);
+
+    if (cmd->type == 0x01 || cmd->type == 0x02) {
+       target_ulong pa = cmd->xfer.segment * 16 + cmd->xfer.segment;
+
+       /* possible buffer overflow */
+       if ((pa + cmd->xfer.nb_sectors * 512) > phys_ram_size)
+           return;
+    }
+
+    switch (cmd->type) {
+    case 0x00:
+       cmd->query_geometry.cylinders = cylinders;
+       cmd->query_geometry.heads = heads;
+       cmd->query_geometry.sectors = sectors;
+       cpu_physical_memory_set_dirty((value & 0xFFFF) << 4);
+       break;
+    case 0x01:
+       err = bdrv_read(bs, cmd->xfer.sector, phys_ram_base +
+                       cmd->xfer.segment * 16 + cmd->xfer.offset,
+                       cmd->xfer.nb_sectors);
+       if (err)
+           printf("Read failed\n");
+       break;
+    case 0x02:
+       err = bdrv_write(bs, cmd->xfer.sector, phys_ram_base +
+                        cmd->xfer.segment * 16 + cmd->xfer.offset,
+                        cmd->xfer.nb_sectors);
+       if (err)
+           printf("Write failed\n");
+
+       cpu_physical_memory_set_dirty(cmd->xfer.segment * 16 + 
cmd->xfer.offset);
+       break;
+    }
+}
+
+void extboot_init(BlockDriverState *bs, int cmd)
+{
+    int *pcmd;
+
+    pcmd = qemu_mallocz(sizeof(int));
+    if (!pcmd) {
+       fprintf(stderr, "Error allocating memory\n");
+       exit(1);
+    }
+
+    *pcmd = cmd;
+    register_ioport_read(0x404, 1, 1, extboot_read, pcmd);
+    register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
+}
diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c
index 6f152ad..3972ab4 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -43,6 +43,7 @@ extern int kvm_allowed;
 #define BIOS_FILENAME "bios.bin"
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+#define EXTBOOT_FILENAME "extboot.bin"
 
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
@@ -715,6 +716,37 @@ extern kvm_context_t kvm_context;
 extern int kvm_allowed;
 #endif
 
+static int load_option_rom(const char *filename, int offset)
+{
+    ram_addr_t option_rom_offset;
+    int size, ret;
+
+    size = get_image_size(filename);
+    if (size < 0) {
+       fprintf(stderr, "Could not load option rom '%s'\n", filename);
+       exit(1);
+    }
+    if (size > (0x10000 - offset))
+       goto option_rom_error;
+    option_rom_offset = qemu_ram_alloc(size);
+    ret = load_image(filename, phys_ram_base + option_rom_offset);
+    if (ret != size) {
+    option_rom_error:
+       fprintf(stderr, "Too many option ROMS\n");
+       exit(1);
+    }
+    size = (size + 4095) & ~4095;
+    cpu_register_physical_memory(0xd0000 + offset,
+                                size, option_rom_offset | IO_MEM_ROM);
+#ifdef USE_KVM
+    if (kvm_allowed)
+           kvm_cpu_register_physical_memory(0xd0000 + offset,
+                                             size, option_rom_offset |
+                                             IO_MEM_ROM);
+#endif
+    return size;
+}
+
 /* PC hardware initialisation */
 static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
                      const char *boot_device, DisplayState *ds,
@@ -726,7 +758,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     int ret, linux_boot, i;
     ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
     ram_addr_t above_4g_mem_size = 0;
-    int bios_size, isa_bios_size, vga_bios_size;
+    int bios_size, isa_bios_size, vga_bios_size, opt_rom_offset;
     PCIBus *pci_bus;
     int piix3_devfn = -1;
     CPUState *env;
@@ -868,40 +900,13 @@ static void pc_init1(ram_addr_t ram_size, int 
vga_ram_size,
                                          (bios_offset + bios_size - 
isa_bios_size) | IO_MEM_ROM);
 #endif
 
+    opt_rom_offset = 0;
+    for (i = 0; i < nb_option_roms; i++)
+       opt_rom_offset += load_option_rom(option_rom[i], opt_rom_offset);
 
-    {
-        ram_addr_t option_rom_offset;
-        int size, offset;
-
-        offset = 0;
-        for (i = 0; i < nb_option_roms; i++) {
-            size = get_image_size(option_rom[i]);
-            if (size < 0) {
-                fprintf(stderr, "Could not load option rom '%s'\n",
-                        option_rom[i]);
-                exit(1);
-            }
-            if (size > (0x10000 - offset))
-                goto option_rom_error;
-            option_rom_offset = qemu_ram_alloc(size);
-            ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
-            if (ret != size) {
-            option_rom_error:
-                fprintf(stderr, "Too many option ROMS\n");
-                exit(1);
-            }
-            size = (size + 4095) & ~4095;
-            cpu_register_physical_memory(0xd0000 + offset,
-                                         size, option_rom_offset | IO_MEM_ROM);
-#ifdef USE_KVM
-            if (kvm_allowed)
-                kvm_cpu_register_physical_memory(0xd0000 + offset,
-                                             size, option_rom_offset |
-                                             IO_MEM_ROM);
-#endif
-
-            offset += size;
-        }
+    if (extboot_drive != -1) {
+       snprintf(buf, sizeof(buf), "%s/%s", bios_dir, EXTBOOT_FILENAME);
+       opt_rom_offset += load_option_rom(buf, opt_rom_offset);
     }
 
     /* map all the bios at the top of memory */
@@ -1116,6 +1121,18 @@ static void pc_init1(ram_addr_t ram_size, int 
vga_ram_size,
            unit_id++;
        }
     }
+
+    if (extboot_drive != -1) {
+       DriveInfo *info = &drives_table[extboot_drive];
+       int cyls, heads, secs;
+
+       if (info->type != IF_IDE) {
+           bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs);
+           bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs);
+       }
+
+       extboot_init(info->bdrv, 1);
+    }
 }
 
 static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size,
diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h
index 5d4c747..7d1832f 100644
--- a/qemu/hw/pc.h
+++ b/qemu/hw/pc.h
@@ -151,4 +151,8 @@ void virtio_net_poll(void);
 void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
                      BlockDriverState *bs);
 
+/* extboot.c */
+
+void extboot_init(BlockDriverState *bs, int cmd);
+
 #endif
diff --git a/qemu/sysemu.h b/qemu/sysemu.h
index b9f4b43..a72a4d6 100644
--- a/qemu/sysemu.h
+++ b/qemu/sysemu.h
@@ -148,6 +148,7 @@ typedef struct DriveInfo {
 
 int nb_drives;
 DriveInfo drives_table[MAX_DRIVES+1];
+int extboot_drive;
 
 extern int drive_get_index(BlockInterfaceType type, int bus, int unit);
 extern int drive_get_max_bus(BlockInterfaceType type);
diff --git a/qemu/vl.c b/qemu/vl.c
index c47b294..39b2e24 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -177,6 +177,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
    to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];
 int nb_drives;
+int extboot_drive = -1;
 /* point to the block driver where the snapshots are managed */
 BlockDriverState *bs_snapshots;
 int vga_ram_size;
@@ -4930,7 +4931,7 @@ static int drive_init(const char *str, int snapshot, 
QEMUMachine *machine)
     int bdrv_flags;
     char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
                        "secs", "trans", "media", "snapshot", "file",
-                       "cache", NULL };
+                       "cache", "boot", NULL };
 
     if (check_params(buf, sizeof(buf), params, str) < 0) {
          fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",
@@ -5101,6 +5102,19 @@ static int drive_init(const char *str, int snapshot, 
QEMUMachine *machine)
         }
     }
 
+    if (get_param_value(buf, sizeof(buf), "boot", str)) {
+       if (!strcmp(buf, "on")) {
+           if (extboot_drive != -1) {
+               fprintf(stderr, "qemu: two bootable drives specified\n");
+               return -1;
+           }
+           extboot_drive = nb_drives;
+       } else if (strcmp(buf, "off")) {
+           fprintf(stderr, "qemu: '%s' invalid boot option\n", str);
+           return -1;
+       }
+    }
+
     get_param_value(file, sizeof(file), "file", str);
 
     /* compute bus and unit according index */
@@ -7895,8 +7909,8 @@ static void help(int exitcode)
            "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
            "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 
master)\n"
           "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n"
-           "       [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]"
-           "       [,cache=on|off]\n"
+           "       [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n"
+           "       [,cache=on|off][,boot=on|off]\n"
           "                use 'file' as a drive image\n"
            "-mtdblock file  use 'file' as on-board Flash memory image\n"
            "-sd file        use 'file' as SecureDigital card image\n"

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-commits mailing list
kvm-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-commits

Reply via email to