This patch adds native support for booting from virtio disks to Seabios.
Signed-off-by: Gleb Natapov g...@redhat.com
---
Changelog:
v1-v2:
- free memory in case of vq initialization error.
- change license of virtio ring/pci to LGPLv3 with permission
of Laurent Vivier (aka the author).
v2-v3:
- free memory in case one of allocations failed
diff --git a/Makefile b/Makefile
index 327a1bf..d0b8881 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,8 @@ OUT=out/
SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \
kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
-usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c
+usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
+virtio-ring.c virtio-pci.c virtio-blk.c
SRC16=$(SRCBOTH) system.c disk.c apm.c font.c
SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
diff --git a/src/block.c b/src/block.c
index ddf441f..b6b1902 100644
--- a/src/block.c
+++ b/src/block.c
@@ -11,6 +11,7 @@
#include util.h // dprintf
#include ata.h // process_ata_op
#include usb-msc.h // process_usb_op
+#include virtio-blk.h // process_virtio_op
struct drives_s Drives VAR16VISIBLE;
@@ -289,6 +290,8 @@ process_op(struct disk_op_s *op)
return process_cdemu_op(op);
case DTYPE_USB:
return process_usb_op(op);
+case DTYPE_VIRTIO:
+ return process_virtio_op(op);
default:
op-count = 0;
return DISK_RET_EPARAM;
diff --git a/src/config.h b/src/config.h
index b101174..ad569c6 100644
--- a/src/config.h
+++ b/src/config.h
@@ -136,6 +136,9 @@
#define CONFIG_SUBMODEL_ID 0x00
#define CONFIG_BIOS_REVISION 0x01
+// Support boot from virtio storage
+#define CONFIG_VIRTIO_BLK 1
+
// Various memory addresses used by the code.
#define BUILD_STACK_ADDR 0x7000
#define BUILD_S3RESUME_STACK_ADDR 0x1000
diff --git a/src/disk.h b/src/disk.h
index 0cd1b74..9e5b083 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -197,6 +197,7 @@ struct drive_s {
#define DTYPE_RAMDISK 0x04
#define DTYPE_CDEMU0x05
#define DTYPE_USB 0x06
+#define DTYPE_VIRTIO 0x07
#define MAXDESCSIZE 80
diff --git a/src/pci_ids.h b/src/pci_ids.h
index 1800f1d..e1cded2 100644
--- a/src/pci_ids.h
+++ b/src/pci_ids.h
@@ -2605,3 +2605,6 @@
#define PCI_DEVICE_ID_RME_DIGI32 0x9896
#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
diff --git a/src/post.c b/src/post.c
index 638b0f7..25535e2 100644
--- a/src/post.c
+++ b/src/post.c
@@ -23,6 +23,7 @@
#include smbios.h // smbios_init
#include paravirt.h // qemu_cfg_port_probe
#include ps2port.h // ps2port_setup
+#include virtio-blk.h // virtio_blk_setup
void
__set_irq(int vector, void *loc)
@@ -184,6 +185,7 @@ init_hw(void)
floppy_setup();
ata_setup();
ramdisk_setup();
+virtio_blk_setup();
}
// Main setup code.
diff --git a/src/virtio-blk.c b/src/virtio-blk.c
new file mode 100644
index 000..f106bdf
--- /dev/null
+++ b/src/virtio-blk.c
@@ -0,0 +1,158 @@
+// Virtio block boot support.
+//
+// Copyright (C) 2010 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov gnata...@redhat.com
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include util.h // dprintf
+#include pci.h // foreachpci
+#include config.h // CONFIG_*
+#include virtio-pci.h
+#include virtio-blk.h
+#include disk.h
+
+struct virtiodrive_s {
+struct drive_s drive;
+struct vring_virtqueue *vq;
+u16 ioaddr;
+};
+
+static int
+virtio_blk_read(struct disk_op_s *op)
+{
+struct virtiodrive_s *vdrive_g =
+container_of(op-drive_g, struct virtiodrive_s, drive);
+struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g-vq);
+struct virtio_blk_outhdr hdr = {
+.type = VIRTIO_BLK_T_IN,
+.ioprio = 0,
+.sector = op-lba,
+};
+u8 status = VIRTIO_BLK_S_UNSUPP;
+struct vring_list sg[] = {
+{
+.addr = MAKE_FLATPTR(GET_SEG(SS), hdr),
+.length= sizeof(hdr),
+},
+{
+.addr = op-buf_fl,
+.length= GET_GLOBAL(vdrive_g-drive.blksize) * op-count,
+},
+{
+.addr = MAKE_FLATPTR(GET_SEG(SS), status),
+.length= sizeof(status),
+},
+};
+
+/* Add to virtqueue and kick host */
+vring_add_buf(vq, sg, 1, 2, 0, 0);
+vring_kick(GET_GLOBAL(vdrive_g-ioaddr), vq, 1);
+
+/* Wait for reply */
+while (!vring_more_used(vq))
+udelay(5);
+
+/* Reclaim virtqueue element */
+vring_get_buf(vq, NULL);
+return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int