xref: /qemu/tests/qtest/nvme-test.c (revision abff1abf)
1 /*
2  * QTest testcase for NVMe
3  *
4  * Copyright (c) 2014 SUSE LINUX Products GmbH
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "qemu/module.h"
12 #include "qemu/units.h"
13 #include "libqos/libqtest.h"
14 #include "libqos/qgraph.h"
15 #include "libqos/pci.h"
16 
17 typedef struct QNvme QNvme;
18 
19 struct QNvme {
20     QOSGraphObject obj;
21     QPCIDevice dev;
22 };
23 
24 static void *nvme_get_driver(void *obj, const char *interface)
25 {
26     QNvme *nvme = obj;
27 
28     if (!g_strcmp0(interface, "pci-device")) {
29         return &nvme->dev;
30     }
31 
32     fprintf(stderr, "%s not present in nvme\n", interface);
33     g_assert_not_reached();
34 }
35 
36 static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
37 {
38     QNvme *nvme = g_new0(QNvme, 1);
39     QPCIBus *bus = pci_bus;
40 
41     qpci_device_init(&nvme->dev, bus, addr);
42     nvme->obj.get_driver = nvme_get_driver;
43 
44     return &nvme->obj;
45 }
46 
47 /* This used to cause a NULL pointer dereference.  */
48 static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
49 {
50     const int cmb_bar_size = 2 * MiB;
51     QNvme *nvme = obj;
52     QPCIDevice *pdev = &nvme->dev;
53     QPCIBar bar;
54 
55     qpci_device_enable(pdev);
56     bar = qpci_iomap(pdev, 2, NULL);
57 
58     qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
59     g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
60     g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);
61 
62     /* Test partially out-of-bounds accesses.  */
63     qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
64     g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
65     g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
66     g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
67 }
68 
69 static void nvme_register_nodes(void)
70 {
71     QOSGraphEdgeOptions opts = {
72         .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
73         .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
74                            "file.read-zeroes=on,format=raw",
75     };
76 
77     add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
78 
79     qos_node_create_driver("nvme", nvme_create);
80     qos_node_consumes("nvme", "pci-bus", &opts);
81     qos_node_produces("nvme", "pci-device");
82 
83     qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
84         .edge.extra_device_opts = "cmb_size_mb=2"
85     });
86 }
87 
88 libqos_init(nvme_register_nodes);
89