#include "libqos/virtio-pci.h"
#include "libqos/virtio-mmio.h"
#include "libqos/malloc-generic.h"
+#include "qapi/qmp/qdict.h"
#include "qemu/bswap.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_config.h"
#include "standard-headers/linux/virtio_blk.h"
#include "standard-headers/linux/virtio_pci.h"
+/* TODO actually test the results and get rid of this */
+#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+
#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
#define PCI_SLOT_HP 0x06
g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
+ global_qtest = qs->qts;
unlink(tmp_path);
g_free(tmp_path);
return qs;
static void arm_test_start(void)
{
- char *cmdline;
char *tmp_path;
tmp_path = drive_create();
- cmdline = g_strdup_printf("-machine virt "
- "-drive if=none,id=drive0,file=%s,format=raw "
- "-device virtio-blk-device,drive=drive0",
- tmp_path);
- qtest_start(cmdline);
+ global_qtest = qtest_initf("-machine virt "
+ "-drive if=none,id=drive0,file=%s,format=raw "
+ "-device virtio-blk-device,drive=drive0",
+ tmp_path);
unlink(tmp_path);
g_free(tmp_path);
- g_free(cmdline);
}
static void test_end(void)
qvirtqueue_kick(dev, vq, free_head);
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
qvirtqueue_kick(dev, vq, free_head);
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
qvirtqueue_add(vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(dev, vq, free_head);
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
qvirtqueue_kick(dev, vq, free_head);
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
uint64_t capacity;
uint32_t features;
uint32_t free_head;
+ uint32_t write_head;
+ uint32_t desc_idx;
uint8_t status;
char *data;
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
/* Write request */
req.type = VIRTIO_BLK_T_OUT;
qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+ write_head = free_head;
/* No notification expected */
status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
+ /* We get just one notification for both requests */
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head, NULL,
QVIRTIO_BLK_TIMEOUT_US);
+ g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx, NULL));
+ g_assert_cmpint(desc_idx, ==, free_head);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
qs = pci_test_start();
/* plug secondary disk */
- qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
- "'drive': 'drive1'");
+ qtest_qmp_device_add("virtio-blk-pci", "drv1",
+ "{'addr': %s, 'drive': 'drive1'}",
+ stringify(PCI_SLOT_HP));
dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
g_assert(dev);
qtest_shutdown(qs);
}
+/*
+ * Check that setting the vring addr on a non-existent virtqueue does
+ * not crash.
+ */
+static void test_nonexistent_virtqueue(void)
+{
+ QPCIBar bar0;
+ QOSState *qs;
+ QPCIDevice *dev;
+
+ qs = pci_test_start();
+ dev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4, 0));
+ g_assert(dev != NULL);
+
+ qpci_device_enable(dev);
+ bar0 = qpci_iomap(dev, 0, NULL);
+
+ qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
+ qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
+
+ g_free(dev);
+ qtest_shutdown(qs);
+}
+
static void mmio_basic(void)
{
QVirtioMMIODevice *dev;
qtest_add_func("/virtio/blk/pci/basic", pci_basic);
qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
qtest_add_func("/virtio/blk/pci/config", pci_config);
+ qtest_add_func("/virtio/blk/pci/nxvirtq", test_nonexistent_virtqueue);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
qtest_add_func("/virtio/blk/pci/msix", pci_msix);
qtest_add_func("/virtio/blk/pci/idx", pci_idx);