diff mbox series

[2/2] tests/qtest/nvme-test: add boot partition read test

Message ID 20210524212416.26652-3-anaidu.gollu@samsung.com
State New
Headers show
Series add boot partitions support and read test case | expand

Commit Message

Gollu Appalanaidu May 24, 2021, 9:24 p.m. UTC
Add a test case for reading an NVMe Boot Partition without
enabling the controller.

Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
---
 tests/qtest/nvme-test.c | 118 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c
index d32c953a38..8409adac04 100644
--- a/tests/qtest/nvme-test.c
+++ b/tests/qtest/nvme-test.c
@@ -13,6 +13,19 @@ 
 #include "libqos/libqtest.h"
 #include "libqos/qgraph.h"
 #include "libqos/pci.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc-pc.h"
+#include "libqos/malloc.h"
+#include "libqos/libqos.h"
+#include "include/block/nvme.h"
+#include "include/hw/pci/pci.h"
+
+#define NVME_BPINFO_BPSZ_UNITS  (128 * KiB)
+#define NVME_BRS_BPSZ_UNITS     (4 * KiB)
+#define NVME_BRS_READ_MAX_TIME  1000000
+#define TEST_IMAGE_SIZE         (2 * 128 * KiB)
+
+static char *t_path;
 
 typedef struct QNvme QNvme;
 
@@ -44,6 +57,13 @@  static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
     return &nvme->obj;
 }
 
+static void drive_destroy(void *path)
+{
+    unlink(path);
+    g_free(path);
+    qos_invalidate_command_line();
+}
+
 /* This used to cause a NULL pointer dereference.  */
 static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
 {
@@ -66,12 +86,100 @@  static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
     g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
 }
 
+static void nvmetest_bp_read_test(void *obj, void *data, QGuestAllocator *alloc)
+{
+    uint16_t test_size = 32;
+    size_t bp_test_len = test_size * NVME_BRS_BPSZ_UNITS;
+    uint8_t *read_buf = g_malloc(bp_test_len);
+    uint8_t *cmp_buf = g_malloc(bp_test_len);
+    QNvme *nvme = obj;
+    QPCIDevice *pdev = &nvme->dev;
+    QPCIBar nvme_bar;
+    uint8_t brs = 0;
+    uint64_t sleep_time = 0;
+    uintptr_t guest_buf;
+    uint64_t buf_addr;
+
+    memset(cmp_buf, 0x42, bp_test_len);
+
+    guest_buf = guest_alloc(alloc, bp_test_len);
+    buf_addr = cpu_to_le64(guest_buf);
+
+    qpci_device_enable(pdev);
+    nvme_bar = qpci_iomap(pdev, 0, NULL);
+
+    /* BPINFO */
+    uint32_t bpinfo = qpci_io_readl(pdev, nvme_bar, 0x40);
+    uint16_t single_bp_size = bpinfo & BPINFO_BPSZ_MASK;
+    uint8_t active_bpid = bpinfo >> BPINFO_ABPID_SHIFT;
+    uint8_t read_select = (bpinfo >> BPINFO_BRS_SHIFT) & BPINFO_BRS_MASK;
+
+    g_assert_cmpint(single_bp_size, ==, 0x1);
+    g_assert_cmpint(active_bpid, ==, 0x1);
+    g_assert_cmpint(read_select, ==, NVME_BPINFO_BRS_NOREAD);
+
+    /* BPMBL */
+    uint64_t bpmbl = buf_addr;
+    uint32_t bpmbl_low = bpmbl & 0xffffffff;
+    uint32_t bpmbl_hi = (bpmbl >> 32) & 0xffffffff;
+    qpci_io_writel(pdev, nvme_bar, 0x48, bpmbl_low);
+    qpci_io_writel(pdev, nvme_bar, 0x4B, bpmbl_hi);
+
+    /* BPRSEL */
+    qpci_io_writel(pdev, nvme_bar, 0x44, 32);
+
+    while (true) {
+        usleep(1000);
+        sleep_time += 1000;
+        brs = qpci_io_readb(pdev, nvme_bar, 0x43) & BPINFO_BRS_MASK;
+        if (brs == NVME_BPINFO_BRS_SUCCESS || brs == NVME_BPINFO_BRS_ERROR ||
+            sleep_time == NVME_BRS_READ_MAX_TIME) {
+            break;
+        }
+    }
+    g_assert_cmpint(brs, ==, NVME_BPINFO_BRS_SUCCESS);
+
+    qtest_memread(pdev->bus->qts, guest_buf, read_buf, bp_test_len);
+    g_assert_cmpint(memcmp(cmp_buf, read_buf, bp_test_len), ==, 0);
+
+    g_free(cmp_buf);
+    g_free(read_buf);
+    g_test_queue_destroy(drive_destroy, t_path);
+}
+
 static void nvme_register_nodes(void)
 {
+    int fd;
+    FILE *fh;
+    uint16_t bpsz = 2;
+    size_t bp_len = NVME_BPINFO_BPSZ_UNITS * bpsz;
+    size_t ret;
+    uint8_t *pattern = g_malloc(bp_len);
+
+    t_path = g_strdup("/tmp/qtest.XXXXXX");
+
+    /* Create a temporary raw image */
+    fd = mkstemp(t_path);
+    g_assert_cmpint(fd, >=, 0);
+    ret = ftruncate(fd, TEST_IMAGE_SIZE);
+    g_assert_cmpint(ret, ==, 0);
+    close(fd);
+
+    memset(pattern, 0x42, bp_len);
+
+    fh = fopen(t_path, "w+");
+    ret = fwrite(pattern, NVME_BPINFO_BPSZ_UNITS, bpsz, fh);
+    g_assert_cmpint(ret, ==, bpsz);
+    fclose(fh);
+
+    char *bp_cmd_line = g_strdup_printf("-drive id=bp0,file=%s,if=none,"
+                                        "format=raw", t_path);
+
     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",
+                           "file.read-zeroes=on,format=raw ",
+                           bp_cmd_line,
     };
 
     add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
@@ -83,6 +191,14 @@  static void nvme_register_nodes(void)
     qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
         .edge.extra_device_opts = "cmb_size_mb=2"
     });
+
+    qos_add_test("bp-read-access", "nvme", nvmetest_bp_read_test,
+                 &(QOSGraphTestOptions) {
+        .edge.extra_device_opts = "bootpart=bp0"
+    });
+
+    /* Clean Up */
+    g_free(pattern);
 }
 
 libqos_init(nvme_register_nodes);