From patchwork Tue Jan 5 20:46:45 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 42229 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 DF401B6EF0 for ; Wed, 6 Jan 2010 10:52:55 +1100 (EST) Received: from localhost ([127.0.0.1]:47409 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NSJCH-0006m0-NS for incoming@patchwork.ozlabs.org; Tue, 05 Jan 2010 18:52:21 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NSGIk-0002sq-CN for qemu-devel@nongnu.org; Tue, 05 Jan 2010 15:46:50 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NSGIi-0002sd-88 for qemu-devel@nongnu.org; Tue, 05 Jan 2010 15:46:49 -0500 Received: from [199.232.76.173] (port=39596 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NSGIi-0002sa-2z for qemu-devel@nongnu.org; Tue, 05 Jan 2010 15:46:48 -0500 Received: from fg-out-1718.google.com ([72.14.220.157]:22944) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NSGIg-0007Zq-Tw for qemu-devel@nongnu.org; Tue, 05 Jan 2010 15:46:47 -0500 Received: by fg-out-1718.google.com with SMTP id 19so1938213fgg.10 for ; Tue, 05 Jan 2010 12:46:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:cc:content-type; bh=ih6kaqVvdrrh1kNDEo8w3yXFm9A800Uox+WuRWJ0KeM=; b=UfHXiFzXWkwzEkxZI/CBggCiagU+uMPf3cQC6k/qAbO1suX1J6g70VnpX7Rp4nj9Oy Fov4PAbIdD0R2BHf52dSnc9ESUdCsue95s2aW1qLPVeMcLC9EoOnS3zXa6vza1Eg1uIN injvu/AKCt2vFLhytkpxnXy9gFSb/ozjvuZBs= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:cc:content-type; b=HSqALkM28SY+wpyFAG65r/tE/QAONdge2edVJ2Z9JqyMupTVgnUMygeMnasCecO8Pe LZi0ZE02+dun+pOZFbazZprJHXNYdf3DV1h/Znd3m1W4jmuMfWUiGyrnCUBD+Ob13Zrt aFfpwBsJ+nL66upVEBZk3X4K8uYVFih7/23iY= MIME-Version: 1.0 Received: by 10.86.221.19 with SMTP id t19mr12277329fgg.37.1262724405103; Tue, 05 Jan 2010 12:46:45 -0800 (PST) Date: Tue, 5 Jan 2010 20:46:45 +0000 Message-ID: From: Stefan Hajnoczi To: gpxe@etherboot.org X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH] [virtio] Add virtio block device sanboot support 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 This patch adds virtio block device support alongside the existing iSCSI, ATA-over-Ethernet, and ramdisk block devices. The virtio block device provides storage in virtualized environments. Using this patch, a gPXE option ROM can boot a QEMU/KVM virtual machine directly from a virtio block device. Here is an example QEMU invocation: qemu -drive if=virtio,file=debian.qcow2 -option-rom gpxe/src/bin/1af41001.rom SANBOOT_PROTO_VIRTIO_BLK must be defined in config/general.h to enable this feature. The gPXE option ROM must be built for PCI ID 1af4:1001. The sanboot gPXE command is used with the virtio_blk: root path scheme. The virtio block device instance is identified by its PCI bus, device, and function (there could be multiple virtio block devices). gPXE> sanboot virtio_blk:PCI00:04.0 Perhaps the first available device should be chosen if virtio_blk: is given without PCI bus, device, and function. I am open to suggestions on how virtio block device option ROMs should work. I have successfully booted Debian testing i386 and FreeDOS 0.84-pre2 under QEMU 0.11.0. Note that QEMU/KVM can boot from a virtio block device using a separate non-virtio interface (-drive if=virtio,boot=on,[...]). This gPXE patch provides a native virtio block implementation. While developing this feature, I noticed that the AoE sanboot code leaves a pointer to a stack value around after it returns. A commit to fix this is included. Stefan Hajnoczi (2): [sanboot] Prevent leaking a stack reference for "keep-san" AoE [virtio] Add virtio block device sanboot support src/arch/i386/interface/pcbios/aoeboot.c | 54 +++-- src/arch/i386/interface/pcbios/virtio_blkboot.c | 70 ++++++ src/config/config.c | 3 + src/config/general.h | 1 + src/drivers/block/virtio-blk.c | 271 +++++++++++++++++++++++ src/drivers/block/virtio-blk.h | 30 +++ src/include/gpxe/errfile.h | 2 + src/include/gpxe/virtblk.h | 37 +++ 8 files changed, 447 insertions(+), 21 deletions(-) create mode 100644 src/arch/i386/interface/pcbios/virtio_blkboot.c create mode 100644 src/drivers/block/virtio-blk.c create mode 100644 src/drivers/block/virtio-blk.h create mode 100644 src/include/gpxe/virtblk.h From 0926649bece8e06dfdb19e4f819795da6ee364dd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Jan 2010 08:05:32 +0000 Subject: [PATCH 1/2] [sanboot] Prevent leaking a stack reference for "keep-san" AoE When the "keep-san" option is used, the function is exited without unregistering the stack allocated int13h drive. To prevent a dangling pointer to the stack, these structs should be heap allocated. --- src/arch/i386/interface/pcbios/aoeboot.c | 54 ++++++++++++++++++----------- 1 files changed, 33 insertions(+), 21 deletions(-) From 0926649bece8e06dfdb19e4f819795da6ee364dd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Jan 2010 08:05:32 +0000 Subject: [PATCH 1/2] [sanboot] Prevent leaking a stack reference for "keep-san" AoE When the "keep-san" option is used, the function is exited without unregistering the stack allocated int13h drive. To prevent a dangling pointer to the stack, these structs should be heap allocated. --- src/arch/i386/interface/pcbios/aoeboot.c | 54 ++++++++++++++++++----------- 1 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/arch/i386/interface/pcbios/aoeboot.c b/src/arch/i386/interface/pcbios/aoeboot.c index 8446c15..2670b15 100644 --- a/src/arch/i386/interface/pcbios/aoeboot.c +++ b/src/arch/i386/interface/pcbios/aoeboot.c @@ -1,11 +1,11 @@ #include #include +#include #include -#include +#include #include #include #include -#include #include #include #include @@ -13,50 +13,62 @@ FILE_LICENCE ( GPL2_OR_LATER ); static int aoeboot ( const char *root_path ) { - struct ata_device ata; - struct int13_drive drive; + struct ata_device *ata; + struct int13_drive *drive; int rc; - memset ( &ata, 0, sizeof ( ata ) ); - memset ( &drive, 0, sizeof ( drive ) ); + ata = zalloc ( sizeof ( *ata ) ); + if ( ! ata ) { + rc = -ENOMEM; + goto err_alloc_ata; + } + drive = zalloc ( sizeof ( *drive ) ); + if ( ! drive ) { + rc = -ENOMEM; + goto err_alloc_drive; + } /* FIXME: ugly, ugly hack */ struct net_device *netdev = last_opened_netdev(); - if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) { + if ( ( rc = aoe_attach ( ata, netdev, root_path ) ) != 0 ) { printf ( "Could not attach AoE device: %s\n", strerror ( rc ) ); - goto error_attach; + goto err_attach; } - if ( ( rc = init_atadev ( &ata ) ) != 0 ) { + if ( ( rc = init_atadev ( ata ) ) != 0 ) { printf ( "Could not initialise AoE device: %s\n", strerror ( rc ) ); - goto error_init; + goto err_init; } /* FIXME: ugly, ugly hack */ struct aoe_session *aoe = - container_of ( ata.backend, struct aoe_session, refcnt ); + container_of ( ata->backend, struct aoe_session, refcnt ); abft_fill_data ( aoe ); - drive.blockdev = &ata.blockdev; + drive->blockdev = &ata->blockdev; - register_int13_drive ( &drive ); - printf ( "Registered as BIOS drive %#02x\n", drive.drive ); - printf ( "Booting from BIOS drive %#02x\n", drive.drive ); - rc = int13_boot ( drive.drive ); + register_int13_drive ( drive ); + printf ( "Registered as BIOS drive %#02x\n", drive->drive ); + printf ( "Booting from BIOS drive %#02x\n", drive->drive ); + rc = int13_boot ( drive->drive ); printf ( "Boot failed\n" ); /* Leave drive registered, if instructed to do so */ if ( keep_san() ) return rc; - printf ( "Unregistering BIOS drive %#02x\n", drive.drive ); - unregister_int13_drive ( &drive ); + printf ( "Unregistering BIOS drive %#02x\n", drive->drive ); + unregister_int13_drive ( drive ); - error_init: - aoe_detach ( &ata ); - error_attach: + err_init: + aoe_detach ( ata ); + err_attach: + free ( drive ); + err_alloc_drive: + free ( ata ); + err_alloc_ata: return rc; } -- 1.6.5 From 3dbc385d29cbdff520ed0694934c01a6808ff1dc Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Jan 2010 17:39:18 +0000 Subject: [PATCH 2/2] [virtio] Add virtio block device sanboot support This patch adds virtio block device support alongside the existing iSCSI, ATA-over-Ethernet, and ramdisk block devices. A gPXE option ROM can boot a QEMU/KVM virtual machine directly from a virtio block device: # Ensure SANBOOT_PROTO_VIRTIO_BLK is defined in config/defaults.h make bin/1af41001.rom The sanboot gPXE command is used with the virtio_blk: root path scheme. The virtio block device instance is identified by its PCI bus, device, and function (there could be multiple virtio block devices). sanboot virtio_blk:PCI00:04.0 Successfully boots Debian testing i386 and FreeDOS 0.84-pre2 under QEMU. --- src/arch/i386/interface/pcbios/virtio_blkboot.c | 70 ++++++ src/config/config.c | 3 + src/config/general.h | 1 + src/drivers/block/virtio-blk.c | 271 +++++++++++++++++++++++ src/drivers/block/virtio-blk.h | 30 +++ src/include/gpxe/errfile.h | 2 + src/include/gpxe/virtblk.h | 37 +++ 7 files changed, 414 insertions(+), 0 deletions(-) create mode 100644 src/arch/i386/interface/pcbios/virtio_blkboot.c create mode 100644 src/drivers/block/virtio-blk.c create mode 100644 src/drivers/block/virtio-blk.h create mode 100644 src/include/gpxe/virtblk.h diff --git a/src/arch/i386/interface/pcbios/virtio_blkboot.c b/src/arch/i386/interface/pcbios/virtio_blkboot.c new file mode 100644 index 0000000..3c2dd47 --- /dev/null +++ b/src/arch/i386/interface/pcbios/virtio_blkboot.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Stefan Hajnoczi . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** + * @file + * + * Virtio block device boot + * + */ + +static int virtio_blkboot ( const char *root_path ) { + struct int13_drive *drive; + struct virtblk *virtblk; + int rc; + + virtblk = find_virtblk ( root_path + sizeof ( "virtio_blk:" ) - 1 ); + if ( ! virtblk ) + return -ENOENT; + + drive = zalloc ( sizeof ( *drive ) ); + if ( ! drive ) + return -ENOMEM; + + drive->blockdev = &virtblk->blockdev; + + register_int13_drive ( drive ); + printf ( "Registered as BIOS drive %#02x\n", drive->drive ); + printf ( "Booting from BIOS drive %#02x\n", drive->drive ); + rc = int13_boot ( drive->drive ); + printf ( "Boot failed\n" ); + + /* Leave drive registered, if instructed to do so */ + if ( keep_san() ) + return rc; + + printf ( "Unregistering BIOS drive %#02x\n", drive->drive ); + unregister_int13_drive ( drive ); + free ( drive ); + return rc; +} + +struct sanboot_protocol virtblk_sanboot_protocol __sanboot_protocol = { + .prefix = "virtio_blk:", + .boot = virtio_blkboot, +}; diff --git a/src/config/config.c b/src/config/config.c index 3c43dfb..bb0ff67 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -130,6 +130,9 @@ REQUIRE_OBJECT ( aoeboot ); #ifdef SANBOOT_PROTO_IB_SRP REQUIRE_OBJECT ( ib_srpboot ); #endif +#ifdef SANBOOT_PROTO_VIRTIO_BLK +REQUIRE_OBJECT ( virtio_blkboot ); +#endif /* * Drag in all requested resolvers diff --git a/src/config/general.h b/src/config/general.h index ee07dfc..a1dec39 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -63,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */ //#undef SANBOOT_PROTO_AOE /* AoE protocol */ //#undef SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */ +//#undef SANBOOT_PROTO_VIRTIO_BLK /* Virtio block device */ /* * Name resolution modules diff --git a/src/drivers/block/virtio-blk.c b/src/drivers/block/virtio-blk.c new file mode 100644 index 0000000..fab5930 --- /dev/null +++ b/src/drivers/block/virtio-blk.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2010 Stefan Hajnoczi . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include "virtio-blk.h" + +/** + * @file + * + * Virtio block devices + * + */ + +/** List of virtio block devices */ +static LIST_HEAD ( virtblk_devices ); + +/** + * Register virtio block device + * + * @v virtblk Virtio block device + * + * Adds the virtio block device to the list of virtio block devices. + */ +static void register_virtblk ( struct virtblk *virtblk ) { + list_add_tail ( &virtblk->virtblk_devices, &virtblk_devices ); +} + +/** + * Unregister virtio block device + * + * @v virtblk Virtio block device + * + * Removes the virtio block device from the list of virtio block devices. + */ +static void unregister_virtblk ( struct virtblk *virtblk ) { + list_del ( &virtblk->virtblk_devices ); +} + +/** + * Find virtio block device by name + * + * @v device_name Device name + * @ret virtblk Virtio block device or NULL + * + * Searches the list of virtio block devices by name. + */ +struct virtblk *find_virtblk ( const char *device_name ) { + struct virtblk *virtblk; + DBG ( "find_virtblk \"%s\"\n", device_name ); + list_for_each_entry ( virtblk, &virtblk_devices, virtblk_devices ) { + if ( ! strcmp ( device_name, virtblk->pdev->dev.name ) ) + return virtblk; + } + return NULL; +} + +/** + * Issue an I/O request and wait for completion + * + * @v virtblk Virtio block device + * @v type VIRTIO_BLK_T_IN or VIRTIO_BLK_T_OUT + * @v block Block number + * @v count Block count + * @v buffer Data buffer + * @ret rc Return status code + */ +static int virtblk_command ( struct virtblk *virtblk, u32 type, + uint64_t block, unsigned long count, + userptr_t buffer ) { + /* + * Virtio block requests have the following format: + * + * +--------------------------------+ + * | struct virtio_blk_outhdr [IN] | + * +--------------------------------+ + * | In/out buffer [IN/OUT] | + * +--------------------------------+ + * | Status byte [OUT] | + * +--------------------------------+ + * + * The device fills in the status byte to indicate the outcome the + * operation. + */ + struct vring_virtqueue *vq = &virtblk->virtqueue; + struct virtio_blk_outhdr hdr = { + .type = type, + .ioprio = 0, + .sector = block, + }; + uint8_t status = VIRTIO_BLK_S_UNSUPP; + struct vring_list list[] = { + { + .addr = ( char * ) &hdr, + .length = sizeof ( hdr ), + }, + { + .addr = ( char * ) user_to_virt ( buffer, 0 ), + .length = virtblk->blockdev.blksize * count, + }, + { + .addr = ( char * ) &status, + .length = sizeof ( status ), + }, + }; + unsigned int in, out; + + DBG ( "VIRTBLK req 0x%02x LBA 0x%llx count 0x%lx\n", + type, block, count ); + + /* Number of elements readable and writable */ + if ( type == VIRTIO_BLK_T_IN ) { + out = 1; + in = 2; + } else { + out = 2; + in = 1; + } + + /* Add to virtqueue and kick host */ + vring_add_buf ( vq, list, out, in, 0, 0 ); + vring_kick ( virtblk->pdev->ioaddr, vq, 1 ); + + /* Wait for reply */ + while ( ! vring_more_used ( vq ) ) { + mb(); + step(); + } + + /* Reclaim virtqueue element */ + vring_get_buf ( vq, NULL ); + return status == VIRTIO_BLK_S_OK ? 0 : -EIO; +} + +/** + * Read block + * + * @v blockdev Block device + * @v block Block number + * @v count Block count + * @v buffer Data buffer + * @ret rc Return status code + */ +static int virtblk_read ( struct block_device *blockdev, uint64_t block, + unsigned long count, userptr_t buffer ) { + struct virtblk *virtblk = + container_of ( blockdev, struct virtblk, blockdev ); + return virtblk_command ( virtblk, VIRTIO_BLK_T_IN, block, + count, buffer ); +} + +/** + * Write block + * + * @v blockdev Block device + * @v block Block number + * @v count Block count + * @v buffer Data buffer + * @ret rc Return status code + */ +static int virtblk_write ( struct block_device *blockdev __unused, uint64_t block __unused, + unsigned long count __unused, userptr_t buffer __unused ) { + struct virtblk *virtblk = + container_of ( blockdev, struct virtblk, blockdev ); + return virtblk_command ( virtblk, VIRTIO_BLK_T_OUT, block, + count, buffer ); +} + +static struct block_device_operations virtblk_operations = { + .read = virtblk_read, + .write = virtblk_write, +}; + +/** + * Probe PCI device + * + * @v pci PCI device + * @v id PCI ID + * @ret rc Return status code + */ +static int virtblk_probe ( struct pci_device *pci, + const struct pci_device_id *id __unused ) { + unsigned long ioaddr = pci->ioaddr; + + /* Initialize driver state */ + struct virtblk *virtblk = zalloc ( sizeof *virtblk ); + if ( ! virtblk ) + return -ENOMEM; + INIT_LIST_HEAD ( &virtblk->virtblk_devices ); + virtblk->blockdev.op = &virtblk_operations; + virtblk->pdev = pci; + pci->priv = virtblk; + + /* Prepare the device */ + adjust_pci_device ( pci ); + vp_reset ( ioaddr ); + + /* Indicate that the driver is starting */ + vp_set_status ( ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER ); + + /* Grab the I/O requests virtqueue */ + if ( vp_find_vq ( ioaddr, 0, &virtblk->virtqueue ) < 0 ) { + free ( virtblk ); + return -ENOENT; + } + + /* Feature negotiation */ + u32 features = vp_get_features ( ioaddr ); + vp_set_features ( ioaddr, 0 ); /* no features required */ + + /* Find out the drive capacity */ + virtblk->blockdev.blksize = 512; /* the default */ + vp_get ( ioaddr, 0, &virtblk->blockdev.blocks, + sizeof virtblk->blockdev.blocks ); + + /* Indicate that the driver is ready */ + vp_set_status ( ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER | + VIRTIO_CONFIG_S_DRIVER_OK ); + + DBGC ( virtblk, "VIRTBLK %p virtio_blk:%s ioaddr=0x%lx irq=%d features=0x%x capacity=%lld\n", + virtblk, pci->dev.name, ioaddr, pci->irq, + features, virtblk->blockdev.blocks ); + + register_virtblk ( virtblk ); + return 0; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void virtblk_remove ( struct pci_device *pci ) { + struct virtblk *virtblk = pci->priv; + + unregister_virtblk ( virtblk ); + vp_reset ( pci->ioaddr ); + free ( virtblk ); +} + +static struct pci_device_id virtblk_ids[] = { + PCI_ROM(0x1af4, 0x1001, "virtio-blk", "Virtio Block Device", 0), +}; + +struct pci_driver virtblk_driver __pci_driver = { + .ids = virtblk_ids, + .id_count = ( sizeof ( virtblk_ids ) / sizeof ( virtblk_ids[0] ) ), + .probe = virtblk_probe, + .remove = virtblk_remove, +}; diff --git a/src/drivers/block/virtio-blk.h b/src/drivers/block/virtio-blk.h new file mode 100644 index 0000000..3a34868 --- /dev/null +++ b/src/drivers/block/virtio-blk.h @@ -0,0 +1,30 @@ +#ifndef _VIRTIO_BLK_H +#define _VIRTIO_BLK_H +/* This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. */ + +FILE_LICENCE ( BSD2 ); + +/* + * Command types + */ + +/* These two define direction. */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 + +/* This is the first element of the read scatter-gather list. */ +struct virtio_blk_outhdr { + /* VIRTIO_BLK_T* */ + u32 type; + /* io priority. */ + u32 ioprio; + /* Sector (ie. 512 byte offset) */ + u64 sector; +}; + +/* And this is the final byte of the write scatter-gather list. */ +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 +#endif /* _VIRTIO_BLK_H */ diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h index 5231c14..092d7eb 100644 --- a/src/include/gpxe/errfile.h +++ b/src/include/gpxe/errfile.h @@ -122,6 +122,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_linda ( ERRFILE_DRIVER | 0x00730000 ) #define ERRFILE_ata ( ERRFILE_DRIVER | 0x00740000 ) #define ERRFILE_srp ( ERRFILE_DRIVER | 0x00750000 ) +#define ERRFILE_virtio_blk ( ERRFILE_DRIVER | 0x00760000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) @@ -191,6 +192,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_x509 ( ERRFILE_OTHER | 0x00160000 ) #define ERRFILE_login_ui ( ERRFILE_OTHER | 0x00170000 ) #define ERRFILE_ib_srpboot ( ERRFILE_OTHER | 0x00180000 ) +#define ERRFILE_virtio_blkboot ( ERRFILE_OTHER | 0x00190000 ) /** @} */ diff --git a/src/include/gpxe/virtblk.h b/src/include/gpxe/virtblk.h new file mode 100644 index 0000000..781d433 --- /dev/null +++ b/src/include/gpxe/virtblk.h @@ -0,0 +1,37 @@ +#ifndef _GPXE_VIRTBLK_H +#define _GPXE_VIRTBLK_H + +/** @file + * + * Virtio block device + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include + +/** + * Virtio block device + */ +struct virtblk { + /** List of virtio-blk devices */ + struct list_head virtblk_devices; + + /** Underlying PCI device */ + struct pci_device *pdev; + + /** Outgoing requests virtqueue */ + struct vring_virtqueue virtqueue; + + /** Block device */ + struct block_device blockdev; +}; + +extern struct virtblk *find_virtblk ( const char *device_name ); + +#endif /* _GPXE_VIRTBLK_H */ -- 1.6.5