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, §ors); + 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