From patchwork Tue Aug 17 16:25:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haishan Bai X-Patchwork-Id: 61936 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A8FD7B6F0D for ; Wed, 18 Aug 2010 02:26:13 +1000 (EST) Received: from localhost ([127.0.0.1]:47853 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OlOzJ-0003Wu-Fx for incoming@patchwork.ozlabs.org; Tue, 17 Aug 2010 12:26:09 -0400 Received: from [140.186.70.92] (port=33092 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OlOyj-0003WD-Q0 for qemu-devel@nongnu.org; Tue, 17 Aug 2010 12:25:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OlOyi-00045z-9a for qemu-devel@nongnu.org; Tue, 17 Aug 2010 12:25:33 -0400 Received: from mail-fx0-f45.google.com ([209.85.161.45]:62778) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OlOyi-00045q-0L for qemu-devel@nongnu.org; Tue, 17 Aug 2010 12:25:32 -0400 Received: by fxm7 with SMTP id 7so3818073fxm.4 for ; Tue, 17 Aug 2010 09:25:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:subject:content-type :content-transfer-encoding; bh=niebMPzcVgBw7yv4w3oeLpaHPWl86ZEO17yPgrLdV9w=; b=vp943duMyCeuJQpmZ6cPqQzJVpujfnXbSIHWzefA5f9KvAmzhKsy++Wtg/iLtrc/Ex fj30xcspGs2c3j4Beg2qye1tZHdJGRbf7aM17FkC711DB5cbSa0c1pLpv0V9ytdwGhzn SK8g9e7LoHvbdUNCvRpgn0wdt0PBWL7R5V2P8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject :content-type:content-transfer-encoding; b=UNrrk6bKvhFUD5y+A9Vy5gu/wrMhr9XvF5ipMAJuRZm+vrFFV+OxppHiZb639/gU/1 IQCj4bzV8BTuzEM7l76oIB5SpMOhpohVVy0qs/rS156Gay90gM/xYwzdfZFyrnd23LU1 ycGClM/iAL5jQ6Te8fd+KWom2yqkNC8m4b3+Y= Received: by 10.223.126.68 with SMTP id b4mr6715223fas.96.1282062330512; Tue, 17 Aug 2010 09:25:30 -0700 (PDT) Received: from [10.0.0.2] ([222.128.128.233]) by mx.google.com with ESMTPS id b9sm3066898faq.31.2010.08.17.09.25.26 (version=SSLv3 cipher=RC4-MD5); Tue, 17 Aug 2010 09:25:28 -0700 (PDT) Message-ID: <4C6AB7F6.3040909@gmail.com> Date: Wed, 18 Aug 2010 00:25:26 +0800 From: Haishan Bai User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100713 Thunderbird/3.0.6 MIME-Version: 1.0 To: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH - V2] Port codes from qemu-kvm to support booting from SCSI disk image X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org There is code indentation errors in my previous post, I am sorry for that, please review this post. The qemu-kvm could boot from SCSI disk image by utilizing seabios, this patch ported codes from qemu-kvm to let upstream qemu to support booting from SCSI disk image. Add 'boot=on' option to qemu command line like following, qemu-system-x86_64 -drive file=scsi-disk.img,if=scsi,boot=on Signed-off-by: Shan Hai --- Makefile.target | 1 + blockdev.c | 13 ++++++ blockdev.h | 2 + hw/extboot.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 17 ++++++++ hw/pc.h | 4 ++ qemu-config.c | 4 ++ 7 files changed, 164 insertions(+), 0 deletions(-) create mode 100644 hw/extboot.c diff --git a/Makefile.target b/Makefile.target index c8281e9..abba79c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -199,6 +199,7 @@ obj-i386-y += mc146818rtc.o i8259.o pc.o obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o +obj-i386-y += extboot.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o diff --git a/blockdev.c b/blockdev.c index 01e402b..78c286c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -15,6 +15,8 @@ #include "qemu-config.h" #include "sysemu.h" +DriveInfo *extboot_drive = NULL; + static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); /* @@ -150,6 +152,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) int on_read_error, on_write_error; const char *devaddr; DriveInfo *dinfo; + int is_extboot = 0; int snapshot = 0; int ret; @@ -311,6 +314,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) } } + is_extboot = qemu_opt_get_bool(opts, "boot", 0); + if (is_extboot && extboot_drive) { + fprintf(stderr, "qemu: two bootable drives specified\n"); + return NULL; + } + on_write_error = BLOCK_ERR_STOP_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { @@ -421,6 +430,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); QTAILQ_INSERT_TAIL(&drives, dinfo, next); + if (is_extboot) { + extboot_drive = dinfo; + } + bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error); switch(type) { diff --git a/blockdev.h b/blockdev.h index 37f3a01..e707b87 100644 --- a/blockdev.h +++ b/blockdev.h @@ -59,4 +59,6 @@ int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_change_block(Monitor *mon, const char *device, const char *filename, const char *fmt); +extern DriveInfo *extboot_drive; + #endif diff --git a/hw/extboot.c b/hw/extboot.c new file mode 100644 index 0000000..8ada21b --- /dev/null +++ b/hw/extboot.c @@ -0,0 +1,123 @@ +/* + * Extended boot option ROM support. + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * 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; + 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 void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value) +{ + union extboot_cmd cmd; + BlockDriverState *bs = opaque; + 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(bs, &cylinders, &heads, §ors); + bdrv_get_geometry(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(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(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); +} + +void extboot_init(BlockDriverState *bs) +{ + register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs); +} diff --git a/hw/pc.c b/hw/pc.c index 58dea57..88f43aa 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -54,6 +54,7 @@ #endif #define BIOS_FILENAME "bios.bin" +#define EXTBOOT_FILENAME "extboot.bin" #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) @@ -953,6 +954,10 @@ void pc_memory_init(ram_addr_t ram_size, isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); + if (extboot_drive) { + option_rom[nb_option_roms++] = qemu_strdup(EXTBOOT_FILENAME); + } + option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE); cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset); @@ -1074,4 +1079,16 @@ void pc_pci_device_init(PCIBus *pci_bus) for (bus = 0; bus <= max_bus; bus++) { pci_create_simple(pci_bus, -1, "lsi53c895a"); } + + if (extboot_drive) { + DriveInfo *info = extboot_drive; + int cyls, heads, secs; + + if (info->type != IF_IDE && info->type != IF_VIRTIO) { + bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs); + bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs); + } + + extboot_init(info->bdrv); + } } diff --git a/hw/pc.h b/hw/pc.h index 63b0249..61882db 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -167,6 +167,10 @@ void isa_cirrus_vga_init(void); void isa_ne2000_init(int base, int irq, NICInfo *nd); +/* extboot.c */ + +void extboot_init(BlockDriverState *bs); + /* e820 types */ #define E820_RAM 1 #define E820_RESERVED 2 diff --git a/qemu-config.c b/qemu-config.c index 95abe61..08ee553 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -79,6 +79,10 @@ QemuOptsList qemu_drive_opts = { },{ .name = "readonly", .type = QEMU_OPT_BOOL, + },{ + .name = "boot", + .type = QEMU_OPT_BOOL, + .help = "make this a boot drive", }, { /* end if list */ } },