Message ID | 20210601143749.1669-3-anaidu.gollu@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | add boot partitions support and read test case | expand |
On Jun 1 20:07, Gollu Appalanaidu wrote: >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); This one byte pattern is too simple and won't catch a lot of possible bugs. The test case should use generate_pattern() (see tests/qtest/libqos/libqos.h). >+ >+ 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 > >
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);
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(-)