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