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 --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c
index d32c953a38..39d2e26f76 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, ==, 0);
+ 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, 0x4c, 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);
--
2.17.1