Add read*/write*_fail qtest APIs to check for memory access failures. Signed-off-by: Octavian Purdila <ta...@google.com> --- tests/qtest/libqtest-single.h | 92 +++++++++++++++++++++++++++++++++++ tests/qtest/libqtest.h | 76 +++++++++++++++++++++++++++++ system/qtest.c | 44 ++++++++++------- tests/qtest/libqtest.c | 73 ++++++++++++++++++++++++++- 4 files changed, 265 insertions(+), 20 deletions(-)
diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h index 851724cbcb..c22037c8b2 100644 --- a/tests/qtest/libqtest-single.h +++ b/tests/qtest/libqtest-single.h @@ -265,6 +265,98 @@ static inline uint64_t readq(uint64_t addr) return qtest_readq(global_qtest, addr); } +/** + * writeb_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to memory expecting a failure. + */ +static inline void writeb_fail(uint64_t addr, uint8_t value) +{ + qtest_writeb_fail(global_qtest, addr, value); +} + +/** + * writew_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to memory expecting a failure. + */ +static inline void writew_fail(uint64_t addr, uint16_t value) +{ + qtest_writew_fail(global_qtest, addr, value); +} + +/** + * writel_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to memory expecting a failure. + */ +static inline void writel_fail(uint64_t addr, uint32_t value) +{ + qtest_writel_fail(global_qtest, addr, value); +} + +/** + * writeq_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to memory expecting a failure. + */ +static inline void writeq_fail(uint64_t addr, uint64_t value) +{ + qtest_writeq_fail(global_qtest, addr, value); +} + +/** + * readb_fail: + * @addr: Guest address to read from. + * + * Reads an 8-bit value from memory expecting a failure. + */ +static inline void readb_fail(uint64_t addr) +{ + qtest_readb_fail(global_qtest, addr); +} + +/** + * readw_fail: + * @addr: Guest address to read from. + * + * Reads a 16-bit value from memory expecting a failure. + */ +static inline void readw_fail(uint64_t addr) +{ + qtest_readw_fail(global_qtest, addr); +} + +/** + * readl_fail: + * @addr: Guest address to read from. + * + * Reads a 32-bit value from memory expecting a failure. + */ +static inline void readl_fail(uint64_t addr) +{ + qtest_readl_fail(global_qtest, addr); +} + +/** + * readq_fail: + * @addr: Guest address to read from. + * + * Reads a 64-bit value from memory expecting a failure. + */ +static inline void readq_fail(uint64_t addr) +{ + qtest_readq_fail(global_qtest, addr); +} + /** * memread: * @addr: Guest address to read from. diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 6e3d3525bf..9057d019c6 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -549,6 +549,82 @@ uint32_t qtest_readl(QTestState *s, uint64_t addr); */ uint64_t qtest_readq(QTestState *s, uint64_t addr); +/** + * qtest_writeb_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to memory expecting a failure. + */ +void qtest_writeb_fail(QTestState *s, uint64_t addr, uint8_t value); + +/** + * qtest_writew_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to memory expecting a failure. + */ +void qtest_writew_fail(QTestState *s, uint64_t addr, uint16_t value); + +/** + * qtest_writel_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to memory expecting a failure. + */ +void qtest_writel_fail(QTestState *s, uint64_t addr, uint32_t value); + +/** + * qtest_writeq_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to memory expecting a failure. + */ +void qtest_writeq_fail(QTestState *s, uint64_t addr, uint64_t value); + +/** + * qtest_readb_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads an 8-bit value from memory expecting a failure. + */ +void qtest_readb_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readw_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 16-bit value from memory expecting a failure. + */ +void qtest_readw_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readl_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 32-bit value from memory expecting a failure. + */ +void qtest_readl_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readq_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 64-bit value from memory expecting a failure. + */ +void qtest_readq_fail(QTestState *s, uint64_t addr); + /** * qtest_memread: * @s: #QTestState instance to operate on. diff --git a/system/qtest.c b/system/qtest.c index 507a358f3b..da46388a6e 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -546,26 +546,30 @@ static void qtest_process_command(CharBackend *chr, gchar **words) if (words[0][5] == 'b') { uint8_t data = value; - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 1); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 1); } else if (words[0][5] == 'w') { uint16_t data = value; tswap16s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 2); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 2); } else if (words[0][5] == 'l') { uint32_t data = value; tswap32s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 4); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 4); } else if (words[0][5] == 'q') { uint64_t data = value; tswap64s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 8); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 8); } qtest_send_prefix(chr); - qtest_send(chr, "OK\n"); + if (ret == MEMTX_OK) { + qtest_send(chr, "OK\n"); + } else { + qtest_send(chr, "FAIL\n"); + } } else if (strcmp(words[0], "readb") == 0 || strcmp(words[0], "readw") == 0 || strcmp(words[0], "readl") == 0 || @@ -580,26 +584,30 @@ static void qtest_process_command(CharBackend *chr, gchar **words) if (words[0][4] == 'b') { uint8_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 1); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 1); value = data; } else if (words[0][4] == 'w') { uint16_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 2); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 2); value = tswap16(data); } else if (words[0][4] == 'l') { uint32_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 4); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 4); value = tswap32(data); } else if (words[0][4] == 'q') { - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &value, 8); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &value, 8); tswap64s(&value); } qtest_send_prefix(chr); - qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value); + if (ret == MEMTX_OK) { + qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value); + } else { + qtest_sendf(chr, "FAIL\n"); + } } else if (strcmp(words[0], "read") == 0) { g_autoptr(GString) enc = NULL; uint64_t addr, len; diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index d8f80d335e..62ba49d5d8 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -665,7 +665,7 @@ static GString *qtest_client_socket_recv_line(QTestState *s) return line; } -static gchar **qtest_rsp_args(QTestState *s, int expected_args) +static gchar **_qtest_rsp_args(QTestState *s, int expected_args, bool fail) { GString *line; gchar **words; @@ -699,7 +699,11 @@ redo: } g_assert(words[0] != NULL); - g_assert_cmpstr(words[0], ==, "OK"); + if (fail) { + g_assert_cmpstr(words[0], ==, "FAIL"); + } else { + g_assert_cmpstr(words[0], ==, "OK"); + } for (i = 0; i < expected_args; i++) { g_assert(words[i] != NULL); @@ -708,6 +712,11 @@ redo: return words; } +static gchar **qtest_rsp_args(QTestState *s, int expected_args) +{ + return _qtest_rsp_args(s, expected_args, false); +} + static void qtest_rsp(QTestState *s) { gchar **words = qtest_rsp_args(s, 0); @@ -715,6 +724,13 @@ static void qtest_rsp(QTestState *s) g_strfreev(words); } +static void qtest_rsp_fail(QTestState *s) +{ + gchar **words = _qtest_rsp_args(s, 0, true); + + g_strfreev(words); +} + static int qtest_query_target_endianness(QTestState *s) { gchar **args; @@ -1100,6 +1116,13 @@ static void qtest_write(QTestState *s, const char *cmd, uint64_t addr, qtest_rsp(s); } +static void qtest_write_fail(QTestState *s, const char *cmd, uint64_t addr, + uint64_t value) +{ + qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value); + qtest_rsp_fail(s); +} + void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) { qtest_write(s, "writeb", addr, value); @@ -1120,6 +1143,26 @@ void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) qtest_write(s, "writeq", addr, value); } +void qtest_writeb_fail(QTestState *s, uint64_t addr, uint8_t value) +{ + qtest_write_fail(s, "writeb", addr, value); +} + +void qtest_writew_fail(QTestState *s, uint64_t addr, uint16_t value) +{ + qtest_write_fail(s, "writew", addr, value); +} + +void qtest_writel_fail(QTestState *s, uint64_t addr, uint32_t value) +{ + qtest_write_fail(s, "writel", addr, value); +} + +void qtest_writeq_fail(QTestState *s, uint64_t addr, uint64_t value) +{ + qtest_write_fail(s, "writeq", addr, value); +} + static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr) { gchar **args; @@ -1135,6 +1178,12 @@ static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr) return value; } +static void qtest_read_fail(QTestState *s, const char *cmd, uint64_t addr) +{ + qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr); + qtest_rsp_fail(s); +} + uint8_t qtest_readb(QTestState *s, uint64_t addr) { return qtest_read(s, "readb", addr); @@ -1155,6 +1204,26 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr) return qtest_read(s, "readq", addr); } +void qtest_readb_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readb", addr); +} + +void qtest_readw_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readw", addr); +} + +void qtest_readl_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readl", addr); +} + +void qtest_readq_fail(QTestState *s, uint64_t addr) +{ + qtest_read(s, "readq", addr); +} + static int hex2nib(char ch) { if (ch >= '0' && ch <= '9') { -- 2.46.0.295.g3b9ea8a38a-goog