Add read*/write*_fail qtest APIs to check for memory access failures.
Signed-off-by: Octavian Purdila <tavip@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 beb96b18eb..f9bbeb2e60 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 12703a2045..95bb80a2bc 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -514,26 +514,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 ||
@@ -548,26 +552,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 9d07de1fbd..4055d6b953 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -666,7 +666,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;
@@ -700,7 +700,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);
@@ -709,6 +713,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);
@@ -716,6 +725,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;
@@ -1103,6 +1119,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);
@@ -1123,6 +1146,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;
@@ -1138,6 +1181,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);
@@ -1158,6 +1207,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.662.g92d0881bb0-goog