mirror of
				https://github.com/mborgerson/xemu.git
				synced 2025-10-30 03:31:27 +00:00 
			
		
		
		
	QEMU headers are relative to the include/ directory, not to the project root directory. Remove "include/". See also: https://www.qemu.org/docs/master/devel/style.html#include-directives Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20240507142737.95735-1-philmd@linaro.org>
		
			
				
	
	
		
			174 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * QTest testcase for NVMe
 | |
|  *
 | |
|  * Copyright (c) 2014 SUSE LINUX Products GmbH
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu/module.h"
 | |
| #include "qemu/units.h"
 | |
| #include "libqtest.h"
 | |
| #include "libqos/qgraph.h"
 | |
| #include "libqos/pci.h"
 | |
| #include "block/nvme.h"
 | |
| 
 | |
| typedef struct QNvme QNvme;
 | |
| 
 | |
| struct QNvme {
 | |
|     QOSGraphObject obj;
 | |
|     QPCIDevice dev;
 | |
| };
 | |
| 
 | |
| static void *nvme_get_driver(void *obj, const char *interface)
 | |
| {
 | |
|     QNvme *nvme = obj;
 | |
| 
 | |
|     if (!g_strcmp0(interface, "pci-device")) {
 | |
|         return &nvme->dev;
 | |
|     }
 | |
| 
 | |
|     fprintf(stderr, "%s not present in nvme\n", interface);
 | |
|     g_assert_not_reached();
 | |
| }
 | |
| 
 | |
| static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 | |
| {
 | |
|     QNvme *nvme = g_new0(QNvme, 1);
 | |
|     QPCIBus *bus = pci_bus;
 | |
| 
 | |
|     qpci_device_init(&nvme->dev, bus, addr);
 | |
|     nvme->obj.get_driver = nvme_get_driver;
 | |
| 
 | |
|     return &nvme->obj;
 | |
| }
 | |
| 
 | |
| /* This used to cause a NULL pointer dereference.  */
 | |
| static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
 | |
| {
 | |
|     const int cmb_bar_size = 2 * MiB;
 | |
|     QNvme *nvme = obj;
 | |
|     QPCIDevice *pdev = &nvme->dev;
 | |
|     QPCIBar bar;
 | |
| 
 | |
|     qpci_device_enable(pdev);
 | |
|     bar = qpci_iomap(pdev, 2, NULL);
 | |
| 
 | |
|     qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
 | |
|     g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
 | |
|     g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);
 | |
| 
 | |
|     /* Test partially out-of-bounds accesses.  */
 | |
|     qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
 | |
|     g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
 | |
|     g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
 | |
|     g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
 | |
| }
 | |
| 
 | |
| static void nvmetest_reg_read_test(void *obj, void *data, QGuestAllocator *alloc)
 | |
| {
 | |
|     QNvme *nvme = obj;
 | |
|     QPCIDevice *pdev = &nvme->dev;
 | |
|     QPCIBar bar;
 | |
|     uint32_t cap_lo, cap_hi;
 | |
|     uint64_t cap;
 | |
| 
 | |
|     qpci_device_enable(pdev);
 | |
|     bar = qpci_iomap(pdev, 0, NULL);
 | |
| 
 | |
|     cap_lo = qpci_io_readl(pdev, bar, 0x0);
 | |
|     g_assert_cmpint(NVME_CAP_MQES(cap_lo), ==, 0x7ff);
 | |
| 
 | |
|     cap_hi = qpci_io_readl(pdev, bar, 0x4);
 | |
|     g_assert_cmpint(NVME_CAP_MPSMAX((uint64_t)cap_hi << 32), ==, 0x4);
 | |
| 
 | |
|     cap = qpci_io_readq(pdev, bar, 0x0);
 | |
|     g_assert_cmpint(NVME_CAP_MQES(cap), ==, 0x7ff);
 | |
|     g_assert_cmpint(NVME_CAP_MPSMAX(cap), ==, 0x4);
 | |
| 
 | |
|     qpci_iounmap(pdev, bar);
 | |
| }
 | |
| 
 | |
| static void nvmetest_pmr_reg_test(void *obj, void *data, QGuestAllocator *alloc)
 | |
| {
 | |
|     QNvme *nvme = obj;
 | |
|     QPCIDevice *pdev = &nvme->dev;
 | |
|     QPCIBar pmr_bar, nvme_bar;
 | |
|     uint32_t pmrcap, pmrsts;
 | |
| 
 | |
|     qpci_device_enable(pdev);
 | |
|     pmr_bar = qpci_iomap(pdev, 4, NULL);
 | |
| 
 | |
|     /* Without Enabling PMRCTL check bar enablemet */
 | |
|     qpci_io_writel(pdev, pmr_bar, 0, 0xccbbaa99);
 | |
|     g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x99);
 | |
|     g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0xaa99);
 | |
| 
 | |
|     /* Map NVMe Bar Register to Enable the Mem Region */
 | |
|     nvme_bar = qpci_iomap(pdev, 0, NULL);
 | |
| 
 | |
|     pmrcap = qpci_io_readl(pdev, nvme_bar, 0xe00);
 | |
|     g_assert_cmpint(NVME_PMRCAP_RDS(pmrcap), ==, 0x1);
 | |
|     g_assert_cmpint(NVME_PMRCAP_WDS(pmrcap), ==, 0x1);
 | |
|     g_assert_cmpint(NVME_PMRCAP_BIR(pmrcap), ==, 0x4);
 | |
|     g_assert_cmpint(NVME_PMRCAP_PMRWBM(pmrcap), ==, 0x2);
 | |
|     g_assert_cmpint(NVME_PMRCAP_CMSS(pmrcap), ==, 0x1);
 | |
| 
 | |
|     /* Enable PMRCTRL */
 | |
|     qpci_io_writel(pdev, nvme_bar, 0xe04, 0x1);
 | |
| 
 | |
|     qpci_io_writel(pdev, pmr_bar, 0, 0x44332211);
 | |
|     g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), ==, 0x11);
 | |
|     g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), ==, 0x2211);
 | |
|     g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), ==, 0x44332211);
 | |
| 
 | |
|     pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08);
 | |
|     g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x0);
 | |
| 
 | |
|     /* Disable PMRCTRL */
 | |
|     qpci_io_writel(pdev, nvme_bar, 0xe04, 0x0);
 | |
| 
 | |
|     qpci_io_writel(pdev, pmr_bar, 0, 0x88776655);
 | |
|     g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x55);
 | |
|     g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0x6655);
 | |
|     g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), !=, 0x88776655);
 | |
| 
 | |
|     pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08);
 | |
|     g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x1);
 | |
| 
 | |
|     qpci_iounmap(pdev, nvme_bar);
 | |
|     qpci_iounmap(pdev, pmr_bar);
 | |
| }
 | |
| 
 | |
| static void nvme_register_nodes(void)
 | |
| {
 | |
|     QOSGraphEdgeOptions opts = {
 | |
|         .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
 | |
|         .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
 | |
|                            "file.read-zeroes=on,format=raw "
 | |
|                            "-object memory-backend-ram,id=pmr0,"
 | |
|                            "share=on,size=8",
 | |
|     };
 | |
| 
 | |
|     add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 | |
| 
 | |
|     qos_node_create_driver("nvme", nvme_create);
 | |
|     qos_node_consumes("nvme", "pci-bus", &opts);
 | |
|     qos_node_produces("nvme", "pci-device");
 | |
| 
 | |
|     qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
 | |
|         .edge.extra_device_opts = "cmb_size_mb=2"
 | |
|     });
 | |
| 
 | |
|     qos_add_test("pmr-test-access", "nvme", nvmetest_pmr_reg_test,
 | |
|                  &(QOSGraphTestOptions) {
 | |
|         .edge.extra_device_opts = "pmrdev=pmr0"
 | |
|     });
 | |
| 
 | |
|     qos_add_test("reg-read", "nvme", nvmetest_reg_read_test, NULL);
 | |
| }
 | |
| 
 | |
| libqos_init(nvme_register_nodes);
 |