Merge tag 'pull-tcg-20240723' of https://gitlab.com/rth7680/qemu into staging
accel/tcg: Export set/clear_helper_retaddr
target/arm: Use set_helper_retaddr for dc_zva, sve and sme
target/ppc: Tidy dcbz helpers
target/ppc: Use set_helper_retaddr for dcbz
target/s390x: Use set_helper_retaddr in mem_helper.c
# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmafJKIdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+FBAf7Bup+karxeGHZx2rN
# cPeF248bcCWTxBWHK7dsYze4KqzsrlNIJlPeOKErU2bbbRDZGhOp1/N95WVz+P8V
# 6Ny63WTsAYkaFWKxE6Jf0FWJlGw92btk75pTV2x/TNZixg7jg0vzVaYkk0lTYc5T
# m5e4WycYEbzYm0uodxI09i+wFvpd+7WCnl6xWtlJPWZENukvJ36Ss43egFMDtuMk
# vTJuBkS9wpwZ9MSi6EY6M+Raieg8bfaotInZeDvE/yRPNi7CwrA7Dgyc1y626uBA
# joGkYRLzhRgvT19kB3bvFZi1AXa0Pxr+j0xJqwspP239Gq5qezlS5Bv/DrHdmGHA
# jaqSwg==
# =XgUE
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 23 Jul 2024 01:33:54 PM AEST
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]
* tag 'pull-tcg-20240723' of https://gitlab.com/rth7680/qemu:
target/riscv: Simplify probing in vext_ldff
target/s390x: Use set/clear_helper_retaddr in mem_helper.c
target/s390x: Use user_or_likely in access_memmove
target/s390x: Use user_or_likely in do_access_memset
target/ppc: Improve helper_dcbz for user-only
target/ppc: Merge helper_{dcbz,dcbzep}
target/ppc: Split out helper_dbczl for 970
target/ppc: Hoist dcbz_size out of dcbz_common
target/ppc/mem_helper.c: Remove a conditional from dcbz_common()
target/arm: Use set/clear_helper_retaddr in SVE and SME helpers
target/arm: Use set/clear_helper_retaddr in helper-a64.c
accel/tcg: Move {set,clear}_helper_retaddr to cpu_ldst.h
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars
index 3785afc..29ab964 100644
--- a/.gitlab-ci.d/cirrus/freebsd-13.vars
+++ b/.gitlab-ci.d/cirrus/freebsd-13.vars
@@ -11,6 +11,6 @@
NINJA='/usr/local/bin/ninja'
PACKAGING_COMMAND='pkg'
PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-tomli py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
+PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py311-numpy py311-pillow py311-pip py311-sphinx py311-sphinx_rtd_theme py311-tomli py311-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
PYPI_PKGS=''
PYTHON='/usr/local/bin/python3'
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d98114..d5ff6c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1727,7 +1727,6 @@
F: hw/sparc/leon3.c
F: hw/*/grlib*
F: include/hw/*/grlib*
-F: tests/avocado/machine_sparc_leon3.py
S390 Machines
-------------
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index b6bae32..ec89a08 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -85,8 +85,7 @@
len = insn->mem_cbs->len;
arr = g_array_sized_new(false, false,
sizeof(struct qemu_plugin_dyn_cb), len);
- memcpy(arr->data, insn->mem_cbs->data,
- len * sizeof(struct qemu_plugin_dyn_cb));
+ g_array_append_vals(arr, insn->mem_cbs->data, len);
qemu_plugin_add_dyn_cb_arr(arr);
tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index 449ead1..98a89d5 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -28,6 +28,7 @@
NAMES += cache
NAMES += drcov
NAMES += ips
+NAMES += stoptrigger
ifeq ($(CONFIG_WIN32),y)
SO_SUFFIX := .dll
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index 371db97..1c1601c 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -101,7 +101,7 @@
GByteArray *temp = reg->last;
g_string_append_printf(cpu->last_exec, ", %s -> 0x", reg->name);
/* TODO: handle BE properly */
- for (int i = sz; i >= 0; i--) {
+ for (int i = sz - 1; i >= 0; i--) {
g_string_append_printf(cpu->last_exec, "%02x",
reg->new->data[i]);
}
diff --git a/contrib/plugins/stoptrigger.c b/contrib/plugins/stoptrigger.c
new file mode 100644
index 0000000..03ee22f
--- /dev/null
+++ b/contrib/plugins/stoptrigger.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024, Simon Hamelin <simon.hamelin@grenoble-inp.org>
+ *
+ * Stop execution once a given address is reached or if the
+ * count of executed instructions reached a specified limit
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <assert.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+/* Scoreboard to track executed instructions count */
+typedef struct {
+ uint64_t insn_count;
+} InstructionsCount;
+static struct qemu_plugin_scoreboard *insn_count_sb;
+static qemu_plugin_u64 insn_count;
+
+static uint64_t icount;
+static int icount_exit_code;
+
+static bool exit_on_icount;
+static bool exit_on_address;
+
+/* Map trigger addresses to exit code */
+static GHashTable *addrs_ht;
+
+static void exit_emulation(int return_code, char *message)
+{
+ qemu_plugin_outs(message);
+ g_free(message);
+ exit(return_code);
+}
+
+static void exit_icount_reached(unsigned int cpu_index, void *udata)
+{
+ uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
+ char *msg = g_strdup_printf("icount reached at 0x%" PRIx64 ", exiting\n",
+ insn_vaddr);
+
+ exit_emulation(icount_exit_code, msg);
+}
+
+static void exit_address_reached(unsigned int cpu_index, void *udata)
+{
+ uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
+ char *msg = g_strdup_printf("0x%" PRIx64 " reached, exiting\n", insn_vaddr);
+ int exit_code;
+
+ exit_code = GPOINTER_TO_INT(
+ g_hash_table_lookup(addrs_ht, GUINT_TO_POINTER(insn_vaddr)));
+
+ exit_emulation(exit_code, msg);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ size_t tb_n = qemu_plugin_tb_n_insns(tb);
+ for (size_t i = 0; i < tb_n; i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+ gpointer insn_vaddr = GUINT_TO_POINTER(qemu_plugin_insn_vaddr(insn));
+
+ if (exit_on_icount) {
+ /* Increment and check scoreboard for each instruction */
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
+ insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
+ qemu_plugin_register_vcpu_insn_exec_cond_cb(
+ insn, exit_icount_reached, QEMU_PLUGIN_CB_NO_REGS,
+ QEMU_PLUGIN_COND_EQ, insn_count, icount + 1, insn_vaddr);
+ }
+
+ if (exit_on_address) {
+ if (g_hash_table_contains(addrs_ht, insn_vaddr)) {
+ /* Exit triggered by address */
+ qemu_plugin_register_vcpu_insn_exec_cb(
+ insn, exit_address_reached, QEMU_PLUGIN_CB_NO_REGS,
+ insn_vaddr);
+ }
+ }
+ }
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_hash_table_destroy(addrs_ht);
+ qemu_plugin_scoreboard_free(insn_count_sb);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info, int argc,
+ char **argv)
+{
+ addrs_ht = g_hash_table_new(NULL, g_direct_equal);
+
+ insn_count_sb = qemu_plugin_scoreboard_new(sizeof(InstructionsCount));
+ insn_count = qemu_plugin_scoreboard_u64_in_struct(
+ insn_count_sb, InstructionsCount, insn_count);
+
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "icount") == 0) {
+ g_auto(GStrv) icount_tokens = g_strsplit(tokens[1], ":", 2);
+ icount = g_ascii_strtoull(icount_tokens[0], NULL, 0);
+ if (icount < 1 || g_strrstr(icount_tokens[0], "-") != NULL) {
+ fprintf(stderr,
+ "icount parsing failed: '%s' must be a positive "
+ "integer\n",
+ icount_tokens[0]);
+ return -1;
+ }
+ if (icount_tokens[1]) {
+ icount_exit_code = g_ascii_strtoull(icount_tokens[1], NULL, 0);
+ }
+ exit_on_icount = true;
+ } else if (g_strcmp0(tokens[0], "addr") == 0) {
+ g_auto(GStrv) addr_tokens = g_strsplit(tokens[1], ":", 2);
+ uint64_t exit_addr = g_ascii_strtoull(addr_tokens[0], NULL, 0);
+ int exit_code = 0;
+ if (addr_tokens[1]) {
+ exit_code = g_ascii_strtoull(addr_tokens[1], NULL, 0);
+ }
+ g_hash_table_insert(addrs_ht, GUINT_TO_POINTER(exit_addr),
+ GINT_TO_POINTER(exit_code));
+ exit_on_address = true;
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ if (!exit_on_icount && !exit_on_address) {
+ fprintf(stderr, "'icount' or 'addr' argument missing\n");
+ return -1;
+ }
+
+ /* Register translation block and exit callbacks */
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+
+ return 0;
+}
diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
index f7d7b9e..954623f 100644
--- a/docs/devel/tcg-plugins.rst
+++ b/docs/devel/tcg-plugins.rst
@@ -642,6 +642,28 @@
configuration arguments implies ``l2=on``.
(default: N = 2097152 (2MB), B = 64, A = 16)
+- contrib/plugins/stoptrigger.c
+
+The stoptrigger plugin allows to setup triggers to stop emulation.
+It can be used for research purposes to launch some code and precisely stop it
+and understand where its execution flow went.
+
+Two types of triggers can be configured: a count of instructions to stop at,
+or an address to stop at. Multiple triggers can be set at once.
+
+By default, QEMU will exit with return code 0. A custom return code can be
+configured for each trigger using ``:CODE`` syntax.
+
+For example, to stop at the 20-th instruction with return code 41, at address
+0xd4 with return code 0 or at address 0xd8 with return code 42::
+
+ $ qemu-system-aarch64 $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libstoptrigger.so,icount=20:41,addr=0xd4,addr=0xd8:42 -d plugin
+
+The plugin will log the reason of exit, for example::
+
+ 0xd4 reached, exiting
+
Plugin API
==========
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index b9ad0a0..b7be8e5 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -1614,18 +1614,21 @@
gdb_put_strbuf();
}
-static char *extended_qsupported_features;
-void gdb_extend_qsupported_features(char *qsupported_features)
-{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert the feature strings are the same on all CPUs, or is set only
- * once (1 CPU).
- */
- g_assert(extended_qsupported_features == NULL ||
- g_strcmp0(extended_qsupported_features, qsupported_features) == 0);
- extended_qsupported_features = qsupported_features;
+static char **extra_query_flags;
+
+void gdb_extend_qsupported_features(char *qflags)
+{
+ if (!extra_query_flags) {
+ extra_query_flags = g_new0(char *, 2);
+ extra_query_flags[0] = g_strdup(qflags);
+ } else if (!g_strv_contains((const gchar * const *) extra_query_flags,
+ qflags)) {
+ int len = g_strv_length(extra_query_flags);
+ extra_query_flags = g_realloc_n(extra_query_flags, len + 2,
+ sizeof(char *));
+ extra_query_flags[len] = g_strdup(qflags);
+ }
}
static void handle_query_supported(GArray *params, void *user_ctx)
@@ -1668,8 +1671,11 @@
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
- if (extended_qsupported_features) {
- g_string_append(gdbserver_state.str_buf, extended_qsupported_features);
+ if (extra_query_flags) {
+ int extras = g_strv_length(extra_query_flags);
+ for (int i = 0; i < extras; i++) {
+ g_string_append(gdbserver_state.str_buf, extra_query_flags[i]);
+ }
}
gdb_put_strbuf();
@@ -1753,39 +1759,58 @@
},
};
-/* Compares if a set of command parsers is equal to another set of parsers. */
-static bool cmp_cmds(GdbCmdParseEntry *c, GdbCmdParseEntry *d, int size)
+/**
+ * extend_table() - extend one of the command tables
+ * @table: the command table to extend (or NULL)
+ * @extensions: a list of GdbCmdParseEntry pointers
+ *
+ * The entries themselves should be pointers to static const
+ * GdbCmdParseEntry entries. If the entry is already in the table we
+ * skip adding it again.
+ *
+ * Returns (a potentially freshly allocated) GPtrArray of GdbCmdParseEntry
+ */
+static GPtrArray *extend_table(GPtrArray *table, GPtrArray *extensions)
{
- for (int i = 0; i < size; i++) {
- if (!(c[i].handler == d[i].handler &&
- g_strcmp0(c[i].cmd, d[i].cmd) == 0 &&
- c[i].cmd_startswith == d[i].cmd_startswith &&
- g_strcmp0(c[i].schema, d[i].schema) == 0)) {
+ if (!table) {
+ table = g_ptr_array_new();
+ }
- /* Sets are different. */
- return false;
+ for (int i = 0; i < extensions->len; i++) {
+ gpointer entry = g_ptr_array_index(extensions, i);
+ if (!g_ptr_array_find(table, entry, NULL)) {
+ g_ptr_array_add(table, entry);
}
}
- /* Sets are equal, i.e. contain the same command parsers. */
- return true;
+ return table;
}
-static GdbCmdParseEntry *extended_query_table;
-static int extended_query_table_size;
-void gdb_extend_query_table(GdbCmdParseEntry *table, int size)
+/**
+ * process_extended_table() - run through an extended command table
+ * @table: the command table to check
+ * @data: parameters
+ *
+ * returns true if the command was found and executed
+ */
+static bool process_extended_table(GPtrArray *table, const char *data)
{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert query table is the same on all CPUs, or is set only once
- * (1 CPU).
- */
- g_assert(extended_query_table == NULL ||
- (extended_query_table_size == size &&
- cmp_cmds(extended_query_table, table, size)));
+ for (int i = 0; i < table->len; i++) {
+ const GdbCmdParseEntry *entry = g_ptr_array_index(table, i);
+ if (process_string_cmd(data, entry, 1)) {
+ return true;
+ }
+ }
+ return false;
+}
- extended_query_table = table;
- extended_query_table_size = size;
+
+/* Ptr to GdbCmdParseEntry */
+static GPtrArray *extended_query_table;
+
+void gdb_extend_query_table(GPtrArray *new_queries)
+{
+ extended_query_table = extend_table(extended_query_table, new_queries);
}
static const GdbCmdParseEntry gdb_gen_query_table[] = {
@@ -1880,20 +1905,12 @@
#endif
};
-static GdbCmdParseEntry *extended_set_table;
-static int extended_set_table_size;
-void gdb_extend_set_table(GdbCmdParseEntry *table, int size)
-{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert set table is the same on all CPUs, or is set only once (1 CPU).
- */
- g_assert(extended_set_table == NULL ||
- (extended_set_table_size == size &&
- cmp_cmds(extended_set_table, table, size)));
+/* Ptr to GdbCmdParseEntry */
+static GPtrArray *extended_set_table;
- extended_set_table = table;
- extended_set_table_size = size;
+void gdb_extend_set_table(GPtrArray *new_set)
+{
+ extended_set_table = extend_table(extended_set_table, new_set);
}
static const GdbCmdParseEntry gdb_gen_set_table[] = {
@@ -1924,26 +1941,28 @@
static void handle_gen_query(GArray *params, void *user_ctx)
{
+ const char *data;
+
if (!params->len) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ data = gdb_get_cmd_param(params, 0)->data;
+
+ if (process_string_cmd(data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ if (process_string_cmd(data,
gdb_gen_query_table,
ARRAY_SIZE(gdb_gen_query_table))) {
return;
}
if (extended_query_table &&
- process_string_cmd(gdb_get_cmd_param(params, 0)->data,
- extended_query_table,
- extended_query_table_size)) {
+ process_extended_table(extended_query_table, data)) {
return;
}
@@ -1953,26 +1972,28 @@
static void handle_gen_set(GArray *params, void *user_ctx)
{
+ const char *data;
+
if (!params->len) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ data = gdb_get_cmd_param(params, 0)->data;
+
+ if (process_string_cmd(data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ if (process_string_cmd(data,
gdb_gen_set_table,
ARRAY_SIZE(gdb_gen_set_table))) {
return;
}
if (extended_set_table &&
- process_string_cmd(gdb_get_cmd_param(params, 0)->data,
- extended_set_table,
- extended_set_table_size)) {
+ process_extended_table(extended_set_table, data)) {
return;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index bc38cad..8a878f8 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -36,7 +36,8 @@
GlobalProperty hw_compat_9_0[] = {
{"arm-cpu", "backcompat-cntfrq", "true" },
- {"scsi-disk-base", "migrate-emulated-scsi-request", "false" },
+ { "scsi-hd", "migrate-emulated-scsi-request", "false" },
+ { "scsi-cd", "migrate-emulated-scsi-request", "false" },
{"vfio-pci", "skip-vsc-check", "false" },
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
{"sd-card", "spec_version", "2" },
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 5b1b0ca..8d25174 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -1758,6 +1758,10 @@
break;
}
+ if (ret == -ECANCELED) {
+ status = NVME_CMD_ABORT_REQ;
+ }
+
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), status);
error_setg_errno(&local_err, -ret, "aio failed");
@@ -2591,6 +2595,7 @@
done:
iocb->aiocb = NULL;
iocb->common.cb(iocb->common.opaque, iocb->ret);
+ g_free(iocb->range);
qemu_aio_unref(iocb);
}
@@ -2695,6 +2700,7 @@
BlockAIOCB common;
BlockAIOCB *aiocb;
NvmeRequest *req;
+ NvmeCtrl *n;
int ret;
void *ranges;
@@ -2713,6 +2719,8 @@
uint64_t slba;
NvmeZone *zone;
+ NvmeNamespace *sns;
+ uint32_t tcl;
} NvmeCopyAIOCB;
static void nvme_copy_cancel(BlockAIOCB *aiocb)
@@ -2759,13 +2767,19 @@
static void nvme_do_copy(NvmeCopyAIOCB *iocb);
-static void nvme_copy_source_range_parse_format0(void *ranges, int idx,
- uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag,
- uint16_t *appmask,
- uint64_t *reftag)
+static void nvme_copy_source_range_parse_format0_2(void *ranges,
+ int idx, uint64_t *slba,
+ uint32_t *nlb,
+ uint32_t *snsid,
+ uint16_t *apptag,
+ uint16_t *appmask,
+ uint64_t *reftag)
{
- NvmeCopySourceRangeFormat0 *_ranges = ranges;
+ NvmeCopySourceRangeFormat0_2 *_ranges = ranges;
+
+ if (snsid) {
+ *snsid = le32_to_cpu(_ranges[idx].sparams);
+ }
if (slba) {
*slba = le64_to_cpu(_ranges[idx].slba);
@@ -2788,13 +2802,19 @@
}
}
-static void nvme_copy_source_range_parse_format1(void *ranges, int idx,
- uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag,
- uint16_t *appmask,
- uint64_t *reftag)
+static void nvme_copy_source_range_parse_format1_3(void *ranges, int idx,
+ uint64_t *slba,
+ uint32_t *nlb,
+ uint32_t *snsid,
+ uint16_t *apptag,
+ uint16_t *appmask,
+ uint64_t *reftag)
{
- NvmeCopySourceRangeFormat1 *_ranges = ranges;
+ NvmeCopySourceRangeFormat1_3 *_ranges = ranges;
+
+ if (snsid) {
+ *snsid = le32_to_cpu(_ranges[idx].sparams);
+ }
if (slba) {
*slba = le64_to_cpu(_ranges[idx].slba);
@@ -2826,18 +2846,20 @@
static void nvme_copy_source_range_parse(void *ranges, int idx, uint8_t format,
uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag, uint16_t *appmask,
- uint64_t *reftag)
+ uint32_t *snsid, uint16_t *apptag,
+ uint16_t *appmask, uint64_t *reftag)
{
switch (format) {
case NVME_COPY_FORMAT_0:
- nvme_copy_source_range_parse_format0(ranges, idx, slba, nlb, apptag,
- appmask, reftag);
+ case NVME_COPY_FORMAT_2:
+ nvme_copy_source_range_parse_format0_2(ranges, idx, slba, nlb, snsid,
+ apptag, appmask, reftag);
break;
case NVME_COPY_FORMAT_1:
- nvme_copy_source_range_parse_format1(ranges, idx, slba, nlb, apptag,
- appmask, reftag);
+ case NVME_COPY_FORMAT_3:
+ nvme_copy_source_range_parse_format1_3(ranges, idx, slba, nlb, snsid,
+ apptag, appmask, reftag);
break;
default:
@@ -2853,10 +2875,10 @@
for (int idx = 0; idx < nr; idx++) {
uint32_t nlb;
nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
copy_len += nlb;
}
-
+ iocb->tcl = copy_len;
if (copy_len > ns->id_ns.mcl) {
return NVME_CMD_SIZE_LIMIT | NVME_DNR;
}
@@ -2868,11 +2890,11 @@
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *dns = req->ns;
uint32_t nlb;
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
if (ret < 0) {
iocb->ret = ret;
@@ -2881,8 +2903,8 @@
goto out;
}
- if (ns->params.zoned) {
- nvme_advance_zone_wp(ns, iocb->zone, nlb);
+ if (dns->params.zoned) {
+ nvme_advance_zone_wp(dns, iocb->zone, nlb);
}
iocb->idx++;
@@ -2895,25 +2917,25 @@
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *dns = req->ns;
uint32_t nlb;
size_t mlen;
uint8_t *mbounce;
- if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
+ if (ret < 0 || iocb->ret < 0 || !dns->lbaf.ms) {
goto out;
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
- mlen = nvme_m2b(ns, nlb);
- mbounce = iocb->bounce + nvme_l2b(ns, nlb);
+ mlen = nvme_m2b(dns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(dns, nlb);
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, mbounce, mlen);
- iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_moff(ns, iocb->slba),
+ iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_moff(dns, iocb->slba),
&iocb->iov, 0, nvme_copy_out_completed_cb,
iocb);
@@ -2927,12 +2949,15 @@
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns = iocb->sns;
+ NvmeNamespace *dns = req->ns;
+ NvmeCopyCmd *copy = NULL;
+ uint8_t *mbounce = NULL;
uint32_t nlb;
uint64_t slba;
uint16_t apptag, appmask;
uint64_t reftag;
- size_t len;
+ size_t len, mlen;
uint16_t status;
if (ret < 0) {
@@ -2943,43 +2968,51 @@
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, &apptag, &appmask, &reftag);
- len = nvme_l2b(ns, nlb);
+ &nlb, NULL, &apptag, &appmask, &reftag);
trace_pci_nvme_copy_out(iocb->slba, nlb);
- if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
- NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
+ len = nvme_l2b(sns, nlb);
+
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps)) {
+ copy = (NvmeCopyCmd *)&req->cmd;
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
- uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
- size_t mlen = nvme_m2b(ns, nlb);
- uint8_t *mbounce = iocb->bounce + nvme_l2b(ns, nlb);
+ mlen = nvme_m2b(sns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(sns, nlb);
- status = nvme_dif_mangle_mdata(ns, mbounce, mlen, slba);
+ status = nvme_dif_mangle_mdata(sns, mbounce, mlen, slba);
if (status) {
goto invalid;
}
- status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen, prinfor,
+ status = nvme_dif_check(sns, iocb->bounce, len, mbounce, mlen, prinfor,
slba, apptag, appmask, &reftag);
if (status) {
goto invalid;
}
+ }
+
+ if (NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ copy = (NvmeCopyCmd *)&req->cmd;
+ uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
+
+ mlen = nvme_m2b(dns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(dns, nlb);
apptag = le16_to_cpu(copy->apptag);
appmask = le16_to_cpu(copy->appmask);
if (prinfow & NVME_PRINFO_PRACT) {
- status = nvme_check_prinfo(ns, prinfow, iocb->slba, iocb->reftag);
+ status = nvme_check_prinfo(dns, prinfow, iocb->slba, iocb->reftag);
if (status) {
goto invalid;
}
- nvme_dif_pract_generate_dif(ns, iocb->bounce, len, mbounce, mlen,
+ nvme_dif_pract_generate_dif(dns, iocb->bounce, len, mbounce, mlen,
apptag, &iocb->reftag);
} else {
- status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen,
+ status = nvme_dif_check(dns, iocb->bounce, len, mbounce, mlen,
prinfow, iocb->slba, apptag, appmask,
&iocb->reftag);
if (status) {
@@ -2988,13 +3021,13 @@
}
}
- status = nvme_check_bounds(ns, iocb->slba, nlb);
+ status = nvme_check_bounds(dns, iocb->slba, nlb);
if (status) {
goto invalid;
}
- if (ns->params.zoned) {
- status = nvme_check_zone_write(ns, iocb->zone, iocb->slba, nlb);
+ if (dns->params.zoned) {
+ status = nvme_check_zone_write(dns, iocb->zone, iocb->slba, nlb);
if (status) {
goto invalid;
}
@@ -3007,7 +3040,10 @@
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
- iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_l2b(ns, iocb->slba),
+ block_acct_start(blk_get_stats(dns->blkconf.blk), &iocb->acct.write, 0,
+ BLOCK_ACCT_WRITE);
+
+ iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_l2b(dns, iocb->slba),
&iocb->iov, 0, nvme_copy_out_cb, iocb);
return;
@@ -3022,23 +3058,22 @@
static void nvme_copy_in_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
- NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns = iocb->sns;
uint64_t slba;
uint32_t nlb;
- if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
+ if (ret < 0 || iocb->ret < 0 || !sns->lbaf.ms) {
goto out;
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
qemu_iovec_reset(&iocb->iov);
- qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(ns, nlb),
- nvme_m2b(ns, nlb));
+ qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(sns, nlb),
+ nvme_m2b(sns, nlb));
- iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_moff(ns, slba),
+ iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_moff(sns, slba),
&iocb->iov, 0, nvme_copy_in_completed_cb,
iocb);
return;
@@ -3047,14 +3082,78 @@
nvme_copy_in_completed_cb(iocb, ret);
}
+static inline bool nvme_csi_supports_copy(uint8_t csi)
+{
+ return csi == NVME_CSI_NVM || csi == NVME_CSI_ZONED;
+}
+
+static inline bool nvme_copy_ns_format_match(NvmeNamespace *sns,
+ NvmeNamespace *dns)
+{
+ return sns->lbaf.ds == dns->lbaf.ds && sns->lbaf.ms == dns->lbaf.ms;
+}
+
+static bool nvme_copy_matching_ns_format(NvmeNamespace *sns, NvmeNamespace *dns,
+ bool pi_enable)
+{
+ if (!nvme_csi_supports_copy(sns->csi) ||
+ !nvme_csi_supports_copy(dns->csi)) {
+ return false;
+ }
+
+ if (!pi_enable && !nvme_copy_ns_format_match(sns, dns)) {
+ return false;
+ }
+
+ if (pi_enable && (!nvme_copy_ns_format_match(sns, dns) ||
+ sns->id_ns.dps != dns->id_ns.dps)) {
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool nvme_copy_corresp_pi_match(NvmeNamespace *sns,
+ NvmeNamespace *dns)
+{
+ return sns->lbaf.ms == 0 &&
+ ((dns->lbaf.ms == 8 && dns->pif == 0) ||
+ (dns->lbaf.ms == 16 && dns->pif == 1));
+}
+
+static bool nvme_copy_corresp_pi_format(NvmeNamespace *sns, NvmeNamespace *dns,
+ bool sns_pi_en)
+{
+ if (!nvme_csi_supports_copy(sns->csi) ||
+ !nvme_csi_supports_copy(dns->csi)) {
+ return false;
+ }
+
+ if (!sns_pi_en && !nvme_copy_corresp_pi_match(sns, dns)) {
+ return false;
+ }
+
+ if (sns_pi_en && !nvme_copy_corresp_pi_match(dns, sns)) {
+ return false;
+ }
+
+ return true;
+}
+
static void nvme_do_copy(NvmeCopyAIOCB *iocb)
{
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns;
+ NvmeNamespace *dns = req->ns;
+ NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
+ uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
+ uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
uint64_t slba;
uint32_t nlb;
size_t len;
uint16_t status;
+ uint32_t dnsid = le32_to_cpu(req->cmd.nsid);
+ uint32_t snsid = dnsid;
if (iocb->ret < 0) {
goto done;
@@ -3064,40 +3163,124 @@
goto done;
}
- nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, NULL, NULL, NULL);
- len = nvme_l2b(ns, nlb);
+ if (iocb->format == 2 || iocb->format == 3) {
+ nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
+ &slba, &nlb, &snsid, NULL, NULL, NULL);
+ if (snsid != dnsid) {
+ if (snsid == NVME_NSID_BROADCAST ||
+ !nvme_nsid_valid(iocb->n, snsid)) {
+ status = NVME_INVALID_NSID | NVME_DNR;
+ goto invalid;
+ }
+ iocb->sns = nvme_ns(iocb->n, snsid);
+ if (unlikely(!iocb->sns)) {
+ status = NVME_INVALID_FIELD | NVME_DNR;
+ goto invalid;
+ }
+ } else {
+ if (((slba + nlb) > iocb->slba) &&
+ ((slba + nlb) < (iocb->slba + iocb->tcl))) {
+ status = NVME_CMD_OVERLAP_IO_RANGE | NVME_DNR;
+ goto invalid;
+ }
+ }
+ } else {
+ nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
+ &slba, &nlb, NULL, NULL, NULL, NULL);
+ }
+
+ sns = iocb->sns;
+ if ((snsid == dnsid) && NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ ((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
+ status = NVME_INVALID_FIELD | NVME_DNR;
+ goto invalid;
+ } else if (snsid != dnsid) {
+ if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ !NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!nvme_copy_matching_ns_format(sns, dns, false)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if ((prinfor & NVME_PRINFO_PRACT) !=
+ (prinfow & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_matching_ns_format(sns, dns, true)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+
+ if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!(prinfow & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_corresp_pi_format(sns, dns, false)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ !NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!(prinfor & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_corresp_pi_format(sns, dns, true)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+ }
+ len = nvme_l2b(sns, nlb);
trace_pci_nvme_copy_source_range(slba, nlb);
- if (nlb > le16_to_cpu(ns->id_ns.mssrl)) {
+ if (nlb > le16_to_cpu(sns->id_ns.mssrl)) {
status = NVME_CMD_SIZE_LIMIT | NVME_DNR;
goto invalid;
}
- status = nvme_check_bounds(ns, slba, nlb);
+ status = nvme_check_bounds(sns, slba, nlb);
if (status) {
goto invalid;
}
- if (NVME_ERR_REC_DULBE(ns->features.err_rec)) {
- status = nvme_check_dulbe(ns, slba, nlb);
+ if (NVME_ERR_REC_DULBE(sns->features.err_rec)) {
+ status = nvme_check_dulbe(sns, slba, nlb);
if (status) {
goto invalid;
}
}
- if (ns->params.zoned) {
- status = nvme_check_zone_read(ns, slba, nlb);
+ if (sns->params.zoned) {
+ status = nvme_check_zone_read(sns, slba, nlb);
if (status) {
goto invalid;
}
}
+ g_free(iocb->bounce);
+ iocb->bounce = g_malloc_n(le16_to_cpu(sns->id_ns.mssrl),
+ sns->lbasz + sns->lbaf.ms);
+
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
- iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_l2b(ns, slba),
+ block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,
+ BLOCK_ACCT_READ);
+
+ iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_l2b(sns, slba),
&iocb->iov, 0, nvme_copy_in_cb, iocb);
return;
@@ -3116,9 +3299,7 @@
nvme_misc_cb, req);
uint16_t nr = copy->nr + 1;
uint8_t format = copy->control[0] & 0xf;
- uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
- uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
- size_t len = sizeof(NvmeCopySourceRangeFormat0);
+ size_t len = sizeof(NvmeCopySourceRangeFormat0_2);
uint16_t status;
@@ -3127,13 +3308,9 @@
iocb->ranges = NULL;
iocb->zone = NULL;
- if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) &&
- ((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
- status = NVME_INVALID_FIELD | NVME_DNR;
- goto invalid;
- }
-
- if (!(n->id_ctrl.ocfs & (1 << format))) {
+ if (!(n->id_ctrl.ocfs & (1 << format)) ||
+ ((format == 2 || format == 3) &&
+ !(n->features.hbs.cdfe & (1 << format)))) {
trace_pci_nvme_err_copy_invalid_format(format);
status = NVME_INVALID_FIELD | NVME_DNR;
goto invalid;
@@ -3144,14 +3321,14 @@
goto invalid;
}
- if ((ns->pif == 0x0 && format != 0x0) ||
- (ns->pif != 0x0 && format != 0x1)) {
+ if ((ns->pif == 0x0 && (format != 0x0 && format != 0x2)) ||
+ (ns->pif != 0x0 && (format != 0x1 && format != 0x3))) {
status = NVME_INVALID_FORMAT | NVME_DNR;
goto invalid;
}
if (ns->pif) {
- len = sizeof(NvmeCopySourceRangeFormat1);
+ len = sizeof(NvmeCopySourceRangeFormat1_3);
}
iocb->format = format;
@@ -3187,17 +3364,13 @@
iocb->idx = 0;
iocb->reftag = le32_to_cpu(copy->reftag);
iocb->reftag |= (uint64_t)le32_to_cpu(copy->cdw3) << 32;
- iocb->bounce = g_malloc_n(le16_to_cpu(ns->id_ns.mssrl),
- ns->lbasz + ns->lbaf.ms);
qemu_iovec_init(&iocb->iov, 1);
- block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.read, 0,
- BLOCK_ACCT_READ);
- block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.write, 0,
- BLOCK_ACCT_WRITE);
-
req->aiocb = &iocb->common;
+ iocb->sns = req->ns;
+ iocb->n = n;
+ iocb->bounce = NULL;
nvme_do_copy(iocb);
return NVME_NO_COMPLETE;
@@ -4167,7 +4340,7 @@
static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req)
{
- NvmeCmd *cmd = (NvmeCmd *)&req->cmd;
+ NvmeCmd *cmd = &req->cmd;
NvmeNamespace *ns = req->ns;
/* cdw12 is zero-based number of dwords to return. Convert to bytes */
uint32_t data_size = (le32_to_cpu(cmd->cdw12) + 1) << 2;
@@ -4406,10 +4579,6 @@
trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
- if (!nvme_nsid_valid(n, nsid)) {
- return NVME_INVALID_NSID | NVME_DNR;
- }
-
/*
* In the base NVM command set, Flush may apply to all namespaces
* (indicated by NSID being set to FFFFFFFFh). But if that feature is used
@@ -4429,10 +4598,15 @@
* device only supports namespace types that includes the NVM Flush command
* (NVM and Zoned), so always do an NVM Flush.
*/
+
if (req->cmd.opcode == NVME_CMD_FLUSH) {
return nvme_flush(n, req);
}
+ if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
ns = nvme_ns(n, nsid);
if (unlikely(!ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
@@ -5780,12 +5954,40 @@
static uint16_t nvme_abort(NvmeCtrl *n, NvmeRequest *req)
{
uint16_t sqid = le32_to_cpu(req->cmd.cdw10) & 0xffff;
+ uint16_t cid = (le32_to_cpu(req->cmd.cdw10) >> 16) & 0xffff;
+ NvmeSQueue *sq = n->sq[sqid];
+ NvmeRequest *r, *next;
+ int i;
req->cqe.result = 1;
if (nvme_check_sqid(n, sqid)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (sqid == 0) {
+ for (i = 0; i < n->outstanding_aers; i++) {
+ NvmeRequest *re = n->aer_reqs[i];
+ if (re->cqe.cid == cid) {
+ memmove(n->aer_reqs + i, n->aer_reqs + i + 1,
+ (n->outstanding_aers - i - 1) * sizeof(NvmeRequest *));
+ n->outstanding_aers--;
+ re->status = NVME_CMD_ABORT_REQ;
+ req->cqe.result = 0;
+ nvme_enqueue_req_completion(&n->admin_cq, re);
+ return NVME_SUCCESS;
+ }
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(r, &sq->out_req_list, entry, next) {
+ if (r->cqe.cid == cid) {
+ if (r->aiocb) {
+ blk_aio_cancel_async(r->aiocb);
+ }
+ break;
+ }
+ }
+
return NVME_SUCCESS;
}
@@ -8287,7 +8489,8 @@
id->nn = cpu_to_le32(NVME_MAX_NAMESPACES);
id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
NVME_ONCS_FEATURES | NVME_ONCS_DSM |
- NVME_ONCS_COMPARE | NVME_ONCS_COPY);
+ NVME_ONCS_COMPARE | NVME_ONCS_COPY |
+ NVME_ONCS_NVMCSA | NVME_ONCS_NVMAFC);
/*
* NOTE: If this device ever supports a command set that does NOT use 0x0
@@ -8298,7 +8501,8 @@
*/
id->vwc = NVME_VWC_NSID_BROADCAST_SUPPORT | NVME_VWC_PRESENT;
- id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1);
+ id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1 |
+ NVME_OCFS_COPY_FORMAT_2 | NVME_OCFS_COPY_FORMAT_3);
id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN);
nvme_init_subnqn(n);
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 7c77d38..5298bc4 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -799,6 +799,8 @@
enum {
NVME_COPY_FORMAT_0 = 0x0,
NVME_COPY_FORMAT_1 = 0x1,
+ NVME_COPY_FORMAT_2 = 0x2,
+ NVME_COPY_FORMAT_3 = 0x3,
};
typedef struct QEMU_PACKED NvmeCopyCmd {
@@ -820,25 +822,30 @@
uint16_t appmask;
} NvmeCopyCmd;
-typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0 {
- uint8_t rsvd0[8];
+typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0_2 {
+ uint32_t sparams;
+ uint8_t rsvd4[4];
uint64_t slba;
uint16_t nlb;
- uint8_t rsvd18[6];
+ uint8_t rsvd18[4];
+ uint16_t sopt;
uint32_t reftag;
uint16_t apptag;
uint16_t appmask;
-} NvmeCopySourceRangeFormat0;
+} NvmeCopySourceRangeFormat0_2;
-typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1 {
- uint8_t rsvd0[8];
+typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1_3 {
+ uint32_t sparams;
+ uint8_t rsvd4[4];
uint64_t slba;
uint16_t nlb;
- uint8_t rsvd18[8];
+ uint8_t rsvd18[4];
+ uint16_t sopt;
+ uint8_t rsvd24[2];
uint8_t sr[10];
uint16_t apptag;
uint16_t appmask;
-} NvmeCopySourceRangeFormat1;
+} NvmeCopySourceRangeFormat1_3;
enum NvmeAsyncEventRequest {
NVME_AER_TYPE_ERROR = 0,
@@ -937,6 +944,8 @@
NVME_INVALID_PROT_INFO = 0x0181,
NVME_WRITE_TO_RO = 0x0182,
NVME_CMD_SIZE_LIMIT = 0x0183,
+ NVME_CMD_INCOMP_NS_OR_FMT = 0x0185,
+ NVME_CMD_OVERLAP_IO_RANGE = 0x0187,
NVME_INVALID_ZONE_OP = 0x01b6,
NVME_NOZRWA = 0x01b7,
NVME_ZONE_BOUNDARY_ERROR = 0x01b8,
@@ -1195,11 +1204,15 @@
NVME_ONCS_TIMESTAMP = 1 << 6,
NVME_ONCS_VERIFY = 1 << 7,
NVME_ONCS_COPY = 1 << 8,
+ NVME_ONCS_NVMCSA = 1 << 9,
+ NVME_ONCS_NVMAFC = 1 << 10,
};
enum NvmeIdCtrlOcfs {
NVME_OCFS_COPY_FORMAT_0 = 1 << NVME_COPY_FORMAT_0,
NVME_OCFS_COPY_FORMAT_1 = 1 << NVME_COPY_FORMAT_1,
+ NVME_OCFS_COPY_FORMAT_2 = 1 << NVME_COPY_FORMAT_2,
+ NVME_OCFS_COPY_FORMAT_3 = 1 << NVME_COPY_FORMAT_3,
};
enum NvmeIdctrlVwc {
@@ -1333,7 +1346,9 @@
uint8_t acre;
uint8_t etdas;
uint8_t lbafee;
- uint8_t rsvd3[509];
+ uint8_t rsvd3;
+ uint16_t cdfe;
+ uint8_t rsvd6[506];
} NvmeHostBehaviorSupport;
typedef struct QEMU_PACKED NvmeLBAF {
@@ -1833,8 +1848,8 @@
QEMU_BUILD_BUG_ON(sizeof(NvmeZonedResult) != 8);
QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0) != 32);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1) != 40);
+ QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0_2) != 32);
+ QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1_3) != 40);
QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
diff --git a/include/gdbstub/commands.h b/include/gdbstub/commands.h
index f3058f9..40f0514 100644
--- a/include/gdbstub/commands.h
+++ b/include/gdbstub/commands.h
@@ -74,23 +74,28 @@
/**
* gdb_extend_query_table() - Extend query table.
- * @table: The table with the additional query packet handlers.
- * @size: The number of handlers to be added.
+ * @table: GPtrArray of GdbCmdParseEntry entries.
+ *
+ * The caller should free @table afterwards
*/
-void gdb_extend_query_table(GdbCmdParseEntry *table, int size);
+void gdb_extend_query_table(GPtrArray *table);
/**
* gdb_extend_set_table() - Extend set table.
- * @table: The table with the additional set packet handlers.
- * @size: The number of handlers to be added.
+ * @table: GPtrArray of GdbCmdParseEntry entries.
+ *
+ * The caller should free @table afterwards
*/
-void gdb_extend_set_table(GdbCmdParseEntry *table, int size);
+void gdb_extend_set_table(GPtrArray *table);
/**
* gdb_extend_qsupported_features() - Extend the qSupported features string.
* @qsupported_features: The additional qSupported feature(s) string. The string
* should start with a semicolon and, if there are more than one feature, the
- * features should be separate by a semiocolon.
+ * features should be separate by a semicolon.
+ *
+ * The caller should free @qsupported_features afterwards if
+ * dynamically allocated.
*/
void gdb_extend_qsupported_features(char *qsupported_features);
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 3a5ec22..b5937c6 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -9,6 +9,8 @@
#ifndef SEMIHOSTING_SYSCALLS_H
#define SEMIHOSTING_SYSCALLS_H
+#include "gdbstub/syscalls.h"
+
/*
* Argument loading from the guest is performed by the caller;
* results are returned via the 'complete' callback.
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index 7edb876..a552e2b 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -21,8 +21,9 @@
# @props: a dictionary of QOM properties to be applied
#
# @deprecated-props: a list of properties that are flagged as deprecated
-# by the CPU vendor. These props are a subset of the full model's
-# definition list of properties. (since 9.1)
+# by the CPU vendor. These properties are either a subset of the
+# properties enabled on the CPU model, or a set of properties
+# deprecated across all models for the architecture.
#
# Since: 2.8
##
diff --git a/semihosting/Kconfig b/semihosting/Kconfig
index eaf3a20..fbe6ac8 100644
--- a/semihosting/Kconfig
+++ b/semihosting/Kconfig
@@ -1,6 +1,7 @@
config SEMIHOSTING
bool
+ depends on TCG
config ARM_COMPATIBLE_SEMIHOSTING
bool
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index c3a9b5e..554b873 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -477,11 +477,9 @@
void arm_cpu_register_gdb_commands(ARMCPU *cpu)
{
- GArray *query_table =
- g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
- GArray *set_table =
- g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
- GString *qsupported_features = g_string_new(NULL);
+ g_autoptr(GPtrArray) query_table = g_ptr_array_new();
+ g_autoptr(GPtrArray) set_table = g_ptr_array_new();
+ g_autoptr(GString) qsupported_features = g_string_new(NULL);
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
#ifdef TARGET_AARCH64
@@ -492,16 +490,12 @@
/* Set arch-specific handlers for 'q' commands. */
if (query_table->len) {
- gdb_extend_query_table(&g_array_index(query_table,
- GdbCmdParseEntry, 0),
- query_table->len);
+ gdb_extend_query_table(query_table);
}
/* Set arch-specific handlers for 'Q' commands. */
if (set_table->len) {
- gdb_extend_set_table(&g_array_index(set_table,
- GdbCmdParseEntry, 0),
- set_table->len);
+ gdb_extend_set_table(set_table);
}
/* Set arch-specific qSupported feature. */
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 2e2bc27..c8cef8c 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -564,7 +564,7 @@
NUM_CMDS
};
-static GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
+static const GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
[qMemTags] = {
.handler = handle_q_memtag,
.cmd_startswith = true,
@@ -590,17 +590,16 @@
#endif /* CONFIG_USER_ONLY */
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *qsupported,
- GArray *qtable, GArray *stable)
+ GPtrArray *qtable, GPtrArray *stable)
{
#ifdef CONFIG_USER_ONLY
/* MTE */
if (cpu_isar_feature(aa64_mte, cpu)) {
g_string_append(qsupported, ";memory-tagging+");
- g_array_append_val(qtable, cmd_handler_table[qMemTags]);
- g_array_append_val(qtable, cmd_handler_table[qIsAddressTagged]);
-
- g_array_append_val(stable, cmd_handler_table[QMemTags]);
+ g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qMemTags]);
+ g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qIsAddressTagged]);
+ g_ptr_array_add(stable, (gpointer) &cmd_handler_table[QMemTags]);
}
#endif
}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index da22d04..757b1fa 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -359,8 +359,8 @@
void arm_translate_init(void);
void arm_cpu_register_gdb_commands(ARMCPU *cpu);
-void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *, GArray *,
- GArray *);
+void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *,
+ GPtrArray *, GPtrArray *);
void arm_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
diff --git a/target/m68k/Kconfig b/target/m68k/Kconfig
index 9eae714..23aae24 100644
--- a/target/m68k/Kconfig
+++ b/target/m68k/Kconfig
@@ -1,3 +1,3 @@
config M68K
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
diff --git a/target/m68k/meson.build b/target/m68k/meson.build
index 8d3f9ce..4d213da 100644
--- a/target/m68k/meson.build
+++ b/target/m68k/meson.build
@@ -11,9 +11,12 @@
m68k_system_ss = ss.source_set()
m68k_system_ss.add(files(
- 'm68k-semi.c',
'monitor.c'
))
+m68k_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
+ if_true: files('m68k-semi.c'),
+ if_false: files('semihosting-stub.c')
+)
target_arch += {'m68k': m68k_ss}
target_system_arch += {'m68k': m68k_system_ss}
diff --git a/target/m68k/semihosting-stub.c b/target/m68k/semihosting-stub.c
new file mode 100644
index 0000000..d6a5965
--- /dev/null
+++ b/target/m68k/semihosting-stub.c
@@ -0,0 +1,15 @@
+/*
+ * m68k/ColdFire semihosting stub
+ *
+ * SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org>
+ * SPDX-FileCopyrightText: 2024 Linaro Ltd.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+
+void do_m68k_semihosting(CPUM68KState *env, int nr)
+{
+ g_assert_not_reached();
+}
diff --git a/target/mips/Kconfig b/target/mips/Kconfig
index eb19c94..876048b 100644
--- a/target/mips/Kconfig
+++ b/target/mips/Kconfig
@@ -1,6 +1,6 @@
config MIPS
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
config MIPS64
bool
diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build
index ec665a4..911341a 100644
--- a/target/mips/tcg/sysemu/meson.build
+++ b/target/mips/tcg/sysemu/meson.build
@@ -1,10 +1,12 @@
mips_system_ss.add(files(
'cp0_helper.c',
- 'mips-semi.c',
'special_helper.c',
'tlb_helper.c',
))
-
+mips_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
+ if_true: files('mips-semi.c'),
+ if_false: files('semihosting-stub.c')
+)
mips_system_ss.add(when: 'TARGET_MIPS64', if_true: files(
'lcsr_helper.c',
))
diff --git a/target/mips/tcg/sysemu/semihosting-stub.c b/target/mips/tcg/sysemu/semihosting-stub.c
new file mode 100644
index 0000000..7ae27d7
--- /dev/null
+++ b/target/mips/tcg/sysemu/semihosting-stub.c
@@ -0,0 +1,15 @@
+/*
+ * MIPS semihosting stub
+ *
+ * SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org>
+ * SPDX-FileCopyrightText: 2024 Linaro Ltd.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "internal.h"
+
+void mips_semihosting(CPUMIPSState *env)
+{
+ g_assert_not_reached();
+}
diff --git a/target/riscv/Kconfig b/target/riscv/Kconfig
index 5f30df2..c332616 100644
--- a/target/riscv/Kconfig
+++ b/target/riscv/Kconfig
@@ -1,9 +1,9 @@
config RISCV32
bool
- select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
+ imply ARM_COMPATIBLE_SEMIHOSTING if TCG
select DEVICE_TREE # needed by boot.c
config RISCV64
bool
- select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
+ imply ARM_COMPATIBLE_SEMIHOSTING if TCG
select DEVICE_TREE # needed by boot.c
diff --git a/target/s390x/cpu_models_sysemu.c b/target/s390x/cpu_models_sysemu.c
index 977fbc6..94dd798 100644
--- a/target/s390x/cpu_models_sysemu.c
+++ b/target/s390x/cpu_models_sysemu.c
@@ -174,11 +174,15 @@
bool delta_changes)
{
QDict *qdict = qdict_new();
- S390FeatBitmap bitmap;
+ S390FeatBitmap bitmap, deprecated;
/* always fallback to the static base model */
info->name = g_strdup_printf("%s-base", model->def->name);
+ /* features flagged as deprecated */
+ bitmap_zero(deprecated, S390_FEAT_MAX);
+ s390_get_deprecated_features(deprecated);
+
if (delta_changes) {
/* features deleted from the base feature set */
bitmap_andnot(bitmap, model->def->base_feat, model->features,
@@ -193,6 +197,9 @@
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
}
+
+ /* deprecated features that are a subset of the model's enabled features */
+ bitmap_and(deprecated, deprecated, model->features, S390_FEAT_MAX);
} else {
/* expand all features */
s390_feat_bitmap_to_ascii(model->features, qdict,
@@ -207,12 +214,7 @@
info->props = QOBJECT(qdict);
}
- /* features flagged as deprecated */
- bitmap_zero(bitmap, S390_FEAT_MAX);
- s390_get_deprecated_features(bitmap);
-
- bitmap_and(bitmap, bitmap, model->def->full_feat, S390_FEAT_MAX);
- s390_feat_bitmap_to_ascii(bitmap, &info->deprecated_props, list_add_feat);
+ s390_feat_bitmap_to_ascii(deprecated, &info->deprecated_props, list_add_feat);
info->has_deprecated_props = !!info->deprecated_props;
}
diff --git a/target/xtensa/Kconfig b/target/xtensa/Kconfig
index 5e46049..e8c2598 100644
--- a/target/xtensa/Kconfig
+++ b/target/xtensa/Kconfig
@@ -1,3 +1,3 @@
config XTENSA
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
diff --git a/tests/Makefile.include b/tests/Makefile.include
index d39d5dd..6618bfe 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -97,7 +97,7 @@
# Controls the output generated by Avocado when running tests.
# Any number of command separated loggers are accepted. For more
# information please refer to "avocado --help".
-AVOCADO_SHOW=app
+AVOCADO_SHOW?=app
ifndef AVOCADO_TAGS
AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \
$(filter %-softmmu,$(TARGETS)))
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 304c428..a3da2a9 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -10,7 +10,6 @@
import logging
import os
-import shutil
import subprocess
import sys
import tempfile
@@ -18,7 +17,7 @@
import uuid
import avocado
-from avocado.utils import cloudinit, datadrainer, process, ssh, vmimage
+from avocado.utils import ssh
from avocado.utils.path import find_command
from qemu.machine import QEMUMachine
@@ -32,14 +31,6 @@
#: and build tree, it will not be accurate.
BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
-if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
- # The link to the avocado tests dir in the source code directory
- lnk = os.path.dirname(os.path.dirname(__file__))
- #: The QEMU root source directory
- SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
-else:
- SOURCE_DIR = BUILD_DIR
-
def has_cmd(name, args=None):
"""
@@ -451,231 +442,3 @@
break
else:
self.fail('"%s" output does not contain "%s"' % (cmd, exp))
-
-class LinuxDistro:
- """Represents a Linux distribution
-
- Holds information of known distros.
- """
- #: A collection of known distros and their respective image checksum
- KNOWN_DISTROS = {
- 'fedora': {
- '31': {
- 'x86_64':
- {'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
- '8a309c2d46215d8fc026954f3c5c27a0'),
- 'pxeboot_url': ('https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/x86_64/os/images/pxeboot/'),
- 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
- '08a96687f73c ro no_timer_check '
- 'net.ifnames=0 console=tty1 '
- 'console=ttyS0,115200n8'),
- },
- 'aarch64':
- {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
- 'd2af0ad0329383d5639c997fdf16fe49'),
- 'pxeboot_url': 'https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/aarch64/os/images/pxeboot/',
- 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
- '355e8475b0a7 ro earlyprintk=pl011,0x9000000'
- ' ignore_loglevel no_timer_check'
- ' printk.time=1 rd_NO_PLYMOUTH'
- ' console=ttyAMA0'),
- },
- 'ppc64':
- {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
- '3f991c506f2cc390dc4efa2026ad2f58')},
- 's390x':
- {'checksum': ('4caaab5a434fd4d1079149a072fdc789'
- '1e354f834d355069ca982fdcaf5a122d')},
- },
- '32': {
- 'aarch64':
- {'checksum': ('b367755c664a2d7a26955bbfff985855'
- 'adfa2ca15e908baf15b4b176d68d3967'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/32/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
- '14d95c0e90c5 ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'),
- },
- },
- '33': {
- 'aarch64':
- {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
- 'a81f386a17f969c1d1c7c87031008a6b'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/33/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
- '1126a0208f8a ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'
- ' console=tty0'),
- },
- },
- }
- }
-
- def __init__(self, name, version, arch):
- self.name = name
- self.version = version
- self.arch = arch
- try:
- info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
- except AttributeError:
- # Unknown distro
- info = None
- self._info = info or {}
-
- @property
- def checksum(self):
- """Gets the cloud-image file checksum"""
- return self._info.get('checksum', None)
-
- @checksum.setter
- def checksum(self, value):
- self._info['checksum'] = value
-
- @property
- def pxeboot_url(self):
- """Gets the repository url where pxeboot files can be found"""
- return self._info.get('pxeboot_url', None)
-
- @property
- def default_kernel_params(self):
- """Gets the default kernel parameters"""
- return self._info.get('kernel_params', None)
-
-
-class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
- """Facilitates having a cloud-image Linux based available.
-
- For tests that intend to interact with guests, this is a better choice
- to start with than the more vanilla `QemuSystemTest` class.
- """
-
- distro = None
- username = 'root'
- password = 'password'
- smp = '2'
- memory = '1024'
-
- def _set_distro(self):
- distro_name = self.params.get(
- 'distro',
- default=self._get_unique_tag_val('distro'))
- if not distro_name:
- distro_name = 'fedora'
-
- distro_version = self.params.get(
- 'distro_version',
- default=self._get_unique_tag_val('distro_version'))
- if not distro_version:
- distro_version = '31'
-
- self.distro = LinuxDistro(distro_name, distro_version, self.arch)
-
- # The distro checksum behaves differently than distro name and
- # version. First, it does not respect a tag with the same
- # name, given that it's not expected to be used for filtering
- # (distro name versions are the natural choice). Second, the
- # order of precedence is: parameter, attribute and then value
- # from KNOWN_DISTROS.
- distro_checksum = self.params.get('distro_checksum',
- default=None)
- if distro_checksum:
- self.distro.checksum = distro_checksum
-
- def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
- super().setUp()
- self.require_netdev('user')
- self._set_distro()
- self.vm.add_args('-smp', self.smp)
- self.vm.add_args('-m', self.memory)
- # The following network device allows for SSH connections
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', '%s,netdev=vnet' % network_device_type)
- self.set_up_boot()
- if ssh_pubkey is None:
- ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
- self.set_up_cloudinit(ssh_pubkey)
-
- def set_up_existing_ssh_keys(self):
- ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
- source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
- ssh_dir = os.path.join(self.workdir, '.ssh')
- os.mkdir(ssh_dir, mode=0o700)
- ssh_private_key = os.path.join(ssh_dir,
- os.path.basename(source_private_key))
- shutil.copyfile(source_private_key, ssh_private_key)
- os.chmod(ssh_private_key, 0o600)
- return (ssh_public_key, ssh_private_key)
-
- def download_boot(self):
- # Set the qemu-img binary.
- # If none is available, the test will cancel.
- vmimage.QEMU_IMG = super().get_qemu_img()
-
- self.log.info('Downloading/preparing boot image')
- # Fedora 31 only provides ppc64le images
- image_arch = self.arch
- if self.distro.name == 'fedora':
- if image_arch == 'ppc64':
- image_arch = 'ppc64le'
-
- try:
- boot = vmimage.get(
- self.distro.name, arch=image_arch, version=self.distro.version,
- checksum=self.distro.checksum,
- algorithm='sha256',
- cache_dir=self.cache_dirs[0],
- snapshot_dir=self.workdir)
- except:
- self.cancel('Failed to download/prepare boot image')
- return boot.path
-
- def prepare_cloudinit(self, ssh_pubkey=None):
- self.log.info('Preparing cloudinit image')
- try:
- cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
- pubkey_content = None
- if ssh_pubkey:
- with open(ssh_pubkey) as pubkey:
- pubkey_content = pubkey.read()
- cloudinit.iso(cloudinit_iso, self.name,
- username=self.username,
- password=self.password,
- # QEMU's hard coded usermode router address
- phone_home_host='10.0.2.2',
- phone_home_port=self.phone_server.server_port,
- authorized_key=pubkey_content)
- except Exception:
- self.cancel('Failed to prepare the cloudinit image')
- return cloudinit_iso
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-drive', 'file=%s' % path)
-
- def set_up_cloudinit(self, ssh_pubkey=None):
- self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
- self.name)
- cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
- self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
-
- def launch_and_wait(self, set_up_ssh_connection=True):
- self.vm.set_console()
- self.vm.launch()
- console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
- logger=self.log.getChild('console'))
- console_drainer.start()
- self.log.info('VM launched, waiting for boot confirmation from guest')
- while not self.phone_server.instance_phoned_back:
- self.phone_server.handle_request()
-
- if set_up_ssh_connection:
- self.log.info('Setting up the SSH connection')
- self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/avocado/avocado_qemu/linuxtest.py b/tests/avocado/avocado_qemu/linuxtest.py
new file mode 100644
index 0000000..e1dc838
--- /dev/null
+++ b/tests/avocado/avocado_qemu/linuxtest.py
@@ -0,0 +1,253 @@
+# Test class and utilities for functional Linux-based tests
+#
+# Copyright (c) 2018 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+import shutil
+
+from avocado.utils import cloudinit, datadrainer, process, vmimage
+
+from . import LinuxSSHMixIn
+from . import QemuSystemTest
+
+if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
+ # The link to the avocado tests dir in the source code directory
+ lnk = os.path.dirname(os.path.dirname(__file__))
+ #: The QEMU root source directory
+ SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
+else:
+ SOURCE_DIR = BUILD_DIR
+
+class LinuxDistro:
+ """Represents a Linux distribution
+
+ Holds information of known distros.
+ """
+ #: A collection of known distros and their respective image checksum
+ KNOWN_DISTROS = {
+ 'fedora': {
+ '31': {
+ 'x86_64':
+ {'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
+ '8a309c2d46215d8fc026954f3c5c27a0'),
+ 'pxeboot_url': ('https://archives.fedoraproject.org/'
+ 'pub/archive/fedora/linux/releases/31/'
+ 'Everything/x86_64/os/images/pxeboot/'),
+ 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
+ '08a96687f73c ro no_timer_check '
+ 'net.ifnames=0 console=tty1 '
+ 'console=ttyS0,115200n8'),
+ },
+ 'aarch64':
+ {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
+ 'd2af0ad0329383d5639c997fdf16fe49'),
+ 'pxeboot_url': 'https://archives.fedoraproject.org/'
+ 'pub/archive/fedora/linux/releases/31/'
+ 'Everything/aarch64/os/images/pxeboot/',
+ 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
+ '355e8475b0a7 ro earlyprintk=pl011,0x9000000'
+ ' ignore_loglevel no_timer_check'
+ ' printk.time=1 rd_NO_PLYMOUTH'
+ ' console=ttyAMA0'),
+ },
+ 'ppc64':
+ {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
+ '3f991c506f2cc390dc4efa2026ad2f58')},
+ 's390x':
+ {'checksum': ('4caaab5a434fd4d1079149a072fdc789'
+ '1e354f834d355069ca982fdcaf5a122d')},
+ },
+ '32': {
+ 'aarch64':
+ {'checksum': ('b367755c664a2d7a26955bbfff985855'
+ 'adfa2ca15e908baf15b4b176d68d3967'),
+ 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
+ 'releases/32/Server/aarch64/os/images/'
+ 'pxeboot/'),
+ 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
+ '14d95c0e90c5 ro no_timer_check net.ifnames=0'
+ ' console=tty1 console=ttyS0,115200n8'),
+ },
+ },
+ '33': {
+ 'aarch64':
+ {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
+ 'a81f386a17f969c1d1c7c87031008a6b'),
+ 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
+ 'releases/33/Server/aarch64/os/images/'
+ 'pxeboot/'),
+ 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
+ '1126a0208f8a ro no_timer_check net.ifnames=0'
+ ' console=tty1 console=ttyS0,115200n8'
+ ' console=tty0'),
+ },
+ },
+ }
+ }
+
+ def __init__(self, name, version, arch):
+ self.name = name
+ self.version = version
+ self.arch = arch
+ try:
+ info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
+ except AttributeError:
+ # Unknown distro
+ info = None
+ self._info = info or {}
+
+ @property
+ def checksum(self):
+ """Gets the cloud-image file checksum"""
+ return self._info.get('checksum', None)
+
+ @checksum.setter
+ def checksum(self, value):
+ self._info['checksum'] = value
+
+ @property
+ def pxeboot_url(self):
+ """Gets the repository url where pxeboot files can be found"""
+ return self._info.get('pxeboot_url', None)
+
+ @property
+ def default_kernel_params(self):
+ """Gets the default kernel parameters"""
+ return self._info.get('kernel_params', None)
+
+
+class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
+ """Facilitates having a cloud-image Linux based available.
+
+ For tests that intend to interact with guests, this is a better choice
+ to start with than the more vanilla `QemuSystemTest` class.
+ """
+
+ distro = None
+ username = 'root'
+ password = 'password'
+ smp = '2'
+ memory = '1024'
+
+ def _set_distro(self):
+ distro_name = self.params.get(
+ 'distro',
+ default=self._get_unique_tag_val('distro'))
+ if not distro_name:
+ distro_name = 'fedora'
+
+ distro_version = self.params.get(
+ 'distro_version',
+ default=self._get_unique_tag_val('distro_version'))
+ if not distro_version:
+ distro_version = '31'
+
+ self.distro = LinuxDistro(distro_name, distro_version, self.arch)
+
+ # The distro checksum behaves differently than distro name and
+ # version. First, it does not respect a tag with the same
+ # name, given that it's not expected to be used for filtering
+ # (distro name versions are the natural choice). Second, the
+ # order of precedence is: parameter, attribute and then value
+ # from KNOWN_DISTROS.
+ distro_checksum = self.params.get('distro_checksum',
+ default=None)
+ if distro_checksum:
+ self.distro.checksum = distro_checksum
+
+ def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
+ super().setUp()
+ self.require_netdev('user')
+ self._set_distro()
+ self.vm.add_args('-smp', self.smp)
+ self.vm.add_args('-m', self.memory)
+ # The following network device allows for SSH connections
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', '%s,netdev=vnet' % network_device_type)
+ self.set_up_boot()
+ if ssh_pubkey is None:
+ ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
+ self.set_up_cloudinit(ssh_pubkey)
+
+ def set_up_existing_ssh_keys(self):
+ ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
+ source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
+ ssh_dir = os.path.join(self.workdir, '.ssh')
+ os.mkdir(ssh_dir, mode=0o700)
+ ssh_private_key = os.path.join(ssh_dir,
+ os.path.basename(source_private_key))
+ shutil.copyfile(source_private_key, ssh_private_key)
+ os.chmod(ssh_private_key, 0o600)
+ return (ssh_public_key, ssh_private_key)
+
+ def download_boot(self):
+ # Set the qemu-img binary.
+ # If none is available, the test will cancel.
+ vmimage.QEMU_IMG = super().get_qemu_img()
+
+ self.log.info('Downloading/preparing boot image')
+ # Fedora 31 only provides ppc64le images
+ image_arch = self.arch
+ if self.distro.name == 'fedora':
+ if image_arch == 'ppc64':
+ image_arch = 'ppc64le'
+
+ try:
+ boot = vmimage.get(
+ self.distro.name, arch=image_arch, version=self.distro.version,
+ checksum=self.distro.checksum,
+ algorithm='sha256',
+ cache_dir=self.cache_dirs[0],
+ snapshot_dir=self.workdir)
+ except:
+ self.cancel('Failed to download/prepare boot image')
+ return boot.path
+
+ def prepare_cloudinit(self, ssh_pubkey=None):
+ self.log.info('Preparing cloudinit image')
+ try:
+ cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
+ pubkey_content = None
+ if ssh_pubkey:
+ with open(ssh_pubkey) as pubkey:
+ pubkey_content = pubkey.read()
+ cloudinit.iso(cloudinit_iso, self.name,
+ username=self.username,
+ password=self.password,
+ # QEMU's hard coded usermode router address
+ phone_home_host='10.0.2.2',
+ phone_home_port=self.phone_server.server_port,
+ authorized_key=pubkey_content)
+ except Exception:
+ self.cancel('Failed to prepare the cloudinit image')
+ return cloudinit_iso
+
+ def set_up_boot(self):
+ path = self.download_boot()
+ self.vm.add_args('-drive', 'file=%s' % path)
+
+ def set_up_cloudinit(self, ssh_pubkey=None):
+ self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
+ self.name)
+ cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
+ self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
+
+ def launch_and_wait(self, set_up_ssh_connection=True):
+ self.vm.set_console()
+ self.vm.launch()
+ console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
+ logger=self.log.getChild('console'))
+ console_drainer.start()
+ self.log.info('VM launched, waiting for boot confirmation from guest')
+ while not self.phone_server.instance_phoned_back:
+ self.phone_server.handle_request()
+
+ if set_up_ssh_connection:
+ self.log.info('Setting up the SSH connection')
+ self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py
index cdce4cb..a029ef4 100644
--- a/tests/avocado/boot_linux.py
+++ b/tests/avocado/boot_linux.py
@@ -10,7 +10,8 @@
import os
-from avocado_qemu import LinuxTest, BUILD_DIR
+from avocado_qemu.linuxtest import LinuxTest
+from avocado_qemu import BUILD_DIR
from avocado import skipUnless
diff --git a/tests/avocado/boot_xen.py b/tests/avocado/boot_xen.py
index fc2faee..f29bc58 100644
--- a/tests/avocado/boot_xen.py
+++ b/tests/avocado/boot_xen.py
@@ -17,9 +17,14 @@
from boot_linux_console import LinuxKernelTest
-class BootXenBase(LinuxKernelTest):
+class BootXen(LinuxKernelTest):
"""
Boots a Xen hypervisor with a Linux DomU kernel.
+
+ :avocado: tags=arch:aarch64
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:cortex-a57
+ :avocado: tags=machine:virt
"""
timeout = 90
@@ -45,11 +50,10 @@
self.vm.set_console()
- xen_command_line = self.XEN_COMMON_COMMAND_LINE
self.vm.add_args('-machine', 'virtualization=on',
'-m', '768',
'-kernel', xen_path,
- '-append', xen_command_line,
+ '-append', self.XEN_COMMON_COMMAND_LINE,
'-device',
'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
% (kernel_path))
@@ -59,17 +63,7 @@
console_pattern = 'VFS: Cannot open root device'
wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
-
-class BootXen(BootXenBase):
-
def test_arm64_xen_411_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
'download?path=%2F&files='
@@ -81,13 +75,6 @@
self.launch_xen(xen_path)
def test_arm64_xen_414_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
'download?path=%2F&files='
@@ -99,13 +86,6 @@
self.launch_xen(xen_path)
def test_arm64_xen_415_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
xen_url = ('https://fileserver.linaro.org/'
's/JSsewXGZ6mqxPr5/download'
'?path=%2F&files=xen-upstream-4.15-unstable.deb')
diff --git a/tests/avocado/hotplug_blk.py b/tests/avocado/hotplug_blk.py
index 5dc30f6..d55ded1 100644
--- a/tests/avocado/hotplug_blk.py
+++ b/tests/avocado/hotplug_blk.py
@@ -9,7 +9,7 @@
import time
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class HotPlug(LinuxTest):
diff --git a/tests/avocado/hotplug_cpu.py b/tests/avocado/hotplug_cpu.py
index 292bb43..342c838 100644
--- a/tests/avocado/hotplug_cpu.py
+++ b/tests/avocado/hotplug_cpu.py
@@ -8,7 +8,7 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class HotPlugCPU(LinuxTest):
diff --git a/tests/avocado/intel_iommu.py b/tests/avocado/intel_iommu.py
index 09e694b..008f214 100644
--- a/tests/avocado/intel_iommu.py
+++ b/tests/avocado/intel_iommu.py
@@ -10,7 +10,7 @@
import os
from avocado import skipUnless
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 29e6b38..f8e263d 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -87,7 +87,7 @@
class AST2x00Machine(QemuSystemTest):
- timeout = 90
+ timeout = 180
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
diff --git a/tests/avocado/machine_sparc_leon3.py b/tests/avocado/machine_sparc_leon3.py
deleted file mode 100644
index e61b223..0000000
--- a/tests/avocado/machine_sparc_leon3.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Functional test that boots a Leon3 machine and checks its serial console.
-#
-# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado import skip
-
-
-class Leon3Machine(QemuSystemTest):
-
- timeout = 60
-
- @skip("Test currently broken")
- # A Window Underflow exception occurs before booting the kernel,
- # and QEMU exit calling cpu_abort(), which makes this test to fail.
- def test_leon3_helenos_uimage(self):
- """
- :avocado: tags=arch:sparc
- :avocado: tags=machine:leon3_generic
- :avocado: tags=binfmt:uimage
- """
- kernel_url = ('http://www.helenos.org/releases/'
- 'HelenOS-0.6.0-sparc32-leon3.bin')
- kernel_hash = 'a88c9cfdb8430c66650e5290a08765f9bf049a30'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path)
-
- self.vm.launch()
-
- wait_for_console_pattern(self, 'Copyright (c) 2001-2014 HelenOS project')
- wait_for_console_pattern(self, 'Booting the kernel ...')
diff --git a/tests/avocado/mem-addr-space-check.py b/tests/avocado/mem-addr-space-check.py
index 85541ea..d397459 100644
--- a/tests/avocado/mem-addr-space-check.py
+++ b/tests/avocado/mem-addr-space-check.py
@@ -9,7 +9,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from avocado_qemu import QemuSystemTest
-import signal
import time
class MemAddrCheck(QemuSystemTest):
diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py
index f3a43dc..b467326 100644
--- a/tests/avocado/replay_linux.py
+++ b/tests/avocado/replay_linux.py
@@ -19,7 +19,7 @@
from avocado.utils import vmimage
from avocado.utils import datadrainer
from avocado.utils.path import find_command
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class ReplayLinux(LinuxTest):
"""
diff --git a/tests/avocado/smmu.py b/tests/avocado/smmu.py
index 4ebfa71..aadda71 100644
--- a/tests/avocado/smmu.py
+++ b/tests/avocado/smmu.py
@@ -10,7 +10,8 @@
import os
from avocado import skipUnless
-from avocado_qemu import LinuxTest, BUILD_DIR
+from avocado_qemu import BUILD_DIR
+from avocado_qemu.linuxtest import LinuxTest
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
diff --git a/tests/avocado/virtiofs_submounts.py.data/cleanup.sh b/tests/avocado/virtiofs_submounts.py.data/cleanup.sh
deleted file mode 100644
index 2a6579a..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/cleanup.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
- rm -rf "$mp"
-done
-echo
-
-rm some-file
-cd ..
-rmdir share
-
-imgs=(fs*.img)
-img_i=0
-for img in "${imgs[@]}"; do
- img_i=$((img_i + 1))
- printf "Detaching and deleting %i/%i...\r" "$img_i" "${#imgs[@]}"
-
- dev=$(losetup -j "$img" | sed -e 's/:.*//')
- sudo losetup -d "$dev"
- rm -f "$img"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh b/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh
deleted file mode 100644
index 729cb2d..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/avocado/virtiofs_submounts.py.data/guest.sh b/tests/avocado/virtiofs_submounts.py.data/guest.sh
deleted file mode 100644
index 59ba40f..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/guest.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <shared dir>"
- echo '(The shared directory is the "share" directory in the scratch' \
- 'directory)'
-}
-
-shared_dir=$1
-if [ -z "$shared_dir" ]; then
- print_usage "$0" 'Shared dir not given' >&2
- exit 1
-fi
-
-cd "$shared_dir"
-
-# FIXME: This should not be necessary, but it is. In order for all
-# submounts to be proper mount points, we need to visit them.
-# (Before we visit them, they will not be auto-mounted, and so just
-# appear as normal directories, with the catch that their st_ino will
-# be the st_ino of the filesystem they host, while the st_dev will
-# still be the st_dev of the parent.)
-# `find` does not work, because it will refuse to touch the mount
-# points as long as they are not mounted; their st_dev being shared
-# with the parent and st_ino just being the root node's inode ID
-# will practically ensure that this node exists elsewhere on the
-# filesystem, and `find` is required to recognize loops and not to
-# follow them.
-# Thus, we have to manually visit all nodes first.
-
-mnt_i=0
-
-function recursively_visit()
-{
- pushd "$1" >/dev/null
- for entry in *; do
- if [[ "$entry" == mnt* ]]; then
- mnt_i=$((mnt_i + 1))
- printf "Triggering auto-mount $mnt_i...\r"
- fi
-
- if [ -d "$entry" ]; then
- recursively_visit "$entry"
- fi
- done
- popd >/dev/null
-}
-
-recursively_visit .
-echo
-
-
-if [ -n "$(find -name not-mounted)" ]; then
- echo "Error: not-mounted files visible on mount points:" >&2
- find -name not-mounted >&2
- exit 1
-fi
-
-if [ ! -f some-file -o "$(cat some-file)" != 'root' ]; then
- echo "Error: Bad file in the share root" >&2
- exit 1
-fi
-
-shopt -s nullglob
-
-function check_submounts()
-{
- local base_path=$1
-
- for mp in mnt*; do
- printf "Checking submount %i...\r" "$((${#devs[@]} + 1))"
-
- mp_i=$(echo "$mp" | sed -e 's/mnt//')
- dev=$(stat -c '%D' "$mp")
-
- if [ -n "${devs[mp_i]}" ]; then
- echo "Error: $mp encountered twice" >&2
- exit 1
- fi
- devs[mp_i]=$dev
-
- pushd "$mp" >/dev/null
- path="$base_path$mp"
- while true; do
- expected_content="$(printf '%s\n%s\n' "$mp_i" "$path")"
- if [ ! -f some-file ]; then
- echo "Error: $PWD/some-file does not exist" >&2
- exit 1
- fi
-
- if [ "$(cat some-file)" != "$expected_content" ]; then
- echo "Error: Bad content in $PWD/some-file:" >&2
- echo '--- found ---'
- cat some-file
- echo '--- expected ---'
- echo "$expected_content"
- exit 1
- fi
- if [ "$(stat -c '%D' some-file)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
-
- if [ -d sub ]; then
- if [ "$(stat -c '%D' sub)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
- cd sub
- path="$path/sub"
- else
- if [ -n "$(echo mnt*)" ]; then
- check_submounts "$path/"
- fi
- break
- fi
- done
- popd >/dev/null
- done
-}
-
-root_dev=$(stat -c '%D' some-file)
-devs=()
-check_submounts ''
-echo
-
-reused_devs=$(echo "$root_dev ${devs[@]}" | tr ' ' '\n' | sort | uniq -d)
-if [ -n "$reused_devs" ]; then
- echo "Error: Reused device IDs: $reused_devs" >&2
- exit 1
-fi
-
-echo "Test passed for ${#devs[@]} submounts."
diff --git a/tests/avocado/virtiofs_submounts.py.data/host.sh b/tests/avocado/virtiofs_submounts.py.data/host.sh
deleted file mode 100644
index d8a9afe..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/host.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-mount_count=128
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir> [seed]"
- echo "(If no seed is given, it will be randomly generated.)"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'No scratch dir given' >&2
- exit 1
-fi
-
-if [ ! -d "$scratch_dir" ]; then
- print_usage "$0" "$scratch_dir is not a directory" >&2
- exit 1
-fi
-
-seed=$2
-if [ -z "$seed" ]; then
- seed=$RANDOM
-fi
-RANDOM=$seed
-
-echo "Seed: $seed"
-
-set -e
-shopt -s nullglob
-
-cd "$scratch_dir"
-if [ -d share ]; then
- echo 'Error: This directory seems to be in use already' >&2
- exit 1
-fi
-
-for ((i = 0; i < $mount_count; i++)); do
- printf "Setting up fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- rm -f fs$i.img
- truncate -s 512M fs$i.img
- mkfs.xfs -q fs$i.img
- devs[i]=$(sudo losetup -f --show fs$i.img)
-done
-echo
-
-top_level_mounts=$((RANDOM % mount_count + 1))
-
-mkdir -p share
-echo 'root' > share/some-file
-
-for ((i = 0; i < $top_level_mounts; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mkdir -p share/mnt$i
- touch share/mnt$i/not-mounted
- sudo mount "${devs[i]}" share/mnt$i
- sudo chown "$(id -u):$(id -g)" share/mnt$i
-
- pushd share/mnt$i >/dev/null
- path=mnt$i
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
-cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-
-for ((; i < $mount_count; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mp_i=$((i % top_level_mounts))
-
- pushd share/mnt$mp_i >/dev/null
- path=mnt$mp_i
- while true; do
- sub_mp="$(echo mnt*)"
- if cd sub 2>/dev/null; then
- path="$path/sub"
- elif [ -n "$sub_mp" ] && cd "$sub_mp" 2>/dev/null; then
- path="$path/$sub_mp"
- else
- break
- fi
- done
- mkdir mnt$i
- touch mnt$i/not-mounted
- sudo mount "${devs[i]}" mnt$i
- sudo chown "$(id -u):$(id -g)" mnt$i
-
- cd mnt$i
- path="$path/mnt$i"
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
- cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-echo
-
-echo 'Done.'
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
index 0e9490c..789b460 160000
--- a/tests/lcitool/libvirt-ci
+++ b/tests/lcitool/libvirt-ci
@@ -1 +1 @@
-Subproject commit 0e9490cebc726ef772b6c9e27dac32e7ae99f9b2
+Subproject commit 789b4601bce4e01f43fdb6ad4ce5ab4e46674440
diff --git a/tests/plugin/inline.c b/tests/plugin/inline.c
index cd63827..73dde99 100644
--- a/tests/plugin/inline.c
+++ b/tests/plugin/inline.c
@@ -71,10 +71,12 @@
const uint64_t cond_track_left = qemu_plugin_u64_sum(insn_cond_track_count);
const uint64_t conditional =
cond_num_trigger * cond_trigger_limit + cond_track_left;
- printf("insn: %" PRIu64 "\n", expected);
- printf("insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
- printf("insn: %" PRIu64 " (cond cb)\n", conditional);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "insn: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (cond cb)\n", conditional);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -91,10 +93,12 @@
const uint64_t cond_track_left = qemu_plugin_u64_sum(tb_cond_track_count);
const uint64_t conditional =
cond_num_trigger * cond_trigger_limit + cond_track_left;
- printf("tb: %" PRIu64 "\n", expected);
- printf("tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
- printf("tb: %" PRIu64 " (conditional cb)\n", conditional);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "tb: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (conditional cb)\n", conditional);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -107,9 +111,11 @@
const uint64_t per_vcpu = qemu_plugin_u64_sum(count_mem);
const uint64_t inl_per_vcpu =
qemu_plugin_u64_sum(count_mem_inline);
- printf("mem: %" PRIu64 "\n", expected);
- printf("mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "mem: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -118,6 +124,7 @@
static void plugin_exit(qemu_plugin_id_t id, void *udata)
{
const unsigned int num_cpus = qemu_plugin_num_vcpus();
+ g_autoptr(GString) stats = g_string_new("");
g_assert(num_cpus == max_cpu_index + 1);
for (int i = 0; i < num_cpus ; ++i) {
@@ -135,20 +142,21 @@
qemu_plugin_u64_get(insn_cond_num_trigger, i);
const uint64_t insn_cond_left =
qemu_plugin_u64_get(insn_cond_track_count, i);
- printf("cpu %d: tb (%" PRIu64 ", %" PRIu64
- ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
- ") | "
- "insn (%" PRIu64 ", %" PRIu64
- ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
- ") | "
- "mem (%" PRIu64 ", %" PRIu64 ")"
- "\n",
- i,
- tb, tb_inline,
- tb_cond_trigger, cond_trigger_limit, tb_cond_left,
- insn, insn_inline,
- insn_cond_trigger, cond_trigger_limit, insn_cond_left,
- mem, mem_inline);
+ g_string_printf(stats, "cpu %d: tb (%" PRIu64 ", %" PRIu64
+ ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
+ ") | "
+ "insn (%" PRIu64 ", %" PRIu64
+ ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
+ ") | "
+ "mem (%" PRIu64 ", %" PRIu64 ")"
+ "\n",
+ i,
+ tb, tb_inline,
+ tb_cond_trigger, cond_trigger_limit, tb_cond_left,
+ insn, insn_inline,
+ insn_cond_trigger, cond_trigger_limit, insn_cond_left,
+ mem, mem_inline);
+ qemu_plugin_outs(stats->str);
g_assert(tb == tb_inline);
g_assert(insn == insn_inline);
g_assert(mem == mem_inline);
diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c
index ec842e0..d107a49 100644
--- a/tests/qtest/fuzz/generic_fuzz.c
+++ b/tests/qtest/fuzz/generic_fuzz.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/range.h"
#include <wordexp.h>
@@ -211,7 +212,7 @@
i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
++i) {
region = g_array_index(dma_regions, address_range, i);
- if (addr < region.addr + region.size && addr + len > region.addr) {
+ if (ranges_overlap(addr, len, region.addr, region.size)) {
double_fetch = true;
if (addr < region.addr
&& avoid_double_fetches) {
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6508bfb..ff9200f 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -1,6 +1,6 @@
slow_qtests = {
'aspeed_smc-test': 360,
- 'bios-tables-test' : 610,
+ 'bios-tables-test' : 910,
'cdrom-test' : 610,
'device-introspect-test' : 720,
'migration-test' : 480,
diff --git a/tests/tcg/aarch64/gdbstub/test-mte.py b/tests/tcg/aarch64/gdbstub/test-mte.py
index 2db0663..66f9c25 100644
--- a/tests/tcg/aarch64/gdbstub/test-mte.py
+++ b/tests/tcg/aarch64/gdbstub/test-mte.py
@@ -18,7 +18,7 @@
from test_gdbstub import main, report
-PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)."
+PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \\(0x[0-9a-f]+\\)."
PATTERN_1 = ".*(0x[0-9a-f]+)"
diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json
index 2d5895e..2a361ce 100644
--- a/tests/vm/generated/freebsd.json
+++ b/tests/vm/generated/freebsd.json
@@ -51,13 +51,13 @@
"pixman",
"pkgconf",
"png",
- "py39-numpy",
- "py39-pillow",
- "py39-pip",
- "py39-sphinx",
- "py39-sphinx_rtd_theme",
- "py39-tomli",
- "py39-yaml",
+ "py311-numpy",
+ "py311-pillow",
+ "py311-pip",
+ "py311-sphinx",
+ "py311-sphinx_rtd_theme",
+ "py311-tomli",
+ "py311-yaml",
"python3",
"rpm2cpio",
"sdl2",