booting from scsi + virtio works now.

usage: -device extboot,drive=<name>

where <name> is the name of your boot drive.  You can either use the
names qemu assignes by default (virtio0, scsi0-hd0, ...) or explitly
name your drives via '-drive id=<name>,...' and use that one.

Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
---
 Makefile.target |    2 +-
 hw/extboot.c    |  168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletions(-)
 create mode 100644 hw/extboot.c

diff --git a/Makefile.target b/Makefile.target
index 7068dc5..b165456 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -197,7 +197,7 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o 
pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
-obj-i386-y += ne2000-isa.o
+obj-i386-y += ne2000-isa.o extboot.o
 
 # shared objects
 obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
diff --git a/hw/extboot.c b/hw/extboot.c
new file mode 100644
index 0000000..3465558
--- /dev/null
+++ b/hw/extboot.c
@@ -0,0 +1,168 @@
+/*
+ * Extended boot option ROM support.
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aligu...@us.ibm.com>
+ *
+ * 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"
+#include "loader.h"
+
+typedef struct ExtbootState {
+    ISADevice dev;
+    DriveInfo *dinfo;
+    BlockDriverState *bs;
+} ExtbootState;
+
+union extboot_cmd
+{
+    uint16_t type;
+    struct {
+       uint16_t type;
+       uint16_t cylinders;
+       uint16_t heads;
+       uint16_t sectors;
+       uint64_t nb_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)
+{
+    return 1;
+}
+
+static void extboot_write(void *opaque, uint32_t addr, uint32_t value)
+{
+    ExtbootState *s = opaque;
+    union extboot_cmd cmd;
+    int cylinders, heads, sectors, err;
+    uint64_t nb_sectors;
+    target_phys_addr_t pa = 0;
+    int blen = 0;
+    void *buf = NULL;
+
+    cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd,
+                             sizeof(cmd));
+
+    if (cmd.type == 0x01 || cmd.type == 0x02) {
+       pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
+        blen = cmd.xfer.nb_sectors * 512;
+        buf = qemu_memalign(512, blen);
+    }
+
+    switch (cmd.type) {
+    case 0x00:
+        get_translated_chs(s->bs, &cylinders, &heads, &sectors);
+       bdrv_get_geometry(s->bs, &nb_sectors);
+       cmd.query_geometry.cylinders = cylinders;
+       cmd.query_geometry.heads = heads;
+       cmd.query_geometry.sectors = sectors;
+       cmd.query_geometry.nb_sectors = nb_sectors;
+       break;
+    case 0x01:
+       err = bdrv_read(s->bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
+       if (err)
+           printf("Read failed\n");
+
+        cpu_physical_memory_write(pa, buf, blen);
+
+       break;
+    case 0x02:
+        cpu_physical_memory_read(pa, buf, blen);
+
+       err = bdrv_write(s->bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
+       if (err)
+           printf("Write failed\n");
+
+       break;
+    }
+
+    cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd,
+                              sizeof(cmd));
+    if (buf)
+        qemu_free(buf);
+}
+
+static int extboot_init(ISADevice *dev)
+{
+    ExtbootState *s = DO_UPCAST(ExtbootState, dev, dev);
+    int cyls, heads, secs;
+
+    if (!s->dinfo) {
+        fprintf(stderr, "extboot: no drive specified\n");
+        return -1;
+    }
+    if (!s->dinfo->bdrv) {
+        fprintf(stderr, "extboot: drive %s is empty\n", s->dinfo->id);
+        return -1;
+    }
+
+    s->bs = s->dinfo->bdrv;
+    bdrv_guess_geometry(s->bs, &cyls, &heads, &secs);
+    bdrv_set_geometry_hint(s->bs, cyls, heads, secs);
+    register_ioport_read(0x404, 1, 1, extboot_read, s);
+    register_ioport_write(0x405, 1, 2, extboot_write, s);
+    rom_add_option("extboot.bin");
+    return 0;
+}
+
+static ISADeviceInfo extboot_info = {
+    .qdev.name  = "extboot",
+    .qdev.size  = sizeof(ExtbootState),
+    .init       = extboot_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_DRIVE("drive", ExtbootState, dinfo),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void extboot_register(void)
+{
+    isa_qdev_register(&extboot_info);
+};
+
+device_init(extboot_register);
-- 
1.6.2.5



Reply via email to