Merge tag 'pull-ppc-for-10.2-d4-20251030' of https://gitlab.com/harshpb/qemu into staging
ppc queue for 10.2
* Firmware updates for SLOF, sam460ex u-boot
* Removal of unusable e200 CPUs
* Coverity fixes for fadump
* Other minor fixes, cleanups for pegasos, spapr.
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEa4EM1tK+EPOIPSFCRUTplPnWj7sFAmkDH0MACgkQRUTplPnW
# j7tRjQ/+JbtHt8v4liav4EXRMvM0b8ASDQZFtltC8cg/vpgy/CbYgqcltQDKC4+F
# NjBwSR4mKMTLX95LQsdFCLZY6FENKCirjpsCvHDxU9Hw/UdsVA12rFd/+lgytrTe
# yvJzyhUAoUMSFgpYGZSRQVV+eMEMgHBZekR2RLXwEeuLf/TOAdG+giCMM92Xs7bz
# petdqCspKvpw8RHjb2nyIh67RQ3zYVisU9/pczoNRytjQHYgllddXRt1/DOdF/Gi
# zREc7qE3biDg5jYgWScByy6EwBBBPqNbvR1GLjMV2rM77785KD9GsIzKCCzg6YQY
# CSN/fy8V4TXVkJn8nY2s3SHvBz3szNSvx/nL8sCyKXol/5Naha5CLN0ykz5VcrIf
# 9gNwifW22lHbAtvbmRY9yuTrao8RoQwEZ/3o8Te3W/U9iCFLnwCmKWb/3GT6i/kw
# yyJlUBuW5WASf5N+G0N7IB5BAwzoQQtd0WXW1ugXAFG+Bd/nkRvVkIf9sPWUxWJ/
# 0Tx+2rPZOFzju8VYO8188wh/zDLuNRTEdfo+L21GMI2OBBEUO2nIiwPTLIMrCT4e
# ycC7Vvyu3IahX9ojIL9g0RhPH4K4JDbQuDnszp9SBGcgJYzwLh5Hb436A30A6qJE
# 7r5FTCiwtG27eMKCeZU3iBGpcj+g4kWIvmYEITsyCl8CxKv5+fs=
# =fzVo
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 30 Oct 2025 09:18:11 AM CET
# gpg: using RSA key 6B810CD6D2BE10F3883D21424544E994F9D68FBB
# gpg: Good signature from "Harsh Prateek Bora <harsh.prateek.bora@gmail.com>" [undefined]
# gpg: aka "Harsh Prateek Bora <harshpb@linux.ibm.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6B81 0CD6 D2BE 10F3 883D 2142 4544 E994 F9D6 8FBB
* tag 'pull-ppc-for-10.2-d4-20251030' of https://gitlab.com/harshpb/qemu:
hw/ppc/pegasos: Update documentation for pegasos1
hw/ppc/pegasos2: Rename to pegasos
hw/ppc/pegasos2: Add /chosen/stdin node with VOF
hw/ppc: Fix memory leak in get_cpu_state_data()
hw/ppc: Fix missing return on allocation failure
ppc/spapr: Cleanup MSI IRQ number handling
target/ppc: Remove the unusable e200 CPUs
target/ppc/cpu_init: Simplify the setup of the TLBxCFG SPR registers
hw/ppc/sam460ex: Update u-boot-sam460ex
pseries: Update SLOF firmware image to release 20251027
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml
index 46db9ae..ee13587 100644
--- a/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml
+++ b/.gitlab-ci.d/custom-runners/ubuntu-24.04-aarch64.yml
@@ -107,7 +107,5 @@
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- allow_failure: true
- if: "$AARCH64_RUNNER_AVAILABLE"
when: manual
- allow_failure: true
diff --git a/MAINTAINERS b/MAINTAINERS
index 8063eef..030d505 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2007,6 +2007,7 @@
S: Supported
F: include/qemu/target-info*.h
F: target-info*.c
+F: configs/targets/*.c
Xtensa Machines
---------------
@@ -4081,7 +4082,7 @@
VHDX
M: Jeff Cody <codyprime@gmail.com>
L: qemu-block@nongnu.org
-S: Supported
+S: Odd Fixes
F: block/vhdx*
VDI
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 631f1fe..fd1606c 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1668,18 +1668,7 @@
if (likely(!maybe_resized)) {
/* Alignment has not been checked by tlb_fill_align. */
- int a_bits = memop_alignment_bits(memop);
-
- /*
- * This alignment check differs from the one above, in that this is
- * based on the atomicity of the operation. The intended use case is
- * the ARM memory type field of each PTE, where access to pages with
- * Device memory type require alignment.
- */
- if (unlikely(flags & TLB_CHECK_ALIGNED)) {
- int at_bits = memop_atomicity_bits(memop);
- a_bits = MAX(a_bits, at_bits);
- }
+ int a_bits = memop_tlb_alignment_bits(memop, flags & TLB_CHECK_ALIGNED);
if (unlikely(addr & ((1 << a_bits) - 1))) {
cpu_unaligned_access(cpu, addr, access_type, mmu_idx, ra);
}
diff --git a/backends/spdm-socket.c b/backends/spdm-socket.c
index 2c709c6..6d8f02d 100644
--- a/backends/spdm-socket.c
+++ b/backends/spdm-socket.c
@@ -13,6 +13,9 @@
#include "qemu/osdep.h"
#include "system/spdm-socket.h"
#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/core/qdev-prop-internal.h"
static bool read_bytes(const int socket, uint8_t *buffer,
size_t number_of_bytes)
@@ -184,29 +187,61 @@
return client_socket;
}
-uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
- void *req, uint32_t req_len,
- void *rsp, uint32_t rsp_len)
+static bool spdm_socket_command_valid(uint32_t command)
+{
+ switch (command) {
+ case SPDM_SOCKET_COMMAND_NORMAL:
+ case SPDM_SOCKET_STORAGE_CMD_IF_SEND:
+ case SPDM_SOCKET_STORAGE_CMD_IF_RECV:
+ case SOCKET_SPDM_STORAGE_ACK_STATUS:
+ case SPDM_SOCKET_COMMAND_OOB_ENCAP_KEY_UPDATE:
+ case SPDM_SOCKET_COMMAND_CONTINUE:
+ case SPDM_SOCKET_COMMAND_SHUTDOWN:
+ case SPDM_SOCKET_COMMAND_UNKOWN:
+ case SPDM_SOCKET_COMMAND_TEST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+uint32_t spdm_socket_receive(const int socket, uint32_t transport_type,
+ void *rsp, uint32_t rsp_len)
{
uint32_t command;
bool result;
- result = send_platform_data(socket, transport_type,
- SPDM_SOCKET_COMMAND_NORMAL,
- req, req_len);
- if (!result) {
- return 0;
- }
-
result = receive_platform_data(socket, transport_type, &command,
(uint8_t *)rsp, &rsp_len);
+
+ /* we may have received some data, but check if the command is valid */
+ if (!result || !spdm_socket_command_valid(command)) {
+ return 0;
+ }
+
+ return rsp_len;
+}
+
+bool spdm_socket_send(const int socket, uint32_t socket_cmd,
+ uint32_t transport_type, void *req, uint32_t req_len)
+{
+ return send_platform_data(socket, transport_type, socket_cmd, req,
+ req_len);
+}
+
+uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
+ void *req, uint32_t req_len,
+ void *rsp, uint32_t rsp_len)
+{
+ bool result;
+
+ result = spdm_socket_send(socket, SPDM_SOCKET_COMMAND_NORMAL,
+ transport_type, req, req_len);
if (!result) {
return 0;
}
- assert(command != 0);
-
- return rsp_len;
+ return spdm_socket_receive(socket, transport_type, rsp, rsp_len);
}
void spdm_socket_close(const int socket, uint32_t transport_type)
@@ -214,3 +249,23 @@
send_platform_data(socket, transport_type,
SPDM_SOCKET_COMMAND_SHUTDOWN, NULL, 0);
}
+
+const QEnumLookup SpdmTransport_lookup = {
+ .array = (const char *const[]) {
+ [SPDM_SOCKET_TRANSPORT_TYPE_UNSPEC] = "unspecified",
+ [SPDM_SOCKET_TRANSPORT_TYPE_MCTP] = "mctp",
+ [SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE] = "doe",
+ [SPDM_SOCKET_TRANSPORT_TYPE_SCSI] = "scsi",
+ [SPDM_SOCKET_TRANSPORT_TYPE_NVME] = "nvme",
+ },
+ .size = SPDM_SOCKET_TRANSPORT_TYPE_MAX
+};
+
+const PropertyInfo qdev_prop_spdm_trans = {
+ .type = "SpdmTransportType",
+ .description = "Spdm Transport, doe/nvme/mctp/scsi/unspecified",
+ .enum_table = &SpdmTransport_lookup,
+ .get = qdev_propinfo_get_enum,
+ .set = qdev_propinfo_set_enum,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
diff --git a/block.c b/block.c
index 8848e9a..cf08e64 100644
--- a/block.c
+++ b/block.c
@@ -1497,6 +1497,17 @@
}
}
+static void coroutine_fn GRAPH_RDLOCK bdrv_child_cb_resize(BdrvChild *child)
+{
+ BlockDriverState *bs = child->opaque;
+
+ if (child->role & BDRV_CHILD_FILTERED) {
+ /* Best effort, ignore errors. */
+ bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
+ bdrv_co_parent_cb_resize(bs);
+ }
+}
+
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
const char *filename,
bool backing_mask_protocol,
@@ -1529,6 +1540,7 @@
.detach = bdrv_child_cb_detach,
.inactivate = bdrv_child_cb_inactivate,
.change_aio_ctx = bdrv_child_cb_change_aio_ctx,
+ .resize = bdrv_child_cb_resize,
.update_filename = bdrv_child_cb_update_filename,
.get_parent_aio_context = child_of_bds_get_parent_aio_context,
};
diff --git a/block/accounting.c b/block/accounting.c
index 3e46159..0933c61 100644
--- a/block/accounting.c
+++ b/block/accounting.c
@@ -28,6 +28,7 @@
#include "block/block_int.h"
#include "qemu/timer.h"
#include "system/qtest.h"
+#include "qapi/error.h"
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000;
@@ -56,13 +57,25 @@
}
}
-void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
- enum OnOffAuto account_failed)
+bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
+ enum OnOffAuto account_failed, uint32_t *stats_intervals,
+ uint32_t num_stats_intervals, Error **errp)
{
stats->account_invalid = bool_from_onoffauto(account_invalid,
stats->account_invalid);
stats->account_failed = bool_from_onoffauto(account_failed,
stats->account_failed);
+ if (stats_intervals) {
+ for (int i = 0; i < num_stats_intervals; i++) {
+ if (stats_intervals[i] <= 0) {
+ error_setg(errp, "Invalid interval length: %u", stats_intervals[i]);
+ return false;
+ }
+ block_acct_add_interval(stats, stats_intervals[i]);
+ }
+ g_free(stats_intervals);
+ }
+ return true;
}
void block_acct_cleanup(BlockAcctStats *stats)
diff --git a/block/crypto.c b/block/crypto.c
index d4226cc..7c37b23 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -67,11 +67,18 @@
BlockCrypto *crypto = bs->opaque;
ssize_t ret;
- GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+ if (qemu_in_coroutine()) {
+ GRAPH_RDLOCK_GUARD();
- ret = bdrv_pread(crypto->header ? crypto->header : bs->file,
- offset, buflen, buf, 0);
+ ret = bdrv_co_pread(crypto->header ? crypto->header : bs->file,
+ offset, buflen, buf, 0);
+ } else {
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
+ ret = bdrv_pread(crypto->header ? crypto->header : bs->file,
+ offset, buflen, buf, 0);
+ }
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read encryption header");
return ret;
@@ -90,11 +97,18 @@
BlockCrypto *crypto = bs->opaque;
ssize_t ret;
- GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+ if (qemu_in_coroutine()) {
+ GRAPH_RDLOCK_GUARD();
- ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file,
- offset, buflen, buf, 0);
+ ret = bdrv_co_pwrite(crypto->header ? crypto->header : bs->file,
+ offset, buflen, buf, 0);
+ } else {
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
+ ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file,
+ offset, buflen, buf, 0);
+ }
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header");
return ret;
@@ -792,7 +806,7 @@
char *buf = NULL;
int64_t size;
bool detached_hdr =
- qemu_opt_get_bool(opts, "detached-header", false);
+ qemu_opt_get_bool_del(opts, "detached-header", false);
unsigned int cflags = 0;
int ret;
Error *local_err = NULL;
diff --git a/block/curl.c b/block/curl.c
index 68cf83c..d7d93d9 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -524,7 +524,7 @@
#endif
#ifdef DEBUG_VERBOSE
- if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) {
+ if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1L)) {
goto err;
}
#endif
diff --git a/block/io.c b/block/io.c
index 9bd8ba8..928c02d 100644
--- a/block/io.c
+++ b/block/io.c
@@ -46,9 +46,6 @@
/* Maximum read size for checking if data reads as zero, in bytes */
#define MAX_ZERO_CHECK_BUFFER (128 * KiB)
-static void coroutine_fn GRAPH_RDLOCK
-bdrv_parent_cb_resize(BlockDriverState *bs);
-
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
@@ -2038,7 +2035,7 @@
end_sector > bs->total_sectors) &&
req->type != BDRV_TRACKED_DISCARD) {
bs->total_sectors = end_sector;
- bdrv_parent_cb_resize(bs);
+ bdrv_co_parent_cb_resize(bs);
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
}
if (req->bytes) {
@@ -3570,11 +3567,11 @@
bytes, read_flags, write_flags);
}
-static void coroutine_fn GRAPH_RDLOCK
-bdrv_parent_cb_resize(BlockDriverState *bs)
+void coroutine_fn bdrv_co_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
+ IO_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) {
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 282d1c3..3640d1f 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -62,7 +62,7 @@
{
QemuOpts *opts;
QDict *qdict;
- Error *local_err = NULL;
+ Error *err = NULL;
opts = qemu_opts_parse_noisily(&qemu_drive_opts, optstr, false);
if (!opts) {
@@ -73,19 +73,19 @@
if (!qdict_get_try_str(qdict, "node-name")) {
qobject_unref(qdict);
- error_report("'node-name' needs to be specified");
+ error_setg(&err, "'node-name' needs to be specified");
goto out;
}
- BlockDriverState *bs = bds_tree_init(qdict, &local_err);
+ BlockDriverState *bs = bds_tree_init(qdict, &err);
if (!bs) {
- error_report_err(local_err);
goto out;
}
bdrv_set_monitor_owned(bs);
out:
qemu_opts_del(opts);
+ hmp_handle_error(mon, err);
}
void hmp_drive_add(Monitor *mon, const QDict *qdict)
@@ -109,7 +109,6 @@
mc = MACHINE_GET_CLASS(current_machine);
dinfo = drive_new(opts, mc->block_default_type, &err);
if (err) {
- error_report_err(err);
qemu_opts_del(opts);
goto err;
}
@@ -123,7 +122,7 @@
monitor_printf(mon, "OK\n");
break;
default:
- monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
+ error_setg(&err, "Can't hot-add drive to type %d", dinfo->type);
goto err;
}
return;
@@ -134,6 +133,7 @@
monitor_remove_blk(blk);
blk_unref(blk);
}
+ hmp_handle_error(mon, err);
}
void hmp_drive_del(Monitor *mon, const QDict *qdict)
@@ -141,36 +141,32 @@
const char *id = qdict_get_str(qdict, "id");
BlockBackend *blk;
BlockDriverState *bs;
- Error *local_err = NULL;
+ Error *err = NULL;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
bs = bdrv_find_node(id);
if (bs) {
- qmp_blockdev_del(id, &local_err);
- if (local_err) {
- error_report_err(local_err);
- }
+ qmp_blockdev_del(id, &err);
goto unlock;
}
blk = blk_by_name(id);
if (!blk) {
- error_report("Device '%s' not found", id);
+ error_setg(&err, "Device '%s' not found", id);
goto unlock;
}
if (!blk_legacy_dinfo(blk)) {
- error_report("Deleting device added with blockdev-add"
- " is not supported");
+ error_setg(&err, "Deleting device added with blockdev-add"
+ " is not supported");
goto unlock;
}
bs = blk_bs(blk);
if (bs) {
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
- error_report_err(local_err);
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &err)) {
goto unlock;
}
@@ -196,6 +192,7 @@
unlock:
bdrv_graph_rdunlock_main_loop();
+ hmp_handle_error(mon, err);
}
void hmp_commit(Monitor *mon, const QDict *qdict)
@@ -203,6 +200,7 @@
const char *device = qdict_get_str(qdict, "device");
BlockBackend *blk;
int ret;
+ Error *err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
@@ -214,22 +212,25 @@
blk = blk_by_name(device);
if (!blk) {
- error_report("Device '%s' not found", device);
- return;
+ error_setg(&err, "Device '%s' not found", device);
+ goto end;
}
bs = bdrv_skip_implicit_filters(blk_bs(blk));
if (!blk_is_available(blk)) {
- error_report("Device '%s' has no medium", device);
- return;
+ error_setg(&err, "Device '%s' has no medium", device);
+ goto end;
}
ret = bdrv_commit(bs);
}
if (ret < 0) {
- error_report("'commit' error for '%s': %s", device, strerror(-ret));
+ error_setg(&err, "'commit' error for '%s': %s", device, strerror(-ret));
}
+
+end:
+ hmp_handle_error(mon, err);
}
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
@@ -890,7 +891,7 @@
bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
if (!bs) {
- error_report_err(err);
+ hmp_handle_error(mon, err);
return;
}
diff --git a/block/qapi.c b/block/qapi.c
index 12fbf8d..9f5771e 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -235,7 +235,8 @@
* in @info, setting @errp on error.
*/
static void GRAPH_RDLOCK
-bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
+bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, bool limits,
+ Error **errp)
{
int64_t size;
const char *backing_filename;
@@ -269,6 +270,33 @@
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
+
+ if (limits) {
+ info->limits = g_new(BlockLimitsInfo, 1);
+ *info->limits = (BlockLimitsInfo) {
+ .request_alignment = bs->bl.request_alignment,
+ .has_max_discard = bs->bl.max_pdiscard != 0,
+ .max_discard = bs->bl.max_pdiscard,
+ .has_discard_alignment = bs->bl.pdiscard_alignment != 0,
+ .discard_alignment = bs->bl.pdiscard_alignment,
+ .has_max_write_zeroes = bs->bl.max_pwrite_zeroes != 0,
+ .max_write_zeroes = bs->bl.max_pwrite_zeroes,
+ .has_write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment != 0,
+ .write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment,
+ .has_opt_transfer = bs->bl.opt_transfer != 0,
+ .opt_transfer = bs->bl.opt_transfer,
+ .has_max_transfer = bs->bl.max_transfer != 0,
+ .max_transfer = bs->bl.max_transfer,
+ .has_max_hw_transfer = bs->bl.max_hw_transfer != 0,
+ .max_hw_transfer = bs->bl.max_hw_transfer,
+ .max_iov = bs->bl.max_iov,
+ .has_max_hw_iov = bs->bl.max_hw_iov != 0,
+ .max_hw_iov = bs->bl.max_hw_iov,
+ .min_mem_alignment = bs->bl.min_mem_alignment,
+ .opt_mem_alignment = bs->bl.opt_mem_alignment,
+ };
+ }
+
info->format_specific = bdrv_get_specific_info(bs, &err);
if (err) {
error_propagate(errp, err);
@@ -343,7 +371,7 @@
ImageInfo *info;
info = g_new0(ImageInfo, 1);
- bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp);
+ bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), true, errp);
if (*errp) {
goto fail;
}
@@ -389,6 +417,7 @@
*/
void bdrv_query_block_graph_info(BlockDriverState *bs,
BlockGraphInfo **p_info,
+ bool limits,
Error **errp)
{
ERRP_GUARD();
@@ -397,7 +426,7 @@
BdrvChild *c;
info = g_new0(BlockGraphInfo, 1);
- bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp);
+ bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), limits, errp);
if (*errp) {
goto fail;
}
@@ -411,7 +440,7 @@
QAPI_LIST_APPEND(children_list_tail, c_info);
c_info->name = g_strdup(c->name);
- bdrv_query_block_graph_info(c->bs, &c_info->info, errp);
+ bdrv_query_block_graph_info(c->bs, &c_info->info, limits, errp);
if (*errp) {
goto fail;
}
@@ -909,6 +938,29 @@
}
/**
+ * Dumps the given BlockLimitsInfo object in a human-readable form,
+ * prepending an optional prefix if the dump is not empty.
+ */
+static void bdrv_image_info_limits_dump(BlockLimitsInfo *limits,
+ const char *prefix,
+ int indentation)
+{
+ QObject *obj;
+ Visitor *v = qobject_output_visitor_new(&obj);
+
+ visit_type_BlockLimitsInfo(v, NULL, &limits, &error_abort);
+ visit_complete(v, &obj);
+ if (!qobject_is_empty_dump(obj)) {
+ if (prefix) {
+ qemu_printf("%*s%s", indentation * 4, "", prefix);
+ }
+ dump_qobject(indentation + 1, obj);
+ }
+ qobject_unref(obj);
+ visit_free(v);
+}
+
+/**
* Print the given @info object in human-readable form. Every field is indented
* using the given @indentation (four spaces per indentation level).
*
@@ -983,6 +1035,12 @@
}
}
+ if (info->limits) {
+ bdrv_image_info_limits_dump(info->limits,
+ "Block limits:\n",
+ indentation);
+ }
+
if (info->has_snapshots) {
SnapshotInfoList *elem;
diff --git a/blockdev.c b/blockdev.c
index b451fee..dbd1d4d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -617,7 +617,8 @@
bs->detect_zeroes = detect_zeroes;
- block_acct_setup(blk_get_stats(blk), account_invalid, account_failed);
+ block_acct_setup(blk_get_stats(blk), account_invalid, account_failed,
+ NULL, 0, NULL);
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
blk_unref(blk);
diff --git a/configs/devices/aarch64-softmmu/minimal.mak b/configs/devices/aarch64-softmmu/minimal.mak
index 0ebc1dc..3c8582e 100644
--- a/configs/devices/aarch64-softmmu/minimal.mak
+++ b/configs/devices/aarch64-softmmu/minimal.mak
@@ -6,4 +6,3 @@
#
CONFIG_ARM_VIRT=y
-CONFIG_SBSA_REF=y
diff --git a/configs/targets/aarch64-softmmu.c b/configs/targets/aarch64-softmmu.c
new file mode 100644
index 0000000..4e1e2f6
--- /dev/null
+++ b/configs/targets/aarch64-softmmu.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU binary/target API (qemu-system-aarch64)
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/target-info-impl.h"
+#include "hw/arm/machines-qom.h"
+#include "target/arm/cpu-qom.h"
+
+static const TargetInfo target_info_aarch64_system = {
+ .target_name = "aarch64",
+ .target_arch = SYS_EMU_TARGET_AARCH64,
+ .long_bits = 64,
+ .cpu_type = TYPE_ARM_CPU,
+ .machine_typename = TYPE_TARGET_AARCH64_MACHINE,
+ .endianness = ENDIAN_MODE_LITTLE,
+};
+
+const TargetInfo *target_info(void)
+{
+ return &target_info_aarch64_system;
+}
diff --git a/configs/targets/arm-softmmu.c b/configs/targets/arm-softmmu.c
new file mode 100644
index 0000000..9b3fdd2
--- /dev/null
+++ b/configs/targets/arm-softmmu.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU binary/target API (qemu-system-arm)
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/target-info-impl.h"
+#include "hw/arm/machines-qom.h"
+#include "target/arm/cpu-qom.h"
+
+static const TargetInfo target_info_arm_system = {
+ .target_name = "arm",
+ .target_arch = SYS_EMU_TARGET_ARM,
+ .long_bits = 32,
+ .cpu_type = TYPE_ARM_CPU,
+ .machine_typename = TYPE_TARGET_ARM_MACHINE,
+ .endianness = ENDIAN_MODE_LITTLE,
+};
+
+const TargetInfo *target_info(void)
+{
+ return &target_info_arm_system;
+}
diff --git a/configs/targets/meson.build b/configs/targets/meson.build
new file mode 100644
index 0000000..cca2514
--- /dev/null
+++ b/configs/targets/meson.build
@@ -0,0 +1,5 @@
+foreach target : [
+ 'arm-softmmu', 'aarch64-softmmu',
+ ]
+ config_target_info += {target : files(target + '.c')}
+endforeach
diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build
index 7eb3629..eb944b5 100644
--- a/contrib/plugins/meson.build
+++ b/contrib/plugins/meson.build
@@ -1,6 +1,6 @@
contrib_plugins = ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotblocks',
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger',
- 'uftrace']
+ 'traps', 'uftrace']
if host_os != 'windows'
# lockstep uses socket.h
contrib_plugins += 'lockstep'
diff --git a/contrib/plugins/traps.c b/contrib/plugins/traps.c
new file mode 100644
index 0000000..d5ddc0f
--- /dev/null
+++ b/contrib/plugins/traps.c
@@ -0,0 +1,83 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2025, Julian Ganz <neither@nut.email>
+ *
+ * Traps - count traps
+ *
+ * Count the number of interrupts (asyncronous events), exceptions (synchronous
+ * events) and host calls (e.g. semihosting) per cpu and report those counts on
+ * exit.
+ */
+
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+typedef struct {
+ uint64_t interrupts;
+ uint64_t exceptions;
+ uint64_t hostcalls;
+} TrapCounters;
+
+static struct qemu_plugin_scoreboard *traps;
+
+static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index,
+ enum qemu_plugin_discon_type type, uint64_t from_pc,
+ uint64_t to_pc)
+{
+ TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu_index);
+ switch (type) {
+ case QEMU_PLUGIN_DISCON_INTERRUPT:
+ rec->interrupts++;
+ break;
+ case QEMU_PLUGIN_DISCON_EXCEPTION:
+ rec->exceptions++;
+ break;
+ case QEMU_PLUGIN_DISCON_HOSTCALL:
+ rec->hostcalls++;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_autoptr(GString) report;
+ report = g_string_new("VCPU, interrupts, exceptions, hostcalls\n");
+ int max_vcpus = qemu_plugin_num_vcpus();
+ int vcpu;
+
+ for (vcpu = 0; vcpu < max_vcpus; vcpu++) {
+ TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu);
+ g_string_append_printf(report,
+ "% 4d, % 10"PRId64", % 10"PRId64", % 10"PRId64
+ "\n", vcpu, rec->interrupts, rec->exceptions,
+ rec->hostcalls);
+ }
+
+ qemu_plugin_outs(report->str);
+ qemu_plugin_scoreboard_free(traps);
+}
+
+QEMU_PLUGIN_EXPORT
+int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
+ int argc, char **argv)
+{
+ if (!info->system_emulation) {
+ qemu_plugin_outs("Note: interrupts are only reported in system"
+ " emulation mode.");
+ }
+
+ traps = qemu_plugin_scoreboard_new(sizeof(TrapCounters));
+
+ qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL,
+ vcpu_discon);
+
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+
+ return 0;
+}
diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index 8a5e128..92c2191 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -1015,6 +1015,14 @@
# generate trace around init execution (2 seconds):
$ uftrace dump --chrome --time-range=1753122320~1753122322 > init.json
+Count traps
+...........
+
+``contrib/plugins/traps.c``
+
+This plugin counts the number of interrupts (asyncronous events), exceptions
+(synchronous events) and host calls (e.g. semihosting) per cpu.
+
Other emulation features
------------------------
diff --git a/docs/devel/testing/ci-jobs.rst.inc b/docs/devel/testing/ci-jobs.rst.inc
index f1c541c..b92d372 100644
--- a/docs/devel/testing/ci-jobs.rst.inc
+++ b/docs/devel/testing/ci-jobs.rst.inc
@@ -168,13 +168,6 @@
runner, you can set this variable to enable the tests that require this
kind of host. The runner should be tagged with "aarch64".
-AARCH32_RUNNER_AVAILABLE
-~~~~~~~~~~~~~~~~~~~~~~~~
-If you've got access to an armhf host or an arch64 host that can run
-aarch32 EL0 code to be used as a gitlab-CI runner, you can set this
-variable to enable the tests that require this kind of host. The
-runner should be tagged with "aarch32".
-
S390X_RUNNER_AVAILABLE
~~~~~~~~~~~~~~~~~~~~~~
If you've got access to an IBM Z host that can be used as a gitlab-CI
diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
index 0e3ad25..477ff9e 100644
--- a/docs/specs/spdm.rst
+++ b/docs/specs/spdm.rst
@@ -98,7 +98,7 @@
.. code-block:: shell
-drive file=blknvme,if=none,id=mynvme,format=raw \
- -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
At which point QEMU will try to connect to the SPDM server.
@@ -113,7 +113,13 @@
-append "root=/dev/vda console=ttyS0" \
-net none -nographic \
-drive file=blknvme,if=none,id=mynvme,format=raw \
- -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe
+
+The ``spdm_trans`` argument defines the underlying transport type that is
+emulated by QEMU. For an PCIe NVMe controller, both "doe" and "nvme" are
+supported. Where, "doe" does SPDM transport over the PCIe extended capability
+Data Object Exchange (DOE), and "nvme" uses the NVMe Admin Security
+Send/Receive commands to implement the SPDM transport.
.. _DMTF:
https://www.dmtf.org/standards/SPDM
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 5e7b850..558b0eb 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -503,7 +503,7 @@
The size syntax is similar to :manpage:`dd(1)`'s size syntax.
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
Give information about the disk image *FILENAME*. Use it in
particular to know the size reserved on disk which can be different
@@ -571,6 +571,10 @@
``ImageInfoSpecific*`` QAPI object (e.g. ``ImageInfoSpecificQCow2``
for qcow2 images).
+ *Block limits*
+ The block limits for I/O that QEMU detected for the image.
+ This information is only shown if the ``--limits`` option was specified.
+
.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME
Dump the metadata of image *FILENAME* and its backing file chain.
diff --git a/gdbstub/syscalls.c b/gdbstub/syscalls.c
index e855df2..d8bb90c 100644
--- a/gdbstub/syscalls.c
+++ b/gdbstub/syscalls.c
@@ -127,7 +127,7 @@
case 's':
i64 = va_arg(va, uint64_t);
i32 = va_arg(va, uint32_t);
- p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);
+ p += snprintf(p, p_end - p, "%" PRIx64 "/%" PRIx32, i64, i32);
break;
default:
bad_format:
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 1bc9e53..ecc7272 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -15,6 +15,7 @@
#include "hw/arm/aspeed.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/arm/aspeed_eeprom.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "hw/i2c/i2c_mux_pca954x.h"
#include "hw/i2c/smbus_eeprom.h"
@@ -1967,99 +1968,123 @@
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_palmetto_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("supermicrox11-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_supermicrox11_bmc_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("supermicro-x11spi-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_supermicro_x11spi_bmc_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("ast2500-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2500_evb_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("romulus-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_romulus_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("sonorapass-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_sonorapass_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_witherspoon_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("ast2600-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2600_evb_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("yosemitev2-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_yosemitev2_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("tiogapass-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_tiogapass_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("g220a-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_g220a_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("qcom-dc-scm-v1-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_qcom_dc_scm_v1_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("qcom-firework-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_qcom_firework_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("fp5280g2-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_fp5280g2_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("quanta-q71l-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_quanta_q71l_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("rainier-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_rainier_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("fuji-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_fuji_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("bletchley-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_bletchley_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("gb200nvl-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_gb200nvl_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("catalina-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_catalina_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("fby35-bmc"),
.parent = MACHINE_TYPE_NAME("ast2600-evb"),
.class_init = aspeed_machine_fby35_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("ast1030-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_minibmc_machine_ast1030_evb_class_init,
+ .interfaces = arm_machine_interfaces,
#ifdef TARGET_AARCH64
}, {
.name = MACHINE_TYPE_NAME("ast2700a0-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2700a0_evb_class_init,
- }, {
+ .interfaces = aarch64_machine_interfaces,
+ }, {
.name = MACHINE_TYPE_NAME("ast2700a1-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2700a1_evb_class_init,
+ .interfaces = aarch64_machine_interfaces,
#endif
}, {
.name = TYPE_ASPEED_MACHINE,
diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c
index 580ac5f..b96ef3f 100644
--- a/hw/arm/aspeed_ast27x0-fc.c
+++ b/hw/arm/aspeed_ast27x0-fc.c
@@ -22,6 +22,7 @@
#include "hw/arm/boot.h"
#include "hw/block/flash.h"
#include "hw/arm/aspeed_coprocessor.h"
+#include "hw/arm/machines-qom.h"
#define TYPE_AST2700A1FC MACHINE_TYPE_NAME("ast2700fc")
OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700A1FC);
@@ -220,6 +221,7 @@
.parent = TYPE_MACHINE,
.class_init = ast2700fc_class_init,
.instance_size = sizeof(Ast2700FCState),
+ .interfaces = aarch64_machine_interfaces,
},
};
diff --git a/hw/arm/b-l475e-iot01a.c b/hw/arm/b-l475e-iot01a.c
index 34ed2e0..f1fbc77 100644
--- a/hw/arm/b-l475e-iot01a.c
+++ b/hw/arm/b-l475e-iot01a.c
@@ -29,6 +29,7 @@
#include "qemu/error-report.h"
#include "hw/arm/boot.h"
#include "hw/core/split-irq.h"
+#include "hw/arm/machines-qom.h"
#include "hw/arm/stm32l4x5_soc.h"
#include "hw/gpio/stm32l4x5_gpio.h"
#include "hw/display/dm163.h"
@@ -131,6 +132,7 @@
.parent = TYPE_MACHINE,
.instance_size = sizeof(Bl475eMachineState),
.class_init = bl475e_machine_init,
+ .interfaces = arm_machine_interfaces,
}
};
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
index b750a57..0f6d986 100644
--- a/hw/arm/bananapi_m2u.c
+++ b/hw/arm/bananapi_m2u.c
@@ -27,6 +27,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/allwinner-r40.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
static struct arm_boot_info bpim2u_binfo;
@@ -144,4 +145,4 @@
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("bpim2u", bpim2u_machine_init)
+DEFINE_MACHINE_ARM("bpim2u", bpim2u_machine_init)
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index 93bb190..5a80b7a 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -15,6 +15,7 @@
#include "hw/boards.h"
#include "strongarm.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "system/address-spaces.h"
#include "qom/object.h"
@@ -86,6 +87,7 @@
.parent = TYPE_MACHINE,
.class_init = collie_machine_class_init,
.instance_size = sizeof(CollieMachineState),
+ .interfaces = arm_machine_interfaces,
};
static void collie_machine_register_types(void)
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
index d665d4e..aa51c0a 100644
--- a/hw/arm/cubieboard.c
+++ b/hw/arm/cubieboard.c
@@ -22,6 +22,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/allwinner-a10.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/i2c/i2c.h"
static struct arm_boot_info cubieboard_binfo = {
@@ -125,4 +126,4 @@
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("cubieboard", cubieboard_machine_init)
+DEFINE_MACHINE_ARM("cubieboard", cubieboard_machine_init)
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
index de56991..23b596d 100644
--- a/hw/arm/digic_boards.c
+++ b/hw/arm/digic_boards.c
@@ -29,6 +29,7 @@
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "hw/arm/digic.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "hw/loader.h"
#include "system/qtest.h"
@@ -145,4 +146,4 @@
mc->default_ram_id = "ram";
}
-DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init)
+DEFINE_MACHINE_ARM("canon-a1100", canon_a1100_machine_init)
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 7304974..89f0e94 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -28,6 +28,7 @@
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "system/address-spaces.h"
#include "hw/arm/exynos4210.h"
#include "hw/net/lan9118.h"
@@ -172,6 +173,7 @@
.name = MACHINE_TYPE_NAME("nuri"),
.parent = TYPE_MACHINE,
.class_init = nuri_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void smdkc210_class_init(ObjectClass *oc, const void *data)
@@ -192,6 +194,7 @@
.name = MACHINE_TYPE_NAME("smdkc210"),
.parent = TYPE_MACHINE,
.class_init = smdkc210_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void exynos4_machines_init(void)
diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c
index 5a94c84..70d3a99 100644
--- a/hw/arm/fby35.c
+++ b/hw/arm/fby35.c
@@ -14,6 +14,7 @@
#include "hw/qdev-clock.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#define TYPE_FBY35 MACHINE_TYPE_NAME("fby35")
OBJECT_DECLARE_SIMPLE_TYPE(Fby35State, FBY35);
@@ -194,6 +195,7 @@
.class_init = fby35_class_init,
.instance_size = sizeof(Fby35State),
.instance_init = fby35_instance_init,
+ .interfaces = arm_machine_interfaces,
},
};
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index ff98746..bd60ab2 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -23,6 +23,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/loader.h"
#include "net/net.h"
#include "system/runstate.h"
@@ -365,6 +366,7 @@
.name = MACHINE_TYPE_NAME("highbank"),
.parent = TYPE_MACHINE,
.class_init = highbank_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void midway_class_init(ObjectClass *oc, const void *data)
@@ -390,6 +392,7 @@
.name = MACHINE_TYPE_NAME("midway"),
.parent = TYPE_MACHINE,
.class_init = midway_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void calxeda_machines_init(void)
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
index e95ea5e..71a4606 100644
--- a/hw/arm/imx25_pdk.c
+++ b/hw/arm/imx25_pdk.c
@@ -28,6 +28,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/fsl-imx25.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "system/qtest.h"
@@ -150,4 +151,4 @@
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init)
+DEFINE_MACHINE_ARM("imx25-pdk", imx25_pdk_machine_init)
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
index b3082fa..fc880a1 100644
--- a/hw/arm/imx8mp-evk.c
+++ b/hw/arm/imx8mp-evk.c
@@ -10,6 +10,7 @@
#include "system/address-spaces.h"
#include "hw/arm/boot.h"
#include "hw/arm/fsl-imx8mp.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "system/qtest.h"
@@ -100,4 +101,5 @@
mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
mc->default_ram_id = "imx8mp-evk.ram";
}
-DEFINE_MACHINE("imx8mp-evk", imx8mp_evk_machine_init)
+
+DEFINE_MACHINE_AARCH64("imx8mp-evk", imx8mp_evk_machine_init)
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index b1d8fbd..031380a 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -13,6 +13,7 @@
#include "migration/vmstate.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/misc/arm_integrator_debug.h"
#include "hw/net/smc91c111.h"
#include "net/net.h"
@@ -693,7 +694,7 @@
machine_add_audiodev_property(mc);
}
-DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
+DEFINE_MACHINE_ARM("integratorcp", integratorcp_machine_init)
static const Property core_properties[] = {
DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 362c145..b446dc1 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -17,6 +17,7 @@
#include "qapi/error.h"
#include "hw/arm/fsl-imx31.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "system/address-spaces.h"
@@ -139,4 +140,4 @@
mc->default_ram_id = "kzm.ram";
}
-DEFINE_MACHINE("kzm", kzm_machine_init)
+DEFINE_MACHINE_ARM("kzm", kzm_machine_init)
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
index 86982cb..f47a265 100644
--- a/hw/arm/mcimx6ul-evk.c
+++ b/hw/arm/mcimx6ul-evk.c
@@ -14,6 +14,7 @@
#include "qapi/error.h"
#include "hw/arm/fsl-imx6ul.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
@@ -76,4 +77,5 @@
mc->default_ram_id = "mcimx6ul-evk.ram";
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("mcimx6ul-evk", mcimx6ul_evk_machine_init)
+
+DEFINE_MACHINE_ARM("mcimx6ul-evk", mcimx6ul_evk_machine_init)
diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
index 3311961..fc8f35c 100644
--- a/hw/arm/mcimx7d-sabre.c
+++ b/hw/arm/mcimx7d-sabre.c
@@ -16,6 +16,7 @@
#include "qapi/error.h"
#include "hw/arm/fsl-imx7.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
@@ -76,4 +77,5 @@
mc->default_ram_id = "mcimx7d-sabre.ram";
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("mcimx7d-sabre", mcimx7d_sabre_machine_init)
+
+DEFINE_MACHINE_ARM("mcimx7d-sabre", mcimx7d_sabre_machine_init)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index b88b5b0..61c66ee 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -1,7 +1,7 @@
arm_ss = ss.source_set()
arm_common_ss = ss.source_set()
-arm_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c'))
-arm_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
+arm_common_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c'))
+arm_common_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
arm_common_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c'))
arm_common_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c'))
arm_common_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
@@ -14,7 +14,7 @@
arm_common_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
arm_common_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm8xx.c', 'npcm8xx_boards.c'))
arm_common_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
-arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
+arm_common_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
arm_common_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
arm_common_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
arm_common_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c'))
@@ -65,7 +65,7 @@
arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_common_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_common_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
-arm_ss.add(when: 'CONFIG_XEN', if_true: files(
+arm_common_ss.add(when: 'CONFIG_XEN', if_true: files(
'xen-stubs.c',
'xen-pvh.c',
))
diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c
index 525443f..0f3161f 100644
--- a/hw/arm/microbit.c
+++ b/hw/arm/microbit.c
@@ -12,6 +12,7 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "system/system.h"
#include "system/address-spaces.h"
@@ -74,6 +75,7 @@
.parent = TYPE_MACHINE,
.instance_size = sizeof(MicrobitMachineState),
.class_init = microbit_machine_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void microbit_machine_init(void)
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 5dd87cc..55dd68c 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -52,6 +52,7 @@
#include "qemu/error-report.h"
#include "hw/arm/boot.h"
#include "hw/arm/armv7m.h"
+#include "hw/arm/machines-qom.h"
#include "hw/or-irq.h"
#include "hw/boards.h"
#include "system/address-spaces.h"
@@ -1463,24 +1464,28 @@
.name = TYPE_MPS2TZ_AN505_MACHINE,
.parent = TYPE_MPS2TZ_MACHINE,
.class_init = mps2tz_an505_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps2tz_an521_info = {
.name = TYPE_MPS2TZ_AN521_MACHINE,
.parent = TYPE_MPS2TZ_MACHINE,
.class_init = mps2tz_an521_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps3tz_an524_info = {
.name = TYPE_MPS3TZ_AN524_MACHINE,
.parent = TYPE_MPS2TZ_MACHINE,
.class_init = mps3tz_an524_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps3tz_an547_info = {
.name = TYPE_MPS3TZ_AN547_MACHINE,
.parent = TYPE_MPS2TZ_MACHINE,
.class_init = mps3tz_an547_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void mps2tz_machine_init(void)
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index bd378e3..fa4b200 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "hw/arm/boot.h"
#include "hw/arm/armv7m.h"
+#include "hw/arm/machines-qom.h"
#include "hw/or-irq.h"
#include "hw/boards.h"
#include "system/address-spaces.h"
@@ -567,24 +568,28 @@
.name = TYPE_MPS2_AN385_MACHINE,
.parent = TYPE_MPS2_MACHINE,
.class_init = mps2_an385_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps2_an386_info = {
.name = TYPE_MPS2_AN386_MACHINE,
.parent = TYPE_MPS2_MACHINE,
.class_init = mps2_an386_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps2_an500_info = {
.name = TYPE_MPS2_AN500_MACHINE,
.parent = TYPE_MPS2_MACHINE,
.class_init = mps2_an500_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo mps2_an511_info = {
.name = TYPE_MPS2_AN511_MACHINE,
.parent = TYPE_MPS2_MACHINE,
.class_init = mps2_an511_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void mps2_machine_init(void)
diff --git a/hw/arm/mps3r.c b/hw/arm/mps3r.c
index 48c73ac..fcb8777 100644
--- a/hw/arm/mps3r.c
+++ b/hw/arm/mps3r.c
@@ -37,6 +37,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/boot.h"
#include "hw/arm/bsa.h"
+#include "hw/arm/machines-qom.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/intc/arm_gicv3.h"
@@ -634,6 +635,7 @@
.name = TYPE_MPS3R_AN536_MACHINE,
.parent = TYPE_MPS3R_MACHINE,
.class_init = mps3r_an536_class_init,
+ .interfaces = arm_machine_interfaces,
},
};
diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
index 29c76c6..c26fecc 100644
--- a/hw/arm/msf2-som.c
+++ b/hw/arm/msf2-som.c
@@ -32,6 +32,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/qdev-clock.h"
#include "system/address-spaces.h"
#include "hw/arm/msf2-soc.h"
@@ -108,4 +109,4 @@
mc->valid_cpu_types = valid_cpu_types;
}
-DEFINE_MACHINE("emcraft-sf2", emcraft_sf2_machine_init)
+DEFINE_MACHINE_ARM("emcraft-sf2", emcraft_sf2_machine_init)
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
index 250b3b5..a3494c9 100644
--- a/hw/arm/musca.c
+++ b/hw/arm/musca.c
@@ -26,6 +26,7 @@
#include "system/system.h"
#include "hw/arm/boot.h"
#include "hw/arm/armsse.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/char/pl011.h"
#include "hw/core/split-irq.h"
@@ -657,12 +658,14 @@
.name = TYPE_MUSCA_A_MACHINE,
.parent = TYPE_MUSCA_MACHINE,
.class_init = musca_a_class_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo musca_b1_info = {
.name = TYPE_MUSCA_B1_MACHINE,
.parent = TYPE_MUSCA_MACHINE,
.class_init = musca_b1_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void musca_machine_init(void)
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 329b162..1ae7cbd 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -15,6 +15,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "net/net.h"
#include "system/system.h"
#include "hw/boards.h"
@@ -1346,7 +1347,7 @@
machine_add_audiodev_property(mc);
}
-DEFINE_MACHINE("musicpal", musicpal_machine_init)
+DEFINE_MACHINE_ARM("musicpal", musicpal_machine_init)
static void mv88w8618_wlan_class_init(ObjectClass *klass, const void *data)
{
diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
index df793c7..bce0d6f 100644
--- a/hw/arm/netduino2.c
+++ b/hw/arm/netduino2.c
@@ -30,6 +30,7 @@
#include "qemu/error-report.h"
#include "hw/arm/stm32f205_soc.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
/* Main SYSCLK frequency in Hz (120MHz) */
#define SYSCLK_FRQ 120000000ULL
@@ -65,4 +66,4 @@
mc->ignore_memory_transaction_failures = true;
}
-DEFINE_MACHINE("netduino2", netduino2_machine_init)
+DEFINE_MACHINE_ARM("netduino2", netduino2_machine_init)
diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c
index 81b6334..8594081 100644
--- a/hw/arm/netduinoplus2.c
+++ b/hw/arm/netduinoplus2.c
@@ -30,6 +30,7 @@
#include "qemu/error-report.h"
#include "hw/arm/stm32f405_soc.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
/* Main SYSCLK frequency in Hz (168MHz) */
#define SYSCLK_FRQ 168000000ULL
@@ -65,4 +66,4 @@
mc->valid_cpu_types = valid_cpu_types;
}
-DEFINE_MACHINE("netduinoplus2", netduinoplus2_machine_init)
+DEFINE_MACHINE_ARM("netduinoplus2", netduinoplus2_machine_init)
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
index 465a0e5..c1e100b 100644
--- a/hw/arm/npcm7xx_boards.c
+++ b/hw/arm/npcm7xx_boards.c
@@ -17,6 +17,7 @@
#include "qemu/osdep.h"
#include "hw/arm/npcm7xx.h"
+#include "hw/arm/machines-qom.h"
#include "hw/core/cpu.h"
#include "hw/i2c/i2c_mux_pca954x.h"
#include "hw/i2c/smbus_eeprom.h"
@@ -549,22 +550,27 @@
.name = MACHINE_TYPE_NAME("npcm750-evb"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = npcm750_evb_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("quanta-gsj"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = gsj_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("quanta-gbs-bmc"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = gbs_bmc_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("kudo-bmc"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = kudo_bmc_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("mori-bmc"),
.parent = TYPE_NPCM7XX_MACHINE,
.class_init = mori_bmc_machine_class_init,
+ .interfaces = arm_machine_interfaces,
},
};
diff --git a/hw/arm/npcm8xx_boards.c b/hw/arm/npcm8xx_boards.c
index 3bf3e1f..b179ead 100644
--- a/hw/arm/npcm8xx_boards.c
+++ b/hw/arm/npcm8xx_boards.c
@@ -19,6 +19,7 @@
#include "chardev/char.h"
#include "hw/boards.h"
#include "hw/arm/npcm8xx.h"
+#include "hw/arm/machines-qom.h"
#include "hw/core/cpu.h"
#include "hw/loader.h"
#include "hw/qdev-core.h"
@@ -248,6 +249,7 @@
.name = MACHINE_TYPE_NAME("npcm845-evb"),
.parent = TYPE_NPCM8XX_MACHINE,
.class_init = npcm845_evb_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
},
};
diff --git a/hw/arm/olimex-stm32-h405.c b/hw/arm/olimex-stm32-h405.c
index 1f15620..c5f6038 100644
--- a/hw/arm/olimex-stm32-h405.c
+++ b/hw/arm/olimex-stm32-h405.c
@@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "hw/arm/stm32f405_soc.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
/* olimex-stm32-h405 implementation is derived from netduinoplus2 */
@@ -71,4 +72,4 @@
mc->default_ram_size = 0;
}
-DEFINE_MACHINE("olimex-stm32-h405", olimex_stm32_h405_machine_init)
+DEFINE_MACHINE_ARM("olimex-stm32-h405", olimex_stm32_h405_machine_init)
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 5d4a31b..730525b 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -32,6 +32,7 @@
#include "hw/arm/omap.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "system/qtest.h"
#include "system/address-spaces.h"
@@ -219,6 +220,7 @@
.name = MACHINE_TYPE_NAME("sx1"),
.parent = TYPE_MACHINE,
.class_init = sx1_machine_v2_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void sx1_machine_v1_class_init(ObjectClass *oc, const void *data)
@@ -238,6 +240,7 @@
.name = MACHINE_TYPE_NAME("sx1-v1"),
.parent = TYPE_MACHINE,
.class_init = sx1_machine_v1_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void sx1_machine_init(void)
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index e095688..3e237e7 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -26,6 +26,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/allwinner-h3.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
static struct arm_boot_info orangepi_binfo;
@@ -124,4 +125,4 @@
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("orangepi-pc", orangepi_machine_init)
+DEFINE_MACHINE_ARM("orangepi-pc", orangepi_machine_init)
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index fbf3e09..81d2fa1 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -25,6 +25,7 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "qom/object.h"
#define TYPE_RASPI_MACHINE MACHINE_TYPE_NAME("raspi-common")
@@ -394,23 +395,28 @@
.name = MACHINE_TYPE_NAME("raspi0"),
.parent = TYPE_RASPI_MACHINE,
.class_init = raspi0_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("raspi1ap"),
.parent = TYPE_RASPI_MACHINE,
.class_init = raspi1ap_machine_class_init,
+ .interfaces = arm_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("raspi2b"),
.parent = TYPE_RASPI_MACHINE,
.class_init = raspi2b_machine_class_init,
+ .interfaces = arm_machine_interfaces,
#ifdef TARGET_AARCH64
}, {
.name = MACHINE_TYPE_NAME("raspi3ap"),
.parent = TYPE_RASPI_MACHINE,
.class_init = raspi3ap_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
}, {
.name = MACHINE_TYPE_NAME("raspi3b"),
.parent = TYPE_RASPI_MACHINE,
.class_init = raspi3b_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
#endif
}, {
.name = TYPE_RASPI_MACHINE,
diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c
index 4df951a..0422ae0 100644
--- a/hw/arm/raspi4b.c
+++ b/hw/arm/raspi4b.c
@@ -11,6 +11,7 @@
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
+#include "hw/arm/machines-qom.h"
#include "hw/arm/raspi_platform.h"
#include "hw/display/bcm2835_fb.h"
#include "hw/registerfields.h"
@@ -123,6 +124,7 @@
.parent = TYPE_RASPI_BASE_MACHINE,
.instance_size = sizeof(Raspi4bMachineState),
.class_init = raspi4b_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
};
static void raspi4b_machine_register_type(void)
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index 5c90504..b940cbf 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -13,6 +13,7 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/machines-qom.h"
#include "hw/core/split-irq.h"
#include "hw/net/lan9118.h"
#include "hw/net/smc91c111.h"
@@ -431,6 +432,7 @@
.name = MACHINE_TYPE_NAME("realview-eb"),
.parent = TYPE_MACHINE,
.class_init = realview_eb_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void realview_eb_mpcore_class_init(ObjectClass *oc, const void *data)
@@ -452,6 +454,7 @@
.name = MACHINE_TYPE_NAME("realview-eb-mpcore"),
.parent = TYPE_MACHINE,
.class_init = realview_eb_mpcore_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void realview_pb_a8_class_init(ObjectClass *oc, const void *data)
@@ -471,6 +474,7 @@
.name = MACHINE_TYPE_NAME("realview-pb-a8"),
.parent = TYPE_MACHINE,
.class_init = realview_pb_a8_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void realview_pbx_a9_class_init(ObjectClass *oc, const void *data)
@@ -491,6 +495,7 @@
.name = MACHINE_TYPE_NAME("realview-pbx-a9"),
.parent = TYPE_MACHINE,
.class_init = realview_pbx_a9_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void realview_machine_init(void)
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index df60d47..5b4ab7d 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -14,6 +14,7 @@
#include "qapi/error.h"
#include "hw/arm/fsl-imx6.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
@@ -113,4 +114,4 @@
mc->auto_create_sdcard = true;
}
-DEFINE_MACHINE("sabrelite", sabrelite_machine_init)
+DEFINE_MACHINE_ARM("sabrelite", sabrelite_machine_init)
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 15c1ff4..2205500 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -35,6 +35,7 @@
#include "hw/arm/bsa.h"
#include "hw/arm/fdt.h"
#include "hw/arm/smmuv3.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "hw/boards.h"
#include "hw/ide/ide-bus.h"
@@ -51,6 +52,7 @@
#include "net/net.h"
#include "qobject/qlist.h"
#include "qom/object.h"
+#include "target/arm/cpu.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
@@ -922,6 +924,7 @@
.instance_init = sbsa_ref_instance_init,
.class_init = sbsa_ref_class_init,
.instance_size = sizeof(SBSAMachineState),
+ .interfaces = aarch64_machine_interfaces,
};
static void sbsa_ref_machine_init(void)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 031ea3a..8113bbd 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -15,6 +15,7 @@
#include "hw/sd/sd.h"
#include "hw/ssi/ssi.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "qemu/timer.h"
#include "hw/i2c/i2c.h"
#include "net/net.h"
@@ -1427,6 +1428,7 @@
.name = MACHINE_TYPE_NAME("lm3s811evb"),
.parent = TYPE_MACHINE,
.class_init = lm3s811evb_class_init,
+ .interfaces = arm_machine_interfaces,
};
/*
@@ -1448,6 +1450,7 @@
.name = MACHINE_TYPE_NAME("lm3s6965evb"),
.parent = TYPE_MACHINE,
.class_init = lm3s6965evb_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void stellaris_machine_init(void)
diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
index e6c1f5b..c11029f 100644
--- a/hw/arm/stm32vldiscovery.c
+++ b/hw/arm/stm32vldiscovery.c
@@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "hw/arm/stm32f100_soc.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
/* stm32vldiscovery implementation is derived from netduinoplus2 */
@@ -68,4 +69,4 @@
mc->valid_cpu_types = valid_cpu_types;
}
-DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
+DEFINE_MACHINE_ARM("stm32vldiscovery", stm32vldiscovery_machine_init)
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index 5cf1a70..6fc1e62 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -12,6 +12,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/net/smc91c111.h"
#include "net/net.h"
#include "system/system.h"
@@ -431,6 +432,7 @@
.name = MACHINE_TYPE_NAME("versatilepb"),
.parent = TYPE_MACHINE,
.class_init = versatilepb_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void versatileab_class_init(ObjectClass *oc, const void *data)
@@ -452,6 +454,7 @@
.name = MACHINE_TYPE_NAME("versatileab"),
.parent = TYPE_MACHINE,
.class_init = versatileab_class_init,
+ .interfaces = arm_machine_interfaces,
};
static void versatile_machine_init(void)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 60cd375..f30923a 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -27,6 +27,7 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/machines-qom.h"
#include "hw/net/lan9118.h"
#include "hw/i2c/i2c.h"
#include "net/net.h"
@@ -850,6 +851,7 @@
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a9_class_init,
.instance_init = vexpress_a9_instance_init,
+ .interfaces = arm_machine_interfaces,
};
static const TypeInfo vexpress_a15_info = {
@@ -857,6 +859,7 @@
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a15_class_init,
.instance_init = vexpress_a15_instance_init,
+ .interfaces = arm_machine_interfaces,
};
static void vexpress_machine_init(void)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 8bb6b60..200e2a1 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -62,6 +62,7 @@
#include "hw/acpi/ghes.h"
#include "hw/acpi/viot.h"
#include "hw/virtio/virtio-acpi.h"
+#include "target/arm/cpu.h"
#include "target/arm/multiprocessing.h"
#define ARM_SPI_BASE 32
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1750238..d07cfe1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -32,11 +32,13 @@
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qemu/option.h"
+#include "qemu/target-info.h"
#include "monitor/qdev.h"
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
#include "hw/arm/virt.h"
+#include "hw/arm/machines-qom.h"
#include "hw/block/flash.h"
#include "hw/display/ramfb.h"
#include "net/net.h"
@@ -127,6 +129,7 @@
.name = MACHINE_VER_TYPE_NAME("virt", __VA_ARGS__), \
.parent = TYPE_VIRT_MACHINE, \
.class_init = MACHINE_VER_SYM(class_init, virt, __VA_ARGS__), \
+ .interfaces = arm_aarch64_machine_interfaces, \
}; \
static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
{ \
@@ -3254,36 +3257,47 @@
return requested_ipa_size;
}
+static const char *virt_get_default_cpu_type(const MachineState *ms)
+{
+ return tcg_enabled() ? ARM_CPU_TYPE_NAME("cortex-a15")
+ : ARM_CPU_TYPE_NAME("max");
+}
+
+static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
+{
+ GPtrArray *vct = g_ptr_array_new_with_free_func(g_free);
+
+ if (tcg_enabled()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a7")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a15")));
+ }
+ if (tcg_enabled() && target_aarch64()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a35")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a55")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a72")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a76")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a710")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("a64fx")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-n1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-n2")));
+ }
+ if (target_aarch64()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a57")));
+ if (kvm_enabled() || hvf_enabled()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("host")));
+ }
+ }
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max")));
+
+ return vct;
+}
+
static void virt_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
- static const char * const valid_cpu_types[] = {
-#ifdef CONFIG_TCG
- ARM_CPU_TYPE_NAME("cortex-a7"),
- ARM_CPU_TYPE_NAME("cortex-a15"),
-#ifdef TARGET_AARCH64
- ARM_CPU_TYPE_NAME("cortex-a35"),
- ARM_CPU_TYPE_NAME("cortex-a55"),
- ARM_CPU_TYPE_NAME("cortex-a72"),
- ARM_CPU_TYPE_NAME("cortex-a76"),
- ARM_CPU_TYPE_NAME("cortex-a710"),
- ARM_CPU_TYPE_NAME("a64fx"),
- ARM_CPU_TYPE_NAME("neoverse-n1"),
- ARM_CPU_TYPE_NAME("neoverse-v1"),
- ARM_CPU_TYPE_NAME("neoverse-n2"),
-#endif /* TARGET_AARCH64 */
-#endif /* CONFIG_TCG */
-#ifdef TARGET_AARCH64
- ARM_CPU_TYPE_NAME("cortex-a53"),
- ARM_CPU_TYPE_NAME("cortex-a57"),
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
- ARM_CPU_TYPE_NAME("host"),
-#endif /* CONFIG_KVM || CONFIG_HVF */
-#endif /* TARGET_AARCH64 */
- ARM_CPU_TYPE_NAME("max"),
- NULL
- };
mc->init = machvirt_init;
/* Start with max_cpus set to 512, which is the maximum supported by KVM.
@@ -3304,12 +3318,8 @@
mc->minimum_page_bits = 12;
mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
-#ifdef CONFIG_TCG
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
-#else
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
-#endif
- mc->valid_cpu_types = valid_cpu_types;
+ mc->get_default_cpu_type = virt_get_default_cpu_type;
+ mc->get_valid_cpu_types = virt_get_valid_cpu_types;
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
mc->hvf_get_physical_address_range = virt_hvf_get_physical_address_range;
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 0372cd0..c82edd3 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -20,6 +20,7 @@
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "net/net.h"
#include "system/system.h"
#include "hw/boards.h"
@@ -480,6 +481,7 @@
.parent = TYPE_MACHINE,
.class_init = zynq_machine_class_init,
.instance_size = sizeof(ZynqMachineState),
+ .interfaces = arm_machine_interfaces,
};
static void zynq_machine_register_types(void)
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 149b448..5e05521 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -21,6 +21,7 @@
#include "hw/arm/fdt.h"
#include "hw/arm/xlnx-versal.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "qom/object.h"
#include "target/arm/cpu.h"
@@ -401,12 +402,14 @@
.name = TYPE_XLNX_VERSAL_VIRT_MACHINE,
.parent = TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE,
.class_init = versal_virt_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
};
static const TypeInfo versal2_virt_machine_init_typeinfo = {
.name = TYPE_XLNX_VERSAL2_VIRT_MACHINE,
.parent = TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE,
.class_init = versal2_virt_machine_class_init,
+ .interfaces = aarch64_machine_interfaces,
};
static void versal_virt_machine_init_register_types(void)
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index 14b6641..330f375 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -19,6 +19,7 @@
#include "qapi/error.h"
#include "hw/arm/xlnx-zynqmp.h"
#include "hw/arm/boot.h"
+#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
@@ -303,6 +304,7 @@
.class_init = xlnx_zcu102_machine_class_init,
.instance_init = xlnx_zcu102_machine_instance_init,
.instance_size = sizeof(XlnxZCU102),
+ .interfaces = aarch64_machine_interfaces,
};
static void xlnx_zcu102_machine_init_register_types(void)
diff --git a/hw/block/block.c b/hw/block/block.c
index 2e10611..f187fa0 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -249,8 +249,11 @@
blk_set_enable_write_cache(blk, wce);
blk_set_on_error(blk, rerror, werror);
- block_acct_setup(blk_get_stats(blk), conf->account_invalid,
- conf->account_failed);
+ if (!block_acct_setup(blk_get_stats(blk), conf->account_invalid,
+ conf->account_failed, conf->stats_intervals,
+ conf->num_stats_intervals, errp)) {
+ return false;
+ }
return true;
}
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index a6e477a..67b769b 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -16,6 +16,7 @@
#include "hw/boards.h"
#include "system/address-spaces.h"
#include "hw/core/cpu.h"
+#include "hw/arm/machines-qom.h"
static void machine_none_init(MachineState *mch)
{
@@ -55,4 +56,7 @@
mc->no_cdrom = 1;
}
-DEFINE_MACHINE("none", machine_none_machine_init)
+DEFINE_MACHINE_WITH_INTERFACES("none", machine_none_machine_init,
+ { TYPE_TARGET_AARCH64_MACHINE },
+ { TYPE_TARGET_ARM_MACHINE },
+ { })
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index cd81f73..4d150c7 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -282,6 +282,8 @@
[NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_ADM_CMD_DIRECTIVE_RECV] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_DIRECTIVE_SEND] = NVME_CMD_EFF_CSUPP,
+ [NVME_ADM_CMD_SECURITY_SEND] = NVME_CMD_EFF_CSUPP,
+ [NVME_ADM_CMD_SECURITY_RECV] = NVME_CMD_EFF_CSUPP,
};
static const uint32_t nvme_cse_iocs_nvm_default[256] = {
@@ -6703,6 +6705,35 @@
} else {
atomic->atomic_writes = 1;
}
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
+ ns = nvme_ns(n, i);
+ if (ns && ns->atomic.atomic_writes) {
+ if (n->dn) {
+ ns->atomic.atomic_max_write_size =
+ le16_to_cpu(ns->id_ns.nawupf) + 1;
+ if (ns->id_ns.nabspf) {
+ ns->atomic.atomic_boundary =
+ le16_to_cpu(ns->id_ns.nabspf) + 1;
+ } else {
+ ns->atomic.atomic_boundary = 0;
+ }
+ } else {
+ ns->atomic.atomic_max_write_size =
+ le16_to_cpu(ns->id_ns.nawun) + 1;
+ if (ns->id_ns.nabsn) {
+ ns->atomic.atomic_boundary =
+ le16_to_cpu(ns->id_ns.nabsn) + 1;
+ } else {
+ ns->atomic.atomic_boundary = 0;
+ }
+ }
+ if (ns->atomic.atomic_max_write_size == 1) {
+ ns->atomic.atomic_writes = 0;
+ } else {
+ ns->atomic.atomic_writes = 1;
+ }
+ }
+ }
break;
default:
return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
@@ -7282,6 +7313,207 @@
return NVME_SUCCESS;
}
+static uint16_t nvme_sec_prot_spdm_send(NvmeCtrl *n, NvmeRequest *req)
+{
+ StorageSpdmTransportHeader hdr = {0};
+ g_autofree uint8_t *sec_buf = NULL;
+ uint32_t transfer_len = le32_to_cpu(req->cmd.cdw11);
+ uint32_t transport_transfer_len = transfer_len;
+ uint32_t dw10 = le32_to_cpu(req->cmd.cdw10);
+ uint32_t recvd;
+ uint16_t nvme_cmd_status, ret;
+ uint8_t secp = extract32(dw10, 24, 8);
+ uint16_t spsp = extract32(dw10, 8, 16);
+ bool spdm_res;
+
+ if (transport_transfer_len > UINT32_MAX - sizeof(hdr)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ transport_transfer_len += sizeof(hdr);
+ if (transport_transfer_len > SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ ret = nvme_check_mdts(n, transport_transfer_len);
+ if (ret != NVME_SUCCESS) {
+ return ret;
+ }
+
+ /* Generate the NVMe transport header */
+ hdr.security_protocol = secp;
+ hdr.security_protocol_specific = cpu_to_le16(spsp);
+ hdr.length = cpu_to_le32(transfer_len);
+
+ sec_buf = g_try_malloc0(transport_transfer_len);
+ if (!sec_buf) {
+ return NVME_INTERNAL_DEV_ERROR;
+ }
+
+ /* Attach the transport header */
+ memcpy(sec_buf, &hdr, sizeof(hdr));
+ ret = nvme_h2c(n, sec_buf + sizeof(hdr), transfer_len, req);
+ if (ret) {
+ return ret;
+ }
+
+ spdm_res = spdm_socket_send(n->spdm_socket, SPDM_SOCKET_STORAGE_CMD_IF_SEND,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME, sec_buf,
+ transport_transfer_len);
+ if (!spdm_res) {
+ return NVME_DATA_TRAS_ERROR | NVME_DNR;
+ }
+
+ /* The responder shall ack with message status */
+ recvd = spdm_socket_receive(n->spdm_socket, SPDM_SOCKET_TRANSPORT_TYPE_NVME,
+ &nvme_cmd_status,
+ SPDM_SOCKET_MAX_MSG_STATUS_LEN);
+
+ nvme_cmd_status = be16_to_cpu(nvme_cmd_status);
+
+ if (recvd < SPDM_SOCKET_MAX_MSG_STATUS_LEN) {
+ return NVME_DATA_TRAS_ERROR | NVME_DNR;
+ }
+
+ return nvme_cmd_status;
+}
+
+/* From host to controller */
+static uint16_t nvme_security_send(NvmeCtrl *n, NvmeRequest *req)
+{
+ uint32_t dw10 = le32_to_cpu(req->cmd.cdw10);
+ uint8_t secp = extract32(dw10, 24, 8);
+
+ switch (secp) {
+ case NVME_SEC_PROT_DMTF_SPDM:
+ if (n->spdm_socket < 0) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+ return nvme_sec_prot_spdm_send(n, req);
+ default:
+ /* Unsupported Security Protocol Type */
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ return NVME_INVALID_FIELD | NVME_DNR;
+}
+
+static uint16_t nvme_sec_prot_spdm_receive(NvmeCtrl *n, NvmeRequest *req)
+{
+ StorageSpdmTransportHeader hdr;
+ g_autofree uint8_t *rsp_spdm_buf = NULL;
+ uint32_t dw10 = le32_to_cpu(req->cmd.cdw10);
+ uint32_t alloc_len = le32_to_cpu(req->cmd.cdw11);
+ uint32_t recvd, spdm_res;
+ uint16_t nvme_cmd_status, ret;
+ uint8_t secp = extract32(dw10, 24, 8);
+ uint8_t spsp = extract32(dw10, 8, 16);
+ if (!alloc_len) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ /* Generate the NVMe transport header */
+ hdr = (StorageSpdmTransportHeader) {
+ .security_protocol = secp,
+ .security_protocol_specific = cpu_to_le16(spsp),
+ .length = cpu_to_le32(alloc_len),
+ };
+
+ /* Forward if_recv to the SPDM Server with SPSP0 */
+ spdm_res = spdm_socket_send(n->spdm_socket, SPDM_SOCKET_STORAGE_CMD_IF_RECV,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME,
+ &hdr, sizeof(hdr));
+ if (!spdm_res) {
+ return NVME_DATA_TRAS_ERROR | NVME_DNR;
+ }
+
+ /* The responder shall ack with message status */
+ recvd = spdm_socket_receive(n->spdm_socket, SPDM_SOCKET_TRANSPORT_TYPE_NVME,
+ &nvme_cmd_status,
+ SPDM_SOCKET_MAX_MSG_STATUS_LEN);
+ if (recvd < SPDM_SOCKET_MAX_MSG_STATUS_LEN) {
+ return NVME_DATA_TRAS_ERROR | NVME_DNR;
+ }
+
+ nvme_cmd_status = be16_to_cpu(nvme_cmd_status);
+ /* An error here implies the prior if_recv from requester was spurious */
+ if (nvme_cmd_status != NVME_SUCCESS) {
+ return nvme_cmd_status;
+ }
+
+ /* Clear to start receiving data from the server */
+ rsp_spdm_buf = g_try_malloc0(alloc_len);
+ if (!rsp_spdm_buf) {
+ return NVME_INTERNAL_DEV_ERROR;
+ }
+
+ recvd = spdm_socket_receive(n->spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME,
+ rsp_spdm_buf, alloc_len);
+ if (!recvd) {
+ return NVME_DATA_TRAS_ERROR | NVME_DNR;
+ }
+
+ ret = nvme_c2h(n, rsp_spdm_buf, MIN(recvd, alloc_len), req);
+ if (ret) {
+ return ret;
+ }
+
+ return NVME_SUCCESS;
+}
+
+static uint16_t nvme_get_sec_prot_info(NvmeCtrl *n, NvmeRequest *req)
+{
+ uint32_t alloc_len = le32_to_cpu(req->cmd.cdw11);
+ uint8_t resp[10] = {
+ /* Support Security Protol List Length */
+ [6] = 0, /* MSB */
+ [7] = 2, /* LSB */
+ /* Support Security Protocol List */
+ [8] = SFSC_SECURITY_PROT_INFO,
+ [9] = 0,
+ };
+
+ if (n->spdm_socket >= 0) {
+ resp[9] = NVME_SEC_PROT_DMTF_SPDM;
+ }
+
+ if (alloc_len < 10) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ return nvme_c2h(n, resp, sizeof(resp), req);
+}
+
+/* From controller to host */
+static uint16_t nvme_security_receive(NvmeCtrl *n, NvmeRequest *req)
+{
+ uint32_t dw10 = le32_to_cpu(req->cmd.cdw10);
+ uint16_t spsp = extract32(dw10, 8, 16);
+ uint8_t secp = extract32(dw10, 24, 8);
+
+ switch (secp) {
+ case SFSC_SECURITY_PROT_INFO:
+ switch (spsp) {
+ case 0:
+ /* Supported security protocol list */
+ return nvme_get_sec_prot_info(n, req);
+ case 1:
+ /* Certificate data */
+ /* fallthrough */
+ default:
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+ case NVME_SEC_PROT_DMTF_SPDM:
+ if (n->spdm_socket < 0) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+ return nvme_sec_prot_spdm_receive(n, req);
+ default:
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+}
+
static uint16_t nvme_directive_send(NvmeCtrl *n, NvmeRequest *req)
{
return NVME_INVALID_FIELD | NVME_DNR;
@@ -7389,6 +7621,10 @@
return nvme_directive_send(n, req);
case NVME_ADM_CMD_DIRECTIVE_RECV:
return nvme_directive_receive(n, req);
+ case NVME_ADM_CMD_SECURITY_SEND:
+ return nvme_security_send(n, req);
+ case NVME_ADM_CMD_SECURITY_RECV:
+ return nvme_security_receive(n, req);
default:
g_assert_not_reached();
}
@@ -7412,6 +7648,36 @@
trace_pci_nvme_update_sq_tail(sq->sqid, sq->tail);
}
+static int nvme_atomic_boundary_check(NvmeCtrl *n, NvmeCmd *cmd,
+ NvmeAtomic *atomic)
+{
+ NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
+
+ if (atomic->atomic_boundary) {
+ uint64_t slba = le64_to_cpu(rw->slba);
+ uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb);
+ uint64_t elba = slba + nlb;
+ uint64_t imask;
+
+ if ((slba < atomic->atomic_nabo) || (elba < atomic->atomic_nabo)) {
+ return 0;
+ }
+
+ /* Update slba/elba based on boundary offset */
+ slba = slba - atomic->atomic_nabo;
+ elba = slba + nlb;
+
+ imask = ~(atomic->atomic_boundary - 1);
+ if ((slba & imask) != (elba & imask)) {
+ if (n->atomic.atomic_max_write_size &&
+ ((nlb + 1) <= n->atomic.atomic_max_write_size)) {
+ return 1;
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
#define NVME_ATOMIC_NO_START 0
#define NVME_ATOMIC_START_ATOMIC 1
#define NVME_ATOMIC_START_NONATOMIC 2
@@ -7432,6 +7698,15 @@
}
/*
+ * Check if a write crosses an atomic boundary.
+ */
+ if (cmd->opcode == NVME_CMD_WRITE) {
+ if (!nvme_atomic_boundary_check(n, cmd, atomic)) {
+ cmd_atomic_wr = false;
+ }
+ }
+
+ /*
* Walk the queues to see if there are any atomic conflicts.
*/
for (i = 1; i < n->params.max_ioqpairs + 1; i++) {
@@ -7481,6 +7756,12 @@
static NvmeAtomic *nvme_get_atomic(NvmeCtrl *n, NvmeCmd *cmd)
{
+ NvmeNamespace *ns = nvme_ns(n, cmd->nsid);
+
+ if (ns && ns->atomic.atomic_writes) {
+ return &ns->atomic;
+ }
+
if (n->atomic.atomic_writes) {
return &n->atomic;
}
@@ -8459,6 +8740,8 @@
sctrl->vfn = cpu_to_le16(i + 1);
}
+ n->spdm_socket = -1;
+
cap->cntlid = cpu_to_le16(n->cntlid);
cap->crt = NVME_CRT_VQ | NVME_CRT_VI;
@@ -8509,6 +8792,8 @@
} else {
atomic->atomic_writes = 1;
}
+ atomic->atomic_boundary = 0;
+ atomic->atomic_nabo = 0;
}
}
@@ -8734,19 +9019,33 @@
pcie_cap_deverr_init(pci_dev);
- /* DOE Initialisation */
+ /* SPDM Initialisation */
if (pci_dev->spdm_port) {
- uint16_t doe_offset = n->params.sriov_max_vfs ?
- PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
- : PCI_CONFIG_SPACE_SIZE;
+ uint16_t doe_offset = PCI_CONFIG_SPACE_SIZE;
- pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
- doe_spdm_prot, true, 0);
+ switch (pci_dev->spdm_trans) {
+ case SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE:
+ if (n->params.sriov_max_vfs) {
+ doe_offset += PCI_ARI_SIZEOF;
+ }
- pci_dev->doe_spdm.spdm_socket = spdm_socket_connect(pci_dev->spdm_port,
- errp);
+ pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
+ doe_spdm_prot, true, 0);
- if (pci_dev->doe_spdm.spdm_socket < 0) {
+ pci_dev->doe_spdm.spdm_socket =
+ spdm_socket_connect(pci_dev->spdm_port, errp);
+
+ if (pci_dev->doe_spdm.spdm_socket < 0) {
+ return false;
+ }
+ break;
+ case SPDM_SOCKET_TRANSPORT_TYPE_NVME:
+ n->spdm_socket = spdm_socket_connect(pci_dev->spdm_port, errp);
+ if (n->spdm_socket < 0) {
+ return false;
+ }
+ break;
+ default:
return false;
}
}
@@ -8820,7 +9119,8 @@
id->mdts = n->params.mdts;
id->ver = cpu_to_le32(NVME_SPEC_VER);
- oacs = NVME_OACS_NMS | NVME_OACS_FORMAT | NVME_OACS_DIRECTIVES;
+ oacs = NVME_OACS_NMS | NVME_OACS_FORMAT | NVME_OACS_DIRECTIVES |
+ NVME_OACS_SECURITY;
if (n->params.dbcs) {
oacs |= NVME_OACS_DBCS;
@@ -9036,9 +9336,14 @@
g_free(n->cmb.buf);
}
+ /* Only one of the `spdm_socket`s below should have been setup */
+ assert(!(pci_dev->doe_spdm.spdm_socket > 0 && n->spdm_socket >= 0));
if (pci_dev->doe_spdm.spdm_socket > 0) {
spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE);
+ } else if (n->spdm_socket >= 0) {
+ spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME);
}
if (n->pmr.dev) {
@@ -9093,6 +9398,8 @@
false),
DEFINE_PROP_UINT16("mqes", NvmeCtrl, params.mqes, 0x7ff),
DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
+ DEFINE_PROP_SPDM_TRANS("spdm_trans", PCIDevice, spdm_trans,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE),
DEFINE_PROP_BOOL("ctratt.mem", NvmeCtrl, params.ctratt.mem, false),
DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0),
DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0),
@@ -9168,7 +9475,9 @@
{
uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
- if (pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+ /* DOE is only initialised if SPDM over DOE is used */
+ if (pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE) &&
+ dev->spdm_trans == SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE) {
pcie_doe_write_config(&dev->doe_spdm, address, val, len);
}
pci_default_write_config(dev, address, val, len);
@@ -9179,7 +9488,9 @@
static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t address, int len)
{
uint32_t val;
- if (dev->spdm_port && pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+
+ if (dev->spdm_port && pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE) &&
+ (dev->spdm_trans == SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE)) {
if (pcie_doe_read_config(&dev->doe_spdm, address, len, &val)) {
return val;
}
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 6df2e8e..86f5ab0 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -724,11 +724,79 @@
BusState *s = qdev_get_parent_bus(dev);
NvmeCtrl *n = NVME(s->parent);
NvmeSubsystem *subsys = n->subsys;
+ NvmeIdCtrl *id = &n->id_ctrl;
+ NvmeIdNs *id_ns = &ns->id_ns;
uint32_t nsid = ns->params.nsid;
int i;
assert(subsys);
+ /* Set atomic write parameters */
+ if (ns->params.atomic_nsfeat) {
+ id_ns->nsfeat |= NVME_ID_NS_NSFEAT_NSABPNS;
+ id_ns->nawun = cpu_to_le16(ns->params.atomic_nawun);
+ if (!id->awupf || (id_ns->nawun && (id_ns->nawun < id->awun))) {
+ error_report("Invalid NAWUN: %x AWUN=%x", id_ns->nawun, id->awun);
+ }
+ id_ns->nawupf = cpu_to_le16(ns->params.atomic_nawupf);
+ if (!id->awupf || (id_ns->nawupf && (id_ns->nawupf < id->awupf))) {
+ error_report("Invalid NAWUPF: %x AWUPF=%x",
+ id_ns->nawupf, id->awupf);
+ }
+ if (id_ns->nawupf > id_ns->nawun) {
+ error_report("Invalid: NAWUN=%x NAWUPF=%x",
+ id_ns->nawun, id_ns->nawupf);
+ }
+ id_ns->nabsn = cpu_to_le16(ns->params.atomic_nabsn);
+ id_ns->nabspf = cpu_to_le16(ns->params.atomic_nabspf);
+ id_ns->nabo = cpu_to_le16(ns->params.atomic_nabo);
+ if (!id->awun || (id_ns->nabsn && ((id_ns->nabsn < id_ns->nawun) ||
+ (id_ns->nabsn < id->awun)))) {
+ error_report("Invalid NABSN: %x NAWUN=%x AWUN=%x",
+ id_ns->nabsn, id_ns->nawun, id->awun);
+ }
+ if (!id->awupf || (id_ns->nabspf && ((id_ns->nabspf < id_ns->nawupf) ||
+ (id_ns->nawupf < id->awupf)))) {
+ error_report("Invalid NABSPF: %x NAWUPF=%x AWUPF=%x",
+ id_ns->nabspf, id_ns->nawupf, id->awupf);
+ }
+ if (id_ns->nabo && ((id_ns->nabo > id_ns->nabsn) ||
+ (id_ns->nabo > id_ns->nabspf))) {
+ error_report("Invalid NABO: %x NABSN=%x NABSPF=%x",
+ id_ns->nabo, id_ns->nabsn, id_ns->nabspf);
+ }
+ if (id_ns->nawupf > id_ns->nawun) {
+ error_report("Invalid: NAWUN=%x NAWUPF=%x", id_ns->nawun,
+ id_ns->nawupf);
+ }
+ }
+
+ if (id_ns->nawun || id_ns->nawupf) {
+ NvmeAtomic *atomic = &ns->atomic;
+
+ if (n->dn) {
+ atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawupf) + 1;
+ if (id_ns->nabspf) {
+ atomic->atomic_boundary = cpu_to_le16(id_ns->nabspf) + 1;
+ } else {
+ atomic->atomic_boundary = 0;
+ }
+ } else {
+ atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawun) + 1;
+ if (id_ns->nabsn) {
+ atomic->atomic_boundary = cpu_to_le16(id_ns->nabsn) + 1;
+ } else {
+ atomic->atomic_boundary = 0;
+ }
+ }
+ if (atomic->atomic_max_write_size == 1) {
+ atomic->atomic_writes = 0;
+ } else {
+ atomic->atomic_writes = 1;
+ }
+ atomic->atomic_nabo = cpu_to_le16(id_ns->nabo);
+ }
+
/* reparent to subsystem bus */
if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) {
return;
@@ -804,6 +872,12 @@
DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default,
false),
DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs),
+ DEFINE_PROP_UINT16("atomic.nawun", NvmeNamespace, params.atomic_nawun, 0),
+ DEFINE_PROP_UINT16("atomic.nawupf", NvmeNamespace, params.atomic_nawupf, 0),
+ DEFINE_PROP_UINT16("atomic.nabspf", NvmeNamespace, params.atomic_nabspf, 0),
+ DEFINE_PROP_UINT16("atomic.nabsn", NvmeNamespace, params.atomic_nabsn, 0),
+ DEFINE_PROP_UINT16("atomic.nabo", NvmeNamespace, params.atomic_nabo, 0),
+ DEFINE_PROP_BOOL("atomic.nsfeat", NvmeNamespace, params.atomic_nsfeat, 0),
};
static void nvme_ns_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index b5c9378..a7d225d 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -218,10 +218,18 @@
struct {
char *ruhs;
} fdp;
+ uint16_t atomic_nawun;
+ uint16_t atomic_nawupf;
+ uint16_t atomic_nabsn;
+ uint16_t atomic_nabspf;
+ uint16_t atomic_nabo;
+ bool atomic_nsfeat;
} NvmeNamespaceParams;
typedef struct NvmeAtomic {
uint32_t atomic_max_write_size;
+ uint64_t atomic_boundary;
+ uint64_t atomic_nabo;
bool atomic_writes;
} NvmeAtomic;
@@ -280,6 +288,12 @@
/* reclaim unit handle identifiers indexed by placement handle */
uint16_t *phs;
} fdp;
+ uint16_t atomic_nawun;
+ uint16_t atomic_nawupf;
+ uint16_t atomic_nabsn;
+ uint16_t atomic_nabspf;
+ uint16_t atomic_nabo;
+ NvmeAtomic atomic;
} NvmeNamespace;
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
@@ -461,6 +475,8 @@
case NVME_ADM_CMD_DIRECTIVE_RECV: return "NVME_ADM_CMD_DIRECTIVE_RECV";
case NVME_ADM_CMD_DBBUF_CONFIG: return "NVME_ADM_CMD_DBBUF_CONFIG";
case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM";
+ case NVME_ADM_CMD_SECURITY_SEND: return "NVME_ADM_CMD_SECURITY_SEND";
+ case NVME_ADM_CMD_SECURITY_RECV: return "NVME_ADM_CMD_SECURITY_RECV";
default: return "NVME_ADM_CMD_UNKNOWN";
}
}
@@ -648,6 +664,9 @@
} next_pri_ctrl_cap; /* These override pri_ctrl_cap after reset */
uint32_t dn; /* Disable Normal */
NvmeAtomic atomic;
+
+ /* Socket mapping to SPDM over NVMe Security In/Out commands */
+ int spdm_socket;
} NvmeCtrl;
typedef enum NvmeResetType {
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index b33c7fe..f8656ec 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -26,6 +26,8 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/timer.h"
+#include "qemu/target-info.h"
+#include "qemu/bitops.h"
#include "cpu_bits.h"
#include "riscv-iommu.h"
@@ -391,9 +393,9 @@
const uint64_t va_mask = (1ULL << va_len) - 1;
if (pass == S_STAGE && va_len > 32) {
- target_ulong mask, masked_msbs;
+ uint64_t mask, masked_msbs;
- mask = (1L << (TARGET_LONG_BITS - (va_len - 1))) - 1;
+ mask = MAKE_64BIT_MASK(0, target_long_bits() - va_len + 1);
masked_msbs = (addr >> (va_len - 1)) & mask;
if (masked_msbs != 0 && masked_msbs != mask) {
diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index 4d51a93..33cbc98 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -94,7 +94,7 @@
g_assert(rc == 0);
csr_call(words[1], cpu, csr, &val);
- qtest_sendf(chr, "OK 0 "TARGET_FMT_lx"\n", (target_ulong)val);
+ qtest_sendf(chr, "OK 0 %"PRIx64"\n", val);
return true;
}
diff --git a/hw/xen/meson.build b/hw/xen/meson.build
index a1850e7..dcd2b7e 100644
--- a/hw/xen/meson.build
+++ b/hw/xen/meson.build
@@ -7,21 +7,16 @@
'xen_pvdev.c',
))
-system_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
- 'xen-operations.c',
-),
-if_false: files(
- 'xen_stubs.c',
-))
-
-xen_specific_ss = ss.source_set()
-xen_specific_ss.add(files(
- 'xen-mapcache.c',
+xen_common_ss = ss.source_set()
+xen_common_ss.add(files(
'xen-hvm-common.c',
+ 'xen-mapcache.c',
+ 'xen-operations.c',
'xen-pvh-common.c',
))
+
if have_xen_pci_passthrough
- xen_specific_ss.add(files(
+ xen_common_ss.add(files(
'xen-host-pci-device.c',
'xen_pt.c',
'xen_pt_config_init.c',
@@ -30,7 +25,8 @@
'xen_pt_msi.c',
))
else
- xen_specific_ss.add(files('xen_pt_stub.c'))
+ xen_common_ss.add(files('xen_pt_stub.c'))
endif
-specific_ss.add_all(when: ['CONFIG_XEN', xen], if_true: xen_specific_ss)
+system_ss.add_all(when: ['CONFIG_XEN', xen], if_true: xen_common_ss)
+system_ss.add(when: ['CONFIG_XEN', xen], if_false: files('xen_stubs.c'))
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 52e2cce..b40ae0b 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -1,8 +1,9 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/bitops.h"
#include "qemu/error-report.h"
+#include "qemu/target-info.h"
#include "qapi/error.h"
-#include "exec/target_long.h"
#include "exec/target_page.h"
#include "trace.h"
@@ -448,12 +449,14 @@
static void handle_ioreq(XenIOState *state, ioreq_t *req)
{
+ size_t req_size_bits = req->size * BITS_PER_BYTE;
+
trace_handle_ioreq(req, req->type, req->dir, req->df, req->data_is_ptr,
req->addr, req->data, req->count, req->size);
if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
- (req->size < sizeof (target_ulong))) {
- req->data &= ((target_ulong) 1 << (8 * req->size)) - 1;
+ (req_size_bits < target_long_bits())) {
+ req->data &= MAKE_64BIT_MASK(0, req_size_bits);
}
if (req->dir == IOREQ_WRITE)
diff --git a/include/block/accounting.h b/include/block/accounting.h
index a59e39f..b1cf417 100644
--- a/include/block/accounting.h
+++ b/include/block/accounting.h
@@ -101,8 +101,9 @@
} BlockAcctCookie;
void block_acct_init(BlockAcctStats *stats);
-void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
- enum OnOffAuto account_failed);
+bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
+ enum OnOffAuto account_failed, uint32_t *stats_intervals,
+ uint32_t num_stats_intervals, Error **errp);
void block_acct_cleanup(BlockAcctStats *stats);
void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length);
BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats,
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 034c063..f2a4e86 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -817,10 +817,10 @@
int64_t max_pdiscard;
/*
- * Optimal alignment for discard requests in bytes. A power of 2
- * is best but not mandatory. Must be a multiple of
- * bl.request_alignment, and must be less than max_pdiscard if
- * that is set. May be 0 if bl.request_alignment is good enough
+ * Optimal alignment for discard requests in bytes. Note that this doesn't
+ * have to be a power of two. Must be a multiple of bl.request_alignment,
+ * and must be less than max_pdiscard if that is set. May be 0 if
+ * bl.request_alignment is good enough.
*/
uint32_t pdiscard_alignment;
@@ -831,11 +831,10 @@
int64_t max_pwrite_zeroes;
/*
- * Optimal alignment for write zeroes requests in bytes. A power
- * of 2 is best but not mandatory. Must be a multiple of
- * bl.request_alignment, and must be less than max_pwrite_zeroes
- * if that is set. May be 0 if bl.request_alignment is good
- * enough
+ * Optimal alignment for write zeroes requests in bytes. Note that this
+ * doesn't have to be a power of two. Must be a multiple of
+ * bl.request_alignment, and must be less than max_pwrite_zeroes if that is
+ * set. May be 0 if bl.request_alignment is good enough.
*/
uint32_t pwrite_zeroes_alignment;
@@ -863,18 +862,23 @@
uint64_t max_hw_transfer;
/*
- * Maximal number of scatter/gather elements allowed by the hardware.
+ * Maximum number of scatter/gather elements allowed by the hardware.
* Applies whenever transfers to the device bypass the kernel I/O
* scheduler, for example with SG_IO. If larger than max_iov
* or if zero, blk_get_max_hw_iov will fall back to max_iov.
*/
int max_hw_iov;
-
- /* memory alignment, in bytes so that no bounce buffer is needed */
+ /*
+ * Minimal required memory alignment in bytes for zero-copy I/O to succeed.
+ * For unaligned requests, a bounce buffer will be used.
+ */
size_t min_mem_alignment;
- /* memory alignment, in bytes, for bounce buffer */
+ /*
+ * Optimal memory alignment in bytes. This is the alignment used for any
+ * buffer allocations QEMU performs internally.
+ */
size_t opt_mem_alignment;
/* maximum number of iovec elements */
@@ -1020,7 +1024,10 @@
* the I/O API.
*/
- void (*resize)(BdrvChild *child);
+ /*
+ * Notifies the parent that the child was resized.
+ */
+ void GRAPH_RDLOCK_PTR (*resize)(BdrvChild *child);
/*
* Returns a name that is supposedly more useful for human users than the
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
index 4f94eb3..ed8b565 100644
--- a/include/block/block_int-io.h
+++ b/include/block/block_int-io.h
@@ -191,4 +191,10 @@
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
+/*
+ * Notify all parents that the size of the child changed.
+ */
+void coroutine_fn GRAPH_RDLOCK
+bdrv_co_parent_cb_resize(BlockDriverState *bs);
+
#endif /* BLOCK_INT_IO_H */
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 358e516..9fa2eca 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -1779,6 +1779,21 @@
NVME_DIRECTIVE_RETURN_PARAMS = 0x1,
};
+typedef enum SfscSecurityProtocol {
+ SFSC_SECURITY_PROT_INFO = 0x00,
+} SfscSecurityProtocol;
+
+typedef enum NvmeSecurityProtocols {
+ NVME_SEC_PROT_DMTF_SPDM = 0xE8,
+} NvmeSecurityProtocols;
+
+typedef enum SpdmOperationCodes {
+ SPDM_STORAGE_DISCOVERY = 0x1, /* Mandatory */
+ SPDM_STORAGE_PENDING_INFO = 0x2, /* Optional */
+ SPDM_STORAGE_MSG = 0x5, /* Mandatory */
+ SPDM_STORAGE_SEC_MSG = 0x6, /* Optional */
+} SpdmOperationCodes;
+
typedef struct QEMU_PACKED NvmeFdpConfsHdr {
uint16_t num_confs;
uint8_t version;
diff --git a/include/block/qapi.h b/include/block/qapi.h
index 54c48de..be554e5 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -42,7 +42,7 @@
bool skip_implicit_filters, Error **errp);
void GRAPH_RDLOCK
bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
- Error **errp);
+ bool limits, Error **errp);
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn);
void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
diff --git a/include/exec/memop.h b/include/exec/memop.h
index cf7da33..799b5b4 100644
--- a/include/exec/memop.h
+++ b/include/exec/memop.h
@@ -73,6 +73,16 @@
MO_ALIGN = MO_AMASK,
/*
+ * MO_ALIGN_TLB_ONLY:
+ * Apply MO_AMASK only along the TCG slow path if TLB_CHECK_ALIGNED
+ * is set; otherwise unaligned access is permitted.
+ * This is used by target/arm, where unaligned accesses are
+ * permitted for pages marked Normal but aligned accesses are
+ * required for pages marked Device.
+ */
+ MO_ALIGN_TLB_ONLY = 1 << 8,
+
+ /*
* MO_ATOM_* describes the atomicity requirements of the operation:
* MO_ATOM_IFALIGN: the operation must be single-copy atomic if it
* is aligned; if unaligned there is no atomicity.
@@ -104,7 +114,7 @@
* size of the operation, if aligned. This retains the behaviour
* from before this field was introduced.
*/
- MO_ATOM_SHIFT = 8,
+ MO_ATOM_SHIFT = 9,
MO_ATOM_IFALIGN = 0 << MO_ATOM_SHIFT,
MO_ATOM_IFALIGN_PAIR = 1 << MO_ATOM_SHIFT,
MO_ATOM_WITHIN16 = 2 << MO_ATOM_SHIFT,
@@ -169,16 +179,16 @@
}
/**
- * memop_alignment_bits:
+ * memop_tlb_alignment_bits:
* @memop: MemOp value
*
- * Extract the alignment size from the memop.
+ * Extract the alignment size for use with TLB_CHECK_ALIGNED.
*/
-static inline unsigned memop_alignment_bits(MemOp memop)
+static inline unsigned memop_tlb_alignment_bits(MemOp memop, bool tlb_check)
{
unsigned a = memop & MO_AMASK;
- if (a == MO_UNALN) {
+ if (a == MO_UNALN || (!tlb_check && (memop & MO_ALIGN_TLB_ONLY))) {
/* No alignment required. */
a = 0;
} else if (a == MO_ALIGN) {
@@ -191,28 +201,15 @@
return a;
}
-/*
- * memop_atomicity_bits:
+/**
+ * memop_alignment_bits:
* @memop: MemOp value
*
- * Extract the atomicity size from the memop.
+ * Extract the alignment size from the memop.
*/
-static inline unsigned memop_atomicity_bits(MemOp memop)
+static inline unsigned memop_alignment_bits(MemOp memop)
{
- unsigned size = memop & MO_SIZE;
-
- switch (memop & MO_ATOM_MASK) {
- case MO_ATOM_NONE:
- size = MO_8;
- break;
- case MO_ATOM_IFALIGN_PAIR:
- case MO_ATOM_WITHIN16_PAIR:
- size = size ? size - 1 : 0;
- break;
- default:
- break;
- }
- return size;
+ return memop_tlb_alignment_bits(memop, false);
}
#endif
diff --git a/include/hw/arm/machines-qom.h b/include/hw/arm/machines-qom.h
new file mode 100644
index 0000000..3f64d5e
--- /dev/null
+++ b/include/hw/arm/machines-qom.h
@@ -0,0 +1,46 @@
+/*
+ * QOM type definitions for ARM / Aarch64 machines
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_ARM_MACHINES_QOM_H
+#define HW_ARM_MACHINES_QOM_H
+
+#include "hw/boards.h"
+
+#define TYPE_TARGET_ARM_MACHINE \
+ "target-info-arm-machine"
+
+#define TYPE_TARGET_AARCH64_MACHINE \
+ "target-info-aarch64-machine"
+
+/*
+ * A machine filtered with arm_machine_interfaces[] or
+ * arm_aarch64_machine_interfaces[] will be available
+ * in both qemu-system-arm and qemu-system-aarch64 binaries.
+ *
+ * One filtered with aarch64_machine_interfaces[] will only
+ * be available in the qemu-system-aarch64 binary.
+ */
+extern const InterfaceInfo arm_machine_interfaces[];
+extern const InterfaceInfo arm_aarch64_machine_interfaces[];
+extern const InterfaceInfo aarch64_machine_interfaces[];
+
+/*
+ * A machine defined with the DEFINE_MACHINE_ARM() macro will be
+ * available in both qemu-system-arm and qemu-system-aarch64 binaries.
+ *
+ * One defined with DEFINE_MACHINE_AARCH64() will only be available in
+ * the qemu-system-aarch64 binary.
+ */
+#define DEFINE_MACHINE_ARM(namestr, machine_initfn) \
+ DEFINE_MACHINE_WITH_INTERFACE_ARRAY(namestr, machine_initfn, \
+ arm_machine_interfaces)
+#define DEFINE_MACHINE_AARCH64(namestr, machine_initfn) \
+ DEFINE_MACHINE_WITH_INTERFACE_ARRAY(namestr, machine_initfn, \
+ aarch64_machine_interfaces)
+
+#endif
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index de3946a..b4d9146 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -34,6 +34,8 @@
OnOffAuto account_invalid, account_failed;
BlockdevOnError rerror;
BlockdevOnError werror;
+ uint32_t num_stats_intervals;
+ uint32_t *stats_intervals;
} BlockConf;
static inline unsigned int get_physical_block_exp(BlockConf *conf)
@@ -66,7 +68,10 @@
DEFINE_PROP_ON_OFF_AUTO("account-invalid", _state, \
_conf.account_invalid, ON_OFF_AUTO_AUTO), \
DEFINE_PROP_ON_OFF_AUTO("account-failed", _state, \
- _conf.account_failed, ON_OFF_AUTO_AUTO)
+ _conf.account_failed, ON_OFF_AUTO_AUTO), \
+ DEFINE_PROP_ARRAY("stats-intervals", _state, \
+ _conf.num_stats_intervals, _conf.stats_intervals, \
+ qdev_prop_uint32, uint32_t)
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index eee0338..88ccea5 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -4,6 +4,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_doe.h"
+#include "system/spdm-socket.h"
#define TYPE_PCI_DEVICE "pci-device"
typedef struct PCIDeviceClass PCIDeviceClass;
@@ -166,6 +167,7 @@
/* SPDM */
uint16_t spdm_port;
+ SpdmTransportType spdm_trans;
/* DOE */
DOECap doe_spdm;
diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
index 7056d84..1100dae 100644
--- a/include/qemu/plugin-event.h
+++ b/include/qemu/plugin-event.h
@@ -20,6 +20,9 @@
QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
QEMU_PLUGIN_EV_FLUSH,
QEMU_PLUGIN_EV_ATEXIT,
+ QEMU_PLUGIN_EV_VCPU_INTERRUPT,
+ QEMU_PLUGIN_EV_VCPU_EXCEPTION,
+ QEMU_PLUGIN_EV_VCPU_HOSTCALL,
QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
};
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index f355c7c..cea0a68 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -59,6 +59,7 @@
qemu_plugin_udata_cb_t udata;
qemu_plugin_vcpu_simple_cb_t vcpu_simple;
qemu_plugin_vcpu_udata_cb_t vcpu_udata;
+ qemu_plugin_vcpu_discon_cb_t vcpu_discon;
qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans;
qemu_plugin_vcpu_mem_cb_t vcpu_mem;
qemu_plugin_vcpu_syscall_cb_t vcpu_syscall;
@@ -160,6 +161,9 @@
void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
+void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from);
+void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from);
+void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from);
void
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
@@ -257,6 +261,15 @@
static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
{ }
+static inline void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from)
+{ }
+
+static inline void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from)
+{ }
+
+static inline void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from)
+{ }
+
static inline void
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index c450106..60de4fd 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -161,6 +161,50 @@
typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
void *userdata);
+
+/**
+ * enum qemu_plugin_discon_type - type of a (potential) PC discontinuity
+ *
+ * @QEMU_PLUGIN_DISCON_INTERRUPT: an interrupt, defined across all architectures
+ * as an asynchronous event, usually originating
+ * from outside the CPU
+ * @QEMU_PLUGIN_DISCON_EXCEPTION: an exception, defined across all architectures
+ * as a synchronous event in response to a
+ * specific instruction being executed
+ * @QEMU_PLUGIN_DISCON_HOSTCALL: a host call, functionally a special kind of
+ * exception that is not handled by code run by
+ * the vCPU but machinery outside the vCPU
+ * @QEMU_PLUGIN_DISCON_ALL: all types of disconinuity events currently covered
+ */
+enum qemu_plugin_discon_type {
+ QEMU_PLUGIN_DISCON_INTERRUPT = 1 << 0,
+ QEMU_PLUGIN_DISCON_EXCEPTION = 1 << 1,
+ QEMU_PLUGIN_DISCON_HOSTCALL = 1 << 2,
+ QEMU_PLUGIN_DISCON_ALL = -1
+};
+
+/**
+ * typedef qemu_plugin_vcpu_discon_cb_t - vcpu discontinuity callback
+ * @id: plugin ID
+ * @vcpu_index: the current vcpu context
+ * @type: the type of discontinuity
+ * @from_pc: the source of the discontinuity, e.g. the PC before the
+ * transition
+ * @to_pc: the PC pointing to the next instruction to be executed
+ *
+ * The exact semantics of @from_pc depends on the @type of discontinuity. For
+ * interrupts, @from_pc will point to the next instruction which would have
+ * been executed. For exceptions and host calls, @from_pc will point to the
+ * instruction that caused the exception or issued the host call. Note that
+ * in the case of exceptions, the instruction may not be retired and thus not
+ * observable via general instruction exec callbacks. The same may be the case
+ * for some host calls such as hypervisor call "exceptions".
+ */
+typedef void (*qemu_plugin_vcpu_discon_cb_t)(qemu_plugin_id_t id,
+ unsigned int vcpu_index,
+ enum qemu_plugin_discon_type type,
+ uint64_t from_pc, uint64_t to_pc);
+
/**
* qemu_plugin_uninstall() - Uninstall a plugin
* @id: this plugin's opaque ID
@@ -237,6 +281,22 @@
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
+/**
+ * qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback
+ * @id: plugin ID
+ * @type: types of discontinuities for which to call the callback
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU receives a discontinuity event
+ * of the specified type(s), after the vCPU was prepared to handle the event.
+ * Preparation entails updating the PC, usually to some interrupt handler or
+ * trap vector entry.
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
+ enum qemu_plugin_discon_type type,
+ qemu_plugin_vcpu_discon_cb_t cb);
+
/** struct qemu_plugin_tb - Opaque handle for a translation block */
struct qemu_plugin_tb;
/** struct qemu_plugin_insn - Opaque handle for a translated instruction */
diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h
index abcf25d..6235962 100644
--- a/include/qemu/target-info.h
+++ b/include/qemu/target-info.h
@@ -50,4 +50,25 @@
*/
bool target_big_endian(void);
+/**
+ * target_base_arm:
+ *
+ * Returns whether the target architecture is ARM or Aarch64.
+ */
+bool target_base_arm(void);
+
+/**
+ * target_arm:
+ *
+ * Returns whether the target architecture is ARM (32-bit, not Aarch64).
+ */
+bool target_arm(void);
+
+/**
+ * target_aarch64:
+ *
+ * Returns whether the target architecture is Aarch64.
+ */
+bool target_aarch64(void);
+
#endif
diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h
index eb80314..dc24512 100644
--- a/include/standard-headers/linux/ethtool.h
+++ b/include/standard-headers/linux/ethtool.h
@@ -2380,6 +2380,7 @@
#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */
#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */
#define RXH_GTP_TEID (1 << 8) /* teid in case of GTP */
+#define RXH_IP6_FL (1 << 9) /* IPv6 flow label */
#define RXH_DISCARD (1 << 31)
#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h
index d8b2fd6..abf3a78 100644
--- a/include/standard-headers/linux/fuse.h
+++ b/include/standard-headers/linux/fuse.h
@@ -235,6 +235,11 @@
*
* 7.44
* - add FUSE_NOTIFY_INC_EPOCH
+ *
+ * 7.45
+ * - add FUSE_COPY_FILE_RANGE_64
+ * - add struct fuse_copy_file_range_out
+ * - add FUSE_NOTIFY_PRUNE
*/
#ifndef _LINUX_FUSE_H
@@ -266,7 +271,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 44
+#define FUSE_KERNEL_MINOR_VERSION 45
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -653,6 +658,7 @@
FUSE_SYNCFS = 50,
FUSE_TMPFILE = 51,
FUSE_STATX = 52,
+ FUSE_COPY_FILE_RANGE_64 = 53,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -671,7 +677,7 @@
FUSE_NOTIFY_DELETE = 6,
FUSE_NOTIFY_RESEND = 7,
FUSE_NOTIFY_INC_EPOCH = 8,
- FUSE_NOTIFY_CODE_MAX,
+ FUSE_NOTIFY_PRUNE = 9,
};
/* The read buffer is required to be at least 8k, but may be much larger */
@@ -1110,6 +1116,12 @@
uint64_t dummy4;
};
+struct fuse_notify_prune_out {
+ uint32_t count;
+ uint32_t padding;
+ uint64_t spare;
+};
+
struct fuse_backing_map {
int32_t fd;
uint32_t flags;
@@ -1122,6 +1134,7 @@
#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
struct fuse_backing_map)
#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
+#define FUSE_DEV_IOC_SYNC_INIT _IO(FUSE_DEV_IOC_MAGIC, 3)
struct fuse_lseek_in {
uint64_t fh;
@@ -1144,6 +1157,11 @@
uint64_t flags;
};
+/* For FUSE_COPY_FILE_RANGE_64 */
+struct fuse_copy_file_range_out {
+ uint64_t bytes_copied;
+};
+
#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0)
#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1)
struct fuse_setupmapping_in {
diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h
index 00dc9ca..c914ccd 100644
--- a/include/standard-headers/linux/input-event-codes.h
+++ b/include/standard-headers/linux/input-event-codes.h
@@ -27,6 +27,7 @@
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
+#define INPUT_PROP_HAPTIC_TOUCHPAD 0x07 /* is a haptic touchpad */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h
index d4512c2..9aff211 100644
--- a/include/standard-headers/linux/input.h
+++ b/include/standard-headers/linux/input.h
@@ -427,6 +427,24 @@
};
/**
+ * struct ff_haptic_effect
+ * @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.)
+ * @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined range
+ * @vendor_waveform_page: the vendor waveform page if hid_usage is in the vendor-defined range
+ * @intensity: strength of the effect as percentage
+ * @repeat_count: number of times to retrigger effect
+ * @retrigger_period: time before effect is retriggered (in ms)
+ */
+struct ff_haptic_effect {
+ uint16_t hid_usage;
+ uint16_t vendor_id;
+ uint8_t vendor_waveform_page;
+ uint16_t intensity;
+ uint16_t repeat_count;
+ uint16_t retrigger_period;
+};
+
+/**
* struct ff_effect - defines force feedback effect
* @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
@@ -462,6 +480,7 @@
struct ff_periodic_effect periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
+ struct ff_haptic_effect haptic;
} u;
};
@@ -469,6 +488,7 @@
* Force feedback effect types
*/
+#define FF_HAPTIC 0x4f
#define FF_RUMBLE 0x50
#define FF_PERIODIC 0x51
#define FF_CONSTANT 0x52
@@ -478,7 +498,7 @@
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
-#define FF_EFFECT_MIN FF_RUMBLE
+#define FF_EFFECT_MIN FF_HAPTIC
#define FF_EFFECT_MAX FF_RAMP
/*
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index f5b1774..07e06aa 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -207,6 +207,9 @@
/* Capability lists */
+#define PCI_CAP_ID_MASK 0x00ff /* Capability ID mask */
+#define PCI_CAP_LIST_NEXT_MASK 0xff00 /* Next Capability Pointer mask */
+
#define PCI_CAP_LIST_ID 0 /* Capability ID */
#define PCI_CAP_ID_PM 0x01 /* Power Management */
#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
@@ -776,6 +779,12 @@
#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */
#define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */
#define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */
+#define PCI_ERR_UNC_POISON_BLK 0x04000000 /* Poisoned TLP Egress Blocked */
+#define PCI_ERR_UNC_DMWR_BLK 0x08000000 /* DMWr Request Egress Blocked */
+#define PCI_ERR_UNC_IDE_CHECK 0x10000000 /* IDE Check Failed */
+#define PCI_ERR_UNC_MISR_IDE 0x20000000 /* Misrouted IDE TLP */
+#define PCI_ERR_UNC_PCRC_CHECK 0x40000000 /* PCRC Check Failed */
+#define PCI_ERR_UNC_XLAT_BLK 0x80000000 /* TLP Translation Egress Blocked */
#define PCI_ERR_UNCOR_MASK 0x08 /* Uncorrectable Error Mask */
/* Same bits as above */
#define PCI_ERR_UNCOR_SEVER 0x0c /* Uncorrectable Error Severity */
@@ -798,6 +807,7 @@
#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
#define PCI_ERR_CAP_PREFIX_LOG_PRESENT 0x00000800 /* TLP Prefix Log Present */
+#define PCI_ERR_CAP_COMP_TIME_LOG 0x00001000 /* Completion Timeout Prefix/Header Log Capable */
#define PCI_ERR_CAP_TLP_LOG_FLIT 0x00040000 /* TLP was logged in Flit Mode */
#define PCI_ERR_CAP_TLP_LOG_SIZE 0x00f80000 /* Logged TLP Size (only in Flit mode) */
#define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index 7aa2eb7..6c12db1 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -68,6 +68,7 @@
#define VIRTIO_ID_AUDIO_POLICY 39 /* virtio audio policy */
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
+#define VIRTIO_ID_SPI 45 /* virtio spi */
/*
* Virtio Transitional IDs
diff --git a/include/system/spdm-socket.h b/include/system/spdm-socket.h
index 5d8bd9a..00cb0e9 100644
--- a/include/system/spdm-socket.h
+++ b/include/system/spdm-socket.h
@@ -51,6 +51,35 @@
void *rsp, uint32_t rsp_len);
/**
+ * spdm_socket_rsp: Receive a message from an SPDM server
+ * @socket: socket returned from spdm_socket_connect()
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ * @rsp: response buffer
+ * @rsp_len: response buffer length
+ *
+ * Receives a message from the SPDM server and returns the number of bytes
+ * received or 0 on failure. This can be used to receive a message from the SPDM
+ * server without sending anything first.
+ */
+uint32_t spdm_socket_receive(const int socket, uint32_t transport_type,
+ void *rsp, uint32_t rsp_len);
+
+/**
+ * spdm_socket_rsp: Sends a message to an SPDM server
+ * @socket: socket returned from spdm_socket_connect()
+ * @socket_cmd: socket command type (normal/if_recv/if_send etc...)
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ * @req: request buffer
+ * @req_len: request buffer length
+ *
+ * Sends platform data to a SPDM server on socket, returns true on success.
+ * The response from the server must then be fetched by using
+ * spdm_socket_receive().
+ */
+bool spdm_socket_send(const int socket, uint32_t socket_cmd,
+ uint32_t transport_type, void *req, uint32_t req_len);
+
+/**
* spdm_socket_close: send a shutdown command to the server
* @socket: socket returned from spdm_socket_connect()
* @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
@@ -59,16 +88,46 @@
*/
void spdm_socket_close(const int socket, uint32_t transport_type);
+/*
+ * Defines the transport encoding for SPDM, this information shall be passed
+ * down to the SPDM server, when conforming to the SPDM over Storage standard
+ * as defined by DSP0286.
+ */
+typedef struct {
+ uint8_t security_protocol; /* Must be 0xE8 for SPDM Commands
+ as per SCSI Primary Commands 5 */
+ uint16_t security_protocol_specific; /* Bit[7:2] SPDM Operation
+ Bit[0:1] Connection ID
+ per DSP0286 1.0: Section 7.2 */
+ uint32_t length; /* Length of the SPDM Message*/
+} QEMU_PACKED StorageSpdmTransportHeader;
+
#define SPDM_SOCKET_COMMAND_NORMAL 0x0001
+#define SPDM_SOCKET_STORAGE_CMD_IF_SEND 0x0002
+#define SPDM_SOCKET_STORAGE_CMD_IF_RECV 0x0003
+#define SOCKET_SPDM_STORAGE_ACK_STATUS 0x0004
#define SPDM_SOCKET_COMMAND_OOB_ENCAP_KEY_UPDATE 0x8001
#define SPDM_SOCKET_COMMAND_CONTINUE 0xFFFD
#define SPDM_SOCKET_COMMAND_SHUTDOWN 0xFFFE
#define SPDM_SOCKET_COMMAND_UNKOWN 0xFFFF
#define SPDM_SOCKET_COMMAND_TEST 0xDEAD
-#define SPDM_SOCKET_TRANSPORT_TYPE_MCTP 0x01
-#define SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE 0x02
-
#define SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE 0x1200
+#define SPDM_SOCKET_MAX_MSG_STATUS_LEN 0x02
+
+typedef enum SpdmTransportType {
+ SPDM_SOCKET_TRANSPORT_TYPE_UNSPEC = 0,
+ SPDM_SOCKET_TRANSPORT_TYPE_MCTP,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE,
+ SPDM_SOCKET_TRANSPORT_TYPE_SCSI,
+ SPDM_SOCKET_TRANSPORT_TYPE_NVME,
+ SPDM_SOCKET_TRANSPORT_TYPE_MAX
+} SpdmTransportType;
+
+extern const PropertyInfo qdev_prop_spdm_trans;
+
+#define DEFINE_PROP_SPDM_TRANS(_name, _state, _field, _default) \
+ DEFINE_PROP_UNSIGNED(_name, _state, _field, _default, \
+ qdev_prop_spdm_trans, SpdmTransportType)
#endif
diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index 5f354f5..57ba1a5 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -103,6 +103,7 @@
#define KVM_LOONGARCH_VM_FEAT_PMU 5
#define KVM_LOONGARCH_VM_FEAT_PV_IPI 6
#define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7
+#define KVM_LOONGARCH_VM_FEAT_PTW 8
/* Device Control API on vcpu fd */
#define KVM_LOONGARCH_VCPU_CPUCFG 0
diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h
index ef27d42..759a485 100644
--- a/linux-headers/asm-riscv/kvm.h
+++ b/linux-headers/asm-riscv/kvm.h
@@ -9,7 +9,7 @@
#ifndef __LINUX_KVM_RISCV_H
#define __LINUX_KVM_RISCV_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <asm/bitsperlong.h>
@@ -56,6 +56,7 @@
unsigned long mimpid;
unsigned long zicboz_block_size;
unsigned long satp_mode;
+ unsigned long zicbop_block_size;
};
/* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
@@ -185,6 +186,10 @@
KVM_RISCV_ISA_EXT_ZICCRSE,
KVM_RISCV_ISA_EXT_ZAAMO,
KVM_RISCV_ISA_EXT_ZALRSC,
+ KVM_RISCV_ISA_EXT_ZICBOP,
+ KVM_RISCV_ISA_EXT_ZFBFMIN,
+ KVM_RISCV_ISA_EXT_ZVFBFMIN,
+ KVM_RISCV_ISA_EXT_ZVFBFWMA,
KVM_RISCV_ISA_EXT_MAX,
};
@@ -205,6 +210,7 @@
KVM_RISCV_SBI_EXT_DBCN,
KVM_RISCV_SBI_EXT_STA,
KVM_RISCV_SBI_EXT_SUSP,
+ KVM_RISCV_SBI_EXT_FWFT,
KVM_RISCV_SBI_EXT_MAX,
};
@@ -214,6 +220,18 @@
unsigned long shmem_hi;
};
+struct kvm_riscv_sbi_fwft_feature {
+ unsigned long enable;
+ unsigned long flags;
+ unsigned long value;
+};
+
+/* SBI FWFT extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
+struct kvm_riscv_sbi_fwft {
+ struct kvm_riscv_sbi_fwft_feature misaligned_deleg;
+ struct kvm_riscv_sbi_fwft_feature pointer_masking;
+};
+
/* Possible states for kvm_riscv_timer */
#define KVM_RISCV_TIMER_STATE_OFF 0
#define KVM_RISCV_TIMER_STATE_ON 1
@@ -297,6 +315,9 @@
#define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
#define KVM_REG_RISCV_SBI_STA_REG(name) \
(offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long))
+#define KVM_REG_RISCV_SBI_FWFT (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT)
+#define KVM_REG_RISCV_SBI_FWFT_REG(name) \
+ (offsetof(struct kvm_riscv_sbi_fwft, name) / sizeof(unsigned long))
/* Device Control API: RISC-V AIA */
#define KVM_DEV_RISCV_APLIC_ALIGN 0x1000
diff --git a/linux-headers/asm-riscv/ptrace.h b/linux-headers/asm-riscv/ptrace.h
index 1e3166c..a3f8211 100644
--- a/linux-headers/asm-riscv/ptrace.h
+++ b/linux-headers/asm-riscv/ptrace.h
@@ -6,7 +6,7 @@
#ifndef _ASM_RISCV_PTRACE_H
#define _ASM_RISCV_PTRACE_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <linux/types.h>
@@ -127,6 +127,6 @@
*/
#define RISCV_MAX_VLENB (8192)
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* _ASM_RISCV_PTRACE_H */
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index f0c1a73..3bb38f6 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -35,6 +35,11 @@
#define MC_VECTOR 18
#define XM_VECTOR 19
#define VE_VECTOR 20
+#define CP_VECTOR 21
+
+#define HV_VECTOR 28
+#define VC_VECTOR 29
+#define SX_VECTOR 30
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
@@ -409,6 +414,35 @@
__u64 padding[16];
};
+#define KVM_X86_REG_TYPE_MSR 2
+#define KVM_X86_REG_TYPE_KVM 3
+
+#define KVM_X86_KVM_REG_SIZE(reg) \
+({ \
+ reg == KVM_REG_GUEST_SSP ? KVM_REG_SIZE_U64 : 0; \
+})
+
+#define KVM_X86_REG_TYPE_SIZE(type, reg) \
+({ \
+ __u64 type_size = (__u64)type << 32; \
+ \
+ type_size |= type == KVM_X86_REG_TYPE_MSR ? KVM_REG_SIZE_U64 : \
+ type == KVM_X86_REG_TYPE_KVM ? KVM_X86_KVM_REG_SIZE(reg) : \
+ 0; \
+ type_size; \
+})
+
+#define KVM_X86_REG_ID(type, index) \
+ (KVM_REG_X86 | KVM_X86_REG_TYPE_SIZE(type, index) | index)
+
+#define KVM_X86_REG_MSR(index) \
+ KVM_X86_REG_ID(KVM_X86_REG_TYPE_MSR, index)
+#define KVM_X86_REG_KVM(index) \
+ KVM_X86_REG_ID(KVM_X86_REG_TYPE_KVM, index)
+
+/* KVM-defined registers starting from 0 */
+#define KVM_REG_GUEST_SSP 0
+
#define KVM_SYNC_X86_REGS (1UL << 0)
#define KVM_SYNC_X86_SREGS (1UL << 1)
#define KVM_SYNC_X86_EVENTS (1UL << 2)
diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h
index 2f55beb..26c258d 100644
--- a/linux-headers/asm-x86/unistd_64.h
+++ b/linux-headers/asm-x86/unistd_64.h
@@ -337,6 +337,7 @@
#define __NR_io_pgetevents 333
#define __NR_rseq 334
#define __NR_uretprobe 335
+#define __NR_uprobe 336
#define __NR_pidfd_send_signal 424
#define __NR_io_uring_setup 425
#define __NR_io_uring_enter 426
diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h
index 8cc8673..65c2aed 100644
--- a/linux-headers/asm-x86/unistd_x32.h
+++ b/linux-headers/asm-x86/unistd_x32.h
@@ -290,6 +290,7 @@
#define __NR_io_pgetevents (__X32_SYSCALL_BIT + 333)
#define __NR_rseq (__X32_SYSCALL_BIT + 334)
#define __NR_uretprobe (__X32_SYSCALL_BIT + 335)
+#define __NR_uprobe (__X32_SYSCALL_BIT + 336)
#define __NR_pidfd_send_signal (__X32_SYSCALL_BIT + 424)
#define __NR_io_uring_setup (__X32_SYSCALL_BIT + 425)
#define __NR_io_uring_enter (__X32_SYSCALL_BIT + 426)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index be70496..4ea28ef 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -954,6 +954,7 @@
#define KVM_CAP_ARM_EL2_E2H0 241
#define KVM_CAP_RISCV_MP_STATE_RESET 242
#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
+#define KVM_CAP_GUEST_MEMFD_FLAGS 244
struct kvm_irq_routing_irqchip {
__u32 irqchip;
@@ -1590,6 +1591,8 @@
#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd)
+#define GUEST_MEMFD_FLAG_MMAP (1ULL << 0)
+#define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1)
struct kvm_create_guest_memfd {
__u64 size;
diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h
index 113c4ce..c525125 100644
--- a/linux-headers/linux/psp-sev.h
+++ b/linux-headers/linux/psp-sev.h
@@ -185,6 +185,10 @@
* @mask_chip_id: whether chip id is present in attestation reports or not
* @mask_chip_key: whether attestation reports are signed or not
* @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded
+ * @feature_info: whether SNP_FEATURE_INFO command is available
+ * @rapl_dis: whether RAPL is disabled
+ * @ciphertext_hiding_cap: whether platform has ciphertext hiding capability
+ * @ciphertext_hiding_en: whether ciphertext hiding is enabled
* @rsvd1: reserved
* @guest_count: the number of guest currently managed by the firmware
* @current_tcb_version: current TCB version
@@ -200,7 +204,11 @@
__u32 mask_chip_id:1; /* Out */
__u32 mask_chip_key:1; /* Out */
__u32 vlek_en:1; /* Out */
- __u32 rsvd1:29;
+ __u32 feature_info:1; /* Out */
+ __u32 rapl_dis:1; /* Out */
+ __u32 ciphertext_hiding_cap:1; /* Out */
+ __u32 ciphertext_hiding_en:1; /* Out */
+ __u32 rsvd1:25;
__u32 guest_count; /* Out */
__u64 current_tcb_version; /* Out */
__u64 reported_tcb_version; /* Out */
diff --git a/linux-headers/linux/stddef.h b/linux-headers/linux/stddef.h
index e1fcfcf..48ee443 100644
--- a/linux-headers/linux/stddef.h
+++ b/linux-headers/linux/stddef.h
@@ -3,7 +3,6 @@
#define _LINUX_STDDEF_H
-
#ifndef __always_inline
#define __always_inline __inline__
#endif
diff --git a/linux-headers/linux/vduse.h b/linux-headers/linux/vduse.h
index f46269a..da6ac89 100644
--- a/linux-headers/linux/vduse.h
+++ b/linux-headers/linux/vduse.h
@@ -237,7 +237,7 @@
* struct vduse_iova_info - information of one IOVA region
* @start: start of the IOVA region
* @last: last of the IOVA region
- * @capability: capability of the IOVA regsion
+ * @capability: capability of the IOVA region
* @reserved: for future use, needs to be initialized to zero
*
* Structure used by VDUSE_IOTLB_GET_INFO ioctl to get information of
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
index 283348b..c57674a 100644
--- a/linux-headers/linux/vhost.h
+++ b/linux-headers/linux/vhost.h
@@ -260,7 +260,7 @@
* When fork_owner is set to VHOST_FORK_OWNER_KTHREAD:
* - Vhost will create vhost workers as kernel threads.
*/
-#define VHOST_SET_FORK_FROM_OWNER _IOW(VHOST_VIRTIO, 0x83, __u8)
+#define VHOST_SET_FORK_FROM_OWNER _IOW(VHOST_VIRTIO, 0x84, __u8)
/**
* VHOST_GET_FORK_OWNER - Get the current fork_owner flag for the vhost device.
@@ -268,6 +268,6 @@
*
* @return: An 8-bit value indicating the current thread mode.
*/
-#define VHOST_GET_FORK_FROM_OWNER _IOR(VHOST_VIRTIO, 0x84, __u8)
+#define VHOST_GET_FORK_FROM_OWNER _IOR(VHOST_VIRTIO, 0x85, __u8)
#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8546f48..2060e56 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3581,7 +3581,7 @@
abi_ulong target_addr, socklen_t addrlen)
{
void *addr;
- void *host_msg;
+ void *host_msg = NULL;
void *copy_msg = NULL;
abi_long ret;
@@ -3589,16 +3589,19 @@
return -TARGET_EINVAL;
}
- host_msg = lock_user(VERIFY_READ, msg, len, 1);
- if (!host_msg)
- return -TARGET_EFAULT;
- if (fd_trans_target_to_host_data(fd)) {
- copy_msg = host_msg;
- host_msg = g_malloc(len);
- memcpy(host_msg, copy_msg, len);
- ret = fd_trans_target_to_host_data(fd)(host_msg, len);
- if (ret < 0) {
- goto fail;
+ if (len != 0) {
+ host_msg = lock_user(VERIFY_READ, msg, len, 1);
+ if (!host_msg) {
+ return -TARGET_EFAULT;
+ }
+ if (fd_trans_target_to_host_data(fd)) {
+ copy_msg = host_msg;
+ host_msg = g_malloc(len);
+ memcpy(host_msg, copy_msg, len);
+ ret = fd_trans_target_to_host_data(fd)(host_msg, len);
+ if (ret < 0) {
+ goto fail;
+ }
}
}
if (target_addr) {
diff --git a/meson.build b/meson.build
index 8ad37c9..df876c7 100644
--- a/meson.build
+++ b/meson.build
@@ -3312,6 +3312,7 @@
config_target_h = {}
config_target_mak = {}
config_base_arch_mak = {}
+config_target_info = {}
disassemblers = {
'alpha' : ['CONFIG_ALPHA_DIS'],
@@ -3911,9 +3912,10 @@
specific_ss.add(files('page-vary-target.c'))
common_ss.add(files('target-info.c'))
-specific_ss.add(files('target-info-stub.c'))
+system_ss.add(files('target-info-qom.c'))
subdir('backends')
+subdir('configs/targets')
subdir('disas')
subdir('migration')
subdir('monitor')
@@ -4364,6 +4366,12 @@
arch_srcs += gdbstub_xml
endif
+ if target in config_target_info
+ arch_srcs += config_target_info[target]
+ else
+ arch_srcs += files('target-info-stub.c')
+ endif
+
t = target_arch[target_base_arch].apply(config_target, strict: false)
arch_srcs += t.sources()
arch_deps += t.dependencies()
diff --git a/plugins/core.c b/plugins/core.c
index ead09fd..8f8bc72 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -111,6 +111,30 @@
* have type information
*/
QEMU_DISABLE_CFI
+static void plugin_vcpu_cb__discon(CPUState *cpu,
+ enum qemu_plugin_event ev,
+ enum qemu_plugin_discon_type type,
+ uint64_t from)
+{
+ struct qemu_plugin_cb *cb, *next;
+ uint64_t to = cpu->cc->get_pc(cpu);
+
+ if (cpu->cpu_index < plugin.num_vcpus) {
+ /* iterate safely; plugins might uninstall themselves at any time */
+ QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+ qemu_plugin_vcpu_discon_cb_t func = cb->f.vcpu_discon;
+
+ func(cb->ctx->id, cpu->cpu_index, type, from, to);
+ }
+ }
+}
+
+/*
+ * Disable CFI checks.
+ * The callback function has been loaded from an external library so we do not
+ * have type information
+ */
+QEMU_DISABLE_CFI
static void plugin_cb__simple(enum qemu_plugin_event ev)
{
struct qemu_plugin_cb *cb, *next;
@@ -557,6 +581,24 @@
}
}
+void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from)
+{
+ plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_INTERRUPT,
+ QEMU_PLUGIN_DISCON_INTERRUPT, from);
+}
+
+void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from)
+{
+ plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_EXCEPTION,
+ QEMU_PLUGIN_DISCON_EXCEPTION, from);
+}
+
+void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from)
+{
+ plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_HOSTCALL,
+ QEMU_PLUGIN_DISCON_HOSTCALL, from);
+}
+
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb)
{
@@ -569,6 +611,21 @@
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
}
+void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
+ enum qemu_plugin_discon_type type,
+ qemu_plugin_vcpu_discon_cb_t cb)
+{
+ if (type & QEMU_PLUGIN_DISCON_INTERRUPT) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
+ }
+ if (type & QEMU_PLUGIN_DISCON_EXCEPTION) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
+ }
+ if (type & QEMU_PLUGIN_DISCON_HOSTCALL) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_HOSTCALL, cb);
+ }
+}
+
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
qemu_plugin_simple_cb_t cb)
{
@@ -611,6 +668,7 @@
}
}
+QEMU_DISABLE_CFI
void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
uint64_t value_low,
uint64_t value_high,
diff --git a/plugins/loader.c b/plugins/loader.c
index ba10eba..0dbe7be 100644
--- a/plugins/loader.c
+++ b/plugins/loader.c
@@ -318,6 +318,7 @@
bool reset;
};
+QEMU_DISABLE_CFI
static void plugin_reset_destroy__locked(struct qemu_plugin_reset_data *data)
{
struct qemu_plugin_ctx *ctx = data->ctx;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index dc6eb4a..2c03718 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -276,6 +276,69 @@
} }
##
+# @BlockLimitsInfo:
+#
+# @request-alignment: Alignment requirement, in bytes, for
+# offset/length of I/O requests.
+#
+# @max-discard: Maximum number of bytes that can be discarded at once.
+# If not present, there is no specific maximum.
+#
+# @discard-alignment: Optimal alignment for discard requests in bytes.
+# Note that this doesn't have to be a power of two. If not
+# present, discards don't have a alignment requirement different
+# from @request-alignment.
+#
+# @max-write-zeroes: Maximum number of bytes that can be zeroed out at
+# once. If not present, there is no specific maximum.
+#
+# @write-zeroes-alignment: Optimal alignment for write zeroes requests
+# in bytes. Note that this doesn't have to be a power of two. If
+# not present, write_zeroes doesn't have a alignment requirement
+# different from @request-alignment.
+#
+# @opt-transfer: Optimal transfer length in bytes. If not present,
+# there is no preferred size.
+#
+# @max-transfer: Maximal transfer length in bytes. If not present,
+# there is no specific maximum.
+#
+# @max-hw-transfer: Maximal hardware transfer length in bytes.
+# Applies whenever transfers to the device bypass the kernel I/O
+# scheduler, for example with SG_IO. If not present, there is no
+# specific maximum.
+#
+# @max-iov: Maximum number of scatter/gather elements
+#
+# @max-hw-iov: Maximum number of scatter/gather elements allowed by
+# the hardware. Applies whenever transfers to the device bypass
+# the kernel I/O scheduler, for example with SG_IO. If not
+# present, the hardware limits is unknown and @max-iov is always
+# used.
+#
+# @min-mem-alignment: Minimal required memory alignment in bytes for
+# zero-copy I/O to succeed. For unaligned requests, a bounce
+# buffer will be used.
+#
+# @opt-mem-alignment: Optimal memory alignment in bytes. This is the
+# alignment used for any buffer allocations QEMU performs
+# internally.
+##
+{ 'struct': 'BlockLimitsInfo',
+ 'data': { 'request-alignment': 'uint32',
+ '*max-discard': 'uint64',
+ '*discard-alignment': 'uint32',
+ '*max-write-zeroes': 'uint64',
+ '*write-zeroes-alignment': 'uint32',
+ '*opt-transfer': 'uint32',
+ '*max-transfer': 'uint32',
+ '*max-hw-transfer': 'uint32',
+ 'max-iov': 'int',
+ '*max-hw-iov': 'int',
+ 'min-mem-alignment': 'size',
+ 'opt-mem-alignment': 'size' } }
+
+##
# @BlockNodeInfo:
#
# Information about a QEMU image file
@@ -304,6 +367,8 @@
#
# @snapshots: list of VM snapshots
#
+# @limits: block limits that are used for I/O on the node (Since 10.2)
+#
# @format-specific: structure supplying additional format-specific
# information (since 1.7)
#
@@ -315,6 +380,7 @@
'*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
+ '*limits': 'BlockLimitsInfo',
'*format-specific': 'ImageInfoSpecific' } }
##
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 2c5a8a2..6bc8265 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -66,9 +66,9 @@
ERST
DEF("info", img_info,
- "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [-U] filename")
+ "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-t CACHE] [-U] filename")
SRST
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
ERST
DEF("map", img_map,
diff --git a/qemu-img.c b/qemu-img.c
index 7a162fd..a779189 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -86,6 +86,7 @@
OPTION_BITMAPS = 275,
OPTION_FORCE = 276,
OPTION_SKIP_BROKEN = 277,
+ OPTION_LIMITS = 278,
};
typedef enum OutputFormat {
@@ -3002,12 +3003,23 @@
static BlockGraphInfoList *collect_image_info_list(bool image_opts,
const char *filename,
const char *fmt,
- bool chain, bool force_share)
+ const char *cache,
+ bool chain, bool limits,
+ bool force_share)
{
BlockGraphInfoList *head = NULL;
BlockGraphInfoList **tail = &head;
GHashTable *filenames;
Error *err = NULL;
+ int cache_flags = 0;
+ bool writethrough = false;
+ int ret;
+
+ ret = bdrv_parse_cache_mode(cache, &cache_flags, &writethrough);
+ if (ret < 0) {
+ error_report("Invalid cache option: %s", cache);
+ return NULL;
+ }
filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
@@ -3024,8 +3036,8 @@
g_hash_table_insert(filenames, (gpointer)filename, NULL);
blk = img_open(image_opts, filename, fmt,
- BDRV_O_NO_BACKING | BDRV_O_NO_IO, false, false,
- force_share);
+ BDRV_O_NO_BACKING | BDRV_O_NO_IO | cache_flags,
+ writethrough, false, force_share);
if (!blk) {
goto err;
}
@@ -3039,7 +3051,7 @@
* the chain manually here.
*/
bdrv_graph_rdlock_main_loop();
- bdrv_query_block_graph_info(bs, &info, &err);
+ bdrv_query_block_graph_info(bs, &info, limits, &err);
bdrv_graph_rdunlock_main_loop();
if (err) {
@@ -3085,9 +3097,11 @@
OutputFormat output_format = OFORMAT_HUMAN;
bool chain = false;
const char *filename, *fmt;
+ const char *cache = BDRV_DEFAULT_CACHE;
BlockGraphInfoList *list;
bool image_opts = false;
bool force_share = false;
+ bool limits = false;
fmt = NULL;
for(;;) {
@@ -3096,12 +3110,14 @@
{"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
+ {"cache", required_argument, 0, 't'},
{"force-share", no_argument, 0, 'U'},
+ {"limits", no_argument, 0, OPTION_LIMITS},
{"output", required_argument, 0, OPTION_OUTPUT},
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hf:U", long_options, NULL);
+ c = getopt_long(argc, argv, "hf:t:U", long_options, NULL);
if (c == -1) {
break;
}
@@ -3117,8 +3133,12 @@
" (incompatible with -f|--format)\n"
" --backing-chain\n"
" display information about the backing chain for copy-on-write overlays\n"
+" -t, --cache CACHE\n"
+" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
" -U, --force-share\n"
" open image in shared mode for concurrent access\n"
+" --limits\n"
+" show detected block limits (may depend on options, e.g. cache mode)\n"
" --output human|json\n"
" specify output format (default: human)\n"
" --object OBJDEF\n"
@@ -3137,9 +3157,15 @@
case OPTION_BACKING_CHAIN:
chain = true;
break;
+ case 't':
+ cache = optarg;
+ break;
case 'U':
force_share = true;
break;
+ case OPTION_LIMITS:
+ limits = true;
+ break;
case OPTION_OUTPUT:
output_format = parse_output_format(argv[0], optarg);
break;
@@ -3155,8 +3181,8 @@
}
filename = argv[optind++];
- list = collect_image_info_list(image_opts, filename, fmt, chain,
- force_share);
+ list = collect_image_info_list(image_opts, filename, fmt, cache, chain,
+ limits, force_share);
if (!list) {
return 1;
}
diff --git a/scripts/ci/setup/ubuntu/build-environment.yml b/scripts/ci/setup/build-environment.yml
similarity index 63%
rename from scripts/ci/setup/ubuntu/build-environment.yml
rename to scripts/ci/setup/build-environment.yml
index 0f8ec5f..528150d 100644
--- a/scripts/ci/setup/ubuntu/build-environment.yml
+++ b/scripts/ci/setup/build-environment.yml
@@ -19,32 +19,38 @@
- '((ansible_version.major == 2) and (ansible_version.minor >= 8)) or (ansible_version.major >= 3)'
msg: "Unsuitable ansible version, please use version 2.8.0 or later"
- - name: Add armhf foreign architecture to aarch64 hosts
- command: dpkg --add-architecture armhf
- when:
- - ansible_facts['distribution'] == 'Ubuntu'
- - ansible_facts['architecture'] == 'aarch64'
-
- name: Update apt cache / upgrade packages via apt
apt:
update_cache: yes
upgrade: yes
when:
- - ansible_facts['distribution'] == 'Ubuntu'
+ - ansible_facts['distribution'] in ['Ubuntu', 'Debian']
# the package lists are updated by "make lcitool-refresh"
- - name: Include package lists based on OS and architecture
- include_vars:
- file: "ubuntu-2404-{{ ansible_facts['architecture'] }}.yaml"
+ - name: Define package list file path for Ubuntu
+ set_fact:
+ package_file: "ubuntu/ubuntu-2404-{{ ansible_facts['architecture'] }}.yaml"
when:
- ansible_facts['distribution'] == 'Ubuntu'
- ansible_facts['distribution_version'] == '24.04'
- - name: Install packages for QEMU on Ubuntu 24.04
+ - name: Define package list file path for Debian
+ set_fact:
+ package_file: "debian/debian-{{ ansible_facts['distribution_major_version'] }}-{{ ansible_facts['architecture'] }}.yaml"
+ when:
+ - ansible_facts['distribution'] == 'Debian'
+
+ - name: Include package lists based on OS and architecture
+ include_vars:
+ file: "{{ package_file }}"
+ when:
+ - package_file is exists
+
+ - name: Install packages for QEMU on Ubuntu/Debian
package:
name: "{{ packages }}"
when:
- - ansible_facts['distribution'] == 'Ubuntu'
- - ansible_facts['distribution_version'] == '24.04'
+ - package_file is exists
+ - packages is defined
diff --git a/scripts/ci/setup/debian/debian-13-ppc64le.yaml b/scripts/ci/setup/debian/debian-13-ppc64le.yaml
new file mode 100644
index 0000000..e29c9c1
--- /dev/null
+++ b/scripts/ci/setup/debian/debian-13-ppc64le.yaml
@@ -0,0 +1,134 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+# $ lcitool variables --host-arch ppc64le debian-13 qemu
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+packages:
+ - bash
+ - bc
+ - bindgen
+ - bison
+ - bsdextrautils
+ - bzip2
+ - ca-certificates
+ - ccache
+ - clang
+ - dbus
+ - debianutils
+ - diffutils
+ - exuberant-ctags
+ - findutils
+ - flex
+ - gcc
+ - gcovr
+ - gettext
+ - git
+ - hostname
+ - libaio-dev
+ - libasan8
+ - libasound2-dev
+ - libattr1-dev
+ - libbpf-dev
+ - libbrlapi-dev
+ - libbz2-dev
+ - libc6-dev
+ - libcacard-dev
+ - libcap-ng-dev
+ - libcapstone-dev
+ - libcbor-dev
+ - libclang-rt-dev
+ - libcmocka-dev
+ - libcurl4-gnutls-dev
+ - libdaxctl-dev
+ - libdrm-dev
+ - libepoxy-dev
+ - libfdt-dev
+ - libffi-dev
+ - libfuse3-dev
+ - libgbm-dev
+ - libgcrypt20-dev
+ - libglib2.0-dev
+ - libglusterfs-dev
+ - libgnutls28-dev
+ - libgtk-3-dev
+ - libgtk-vnc-2.0-dev
+ - libibverbs-dev
+ - libiscsi-dev
+ - libjemalloc-dev
+ - libjpeg62-turbo-dev
+ - libjson-c-dev
+ - liblttng-ust-dev
+ - liblzo2-dev
+ - libncursesw5-dev
+ - libnfs-dev
+ - libnuma-dev
+ - libpam0g-dev
+ - libpcre2-dev
+ - libpipewire-0.3-dev
+ - libpixman-1-dev
+ - libpng-dev
+ - libpulse-dev
+ - librbd-dev
+ - librdmacm-dev
+ - libsasl2-dev
+ - libsdl2-dev
+ - libsdl2-image-dev
+ - libseccomp-dev
+ - libselinux1-dev
+ - libslirp-dev
+ - libsnappy-dev
+ - libsndio-dev
+ - libspice-protocol-dev
+ - libspice-server-dev
+ - libssh-dev
+ - libstd-rust-dev
+ - libsystemd-dev
+ - libtasn1-6-dev
+ - libubsan1
+ - libudev-dev
+ - liburing-dev
+ - libusb-1.0-0-dev
+ - libusbredirhost-dev
+ - libvdeplug-dev
+ - libvirglrenderer-dev
+ - libvte-2.91-dev
+ - libxdp-dev
+ - libzstd-dev
+ - llvm
+ - locales
+ - make
+ - mtools
+ - multipath-tools
+ - ncat
+ - nettle-dev
+ - ninja-build
+ - openssh-client
+ - pkgconf
+ - python3
+ - python3-numpy
+ - python3-opencv
+ - python3-pillow
+ - python3-pip
+ - python3-setuptools
+ - python3-sphinx
+ - python3-sphinx-rtd-theme
+ - python3-tomli
+ - python3-venv
+ - python3-wheel
+ - python3-yaml
+ - rpm2cpio
+ - rustc
+ - sed
+ - socat
+ - sparse
+ - swtpm
+ - systemtap-sdt-dev
+ - tar
+ - tesseract-ocr
+ - tesseract-ocr-eng
+ - vulkan-tools
+ - xorriso
+ - zlib1g-dev
+ - zstd
+
diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml
index 7025935..76aeaf4 100644
--- a/scripts/ci/setup/gitlab-runner.yml
+++ b/scripts/ci/setup/gitlab-runner.yml
@@ -56,12 +56,12 @@
url: "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh"
mode: 0755
when:
- - ansible_facts['distribution'] == 'Ubuntu'
+ - ansible_facts['distribution'] in ['Ubuntu', 'Debian']
- name: Run gitlab-runner repo setup script (DEB)
shell: "/root/script.deb.sh"
when:
- - ansible_facts['distribution'] == 'Ubuntu'
+ - ansible_facts['distribution'] in ['Ubuntu', 'Debian']
- name: Install gitlab-runner (DEB)
ansible.builtin.apt:
@@ -69,7 +69,7 @@
update_cache: yes
state: present
when:
- - ansible_facts['distribution'] == 'Ubuntu'
+ - ansible_facts['distribution'] in ['Ubuntu', 'Debian']
# RPM setup
- name: Get gitlab-runner repo setup script (RPM)
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
index ce632d9..70063db 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
@@ -26,7 +26,7 @@
- git
- hostname
- libaio-dev
- - libasan6
+ - libasan8
- libasound2-dev
- libattr1-dev
- libbpf-dev
@@ -37,7 +37,7 @@
- libcap-ng-dev
- libcapstone-dev
- libcbor-dev
- - libclang-dev
+ - libclang-rt-dev
- libcmocka-dev
- libcurl4-gnutls-dev
- libdaxctl-dev
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
index f45f75c..4f1a49b 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
@@ -26,7 +26,7 @@
- git
- hostname
- libaio-dev
- - libasan6
+ - libasan8
- libasound2-dev
- libattr1-dev
- libbpf-dev
@@ -37,7 +37,7 @@
- libcap-ng-dev
- libcapstone-dev
- libcbor-dev
- - libclang-dev
+ - libclang-rt-dev
- libcmocka-dev
- libcurl4-gnutls-dev
- libdaxctl-dev
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 6100126..c5a07cb 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -316,10 +316,7 @@
&size, 8, 0)) {
ret = -1, err = EFAULT;
} else {
- size = be64_to_cpu(size);
- if (ret != size) {
- ret = -1, err = EOVERFLOW;
- }
+ ret = be64_to_cpu(size);
}
}
common_semi_cb(cs, ret, err);
diff --git a/target-info-qom.c b/target-info-qom.c
new file mode 100644
index 0000000..7fd58d2
--- /dev/null
+++ b/target-info-qom.c
@@ -0,0 +1,24 @@
+/*
+ * QEMU binary/target API (QOM types)
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qom/object.h"
+#include "hw/arm/machines-qom.h"
+
+static const TypeInfo target_info_types[] = {
+ {
+ .name = TYPE_TARGET_ARM_MACHINE,
+ .parent = TYPE_INTERFACE,
+ },
+ {
+ .name = TYPE_TARGET_AARCH64_MACHINE,
+ .parent = TYPE_INTERFACE,
+ },
+};
+
+DEFINE_TYPES(target_info_types)
diff --git a/target-info.c b/target-info.c
index 3110ab3..24696ff 100644
--- a/target-info.c
+++ b/target-info.c
@@ -52,3 +52,24 @@
{
return target_endian_mode() == ENDIAN_MODE_BIG;
}
+
+bool target_base_arm(void)
+{
+ switch (target_arch()) {
+ case SYS_EMU_TARGET_ARM:
+ case SYS_EMU_TARGET_AARCH64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool target_arm(void)
+{
+ return target_arch() == SYS_EMU_TARGET_ARM;
+}
+
+bool target_aarch64(void)
+{
+ return target_arch() == SYS_EMU_TARGET_AARCH64;
+}
diff --git a/target/alpha/helper.c b/target/alpha/helper.c
index 096eac3..a9af52a 100644
--- a/target/alpha/helper.c
+++ b/target/alpha/helper.c
@@ -27,6 +27,7 @@
#include "exec/helper-proto.h"
#include "qemu/qemu-print.h"
#include "system/memory.h"
+#include "qemu/plugin.h"
#define CONVERT_BIT(X, SRC, DST) \
@@ -328,6 +329,7 @@
{
CPUAlphaState *env = cpu_env(cs);
int i = cs->exception_index;
+ uint64_t last_pc = env->pc;
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
@@ -431,6 +433,17 @@
/* Switch to PALmode. */
env->flags |= ENV_FLAG_PAL_MODE;
+
+ switch (i) {
+ case EXCP_SMP_INTERRUPT:
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ break;
+ }
}
bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2ef9c17..ef6435c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -34,6 +34,7 @@
#endif
#include "cpregs.h"
#include "target/arm/gtimer.h"
+#include "qemu/plugin.h"
#define HELPER_H "tcg/helper.h"
#include "exec/helper-proto.h.inc"
@@ -8783,6 +8784,24 @@
}
}
+void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from)
+{
+ switch (cs->exception_index) {
+ case EXCP_IRQ:
+ case EXCP_VIRQ:
+ case EXCP_NMI:
+ case EXCP_VINMI:
+ case EXCP_FIQ:
+ case EXCP_VFIQ:
+ case EXCP_VFNMI:
+ case EXCP_VSERR:
+ qemu_plugin_vcpu_interrupt_cb(cs, from);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, from);
+ }
+}
+
static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
{
/*
@@ -9473,6 +9492,7 @@
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
+ uint64_t last_pc = cs->cc->get_pc(cs);
assert(!arm_feature(env, ARM_FEATURE_M));
@@ -9489,6 +9509,7 @@
if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
return;
}
@@ -9500,6 +9521,7 @@
#ifdef CONFIG_TCG
if (cs->exception_index == EXCP_SEMIHOST) {
tcg_handle_semihosting(cs);
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
return;
}
#endif
@@ -9525,6 +9547,8 @@
if (!kvm_enabled()) {
cpu_set_interrupt(cs, CPU_INTERRUPT_EXITTB);
}
+
+ arm_do_plugin_vcpu_discon_cb(cs, last_pc);
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/arm/internals.h b/target/arm/internals.h
index f86f421..6fbf7e1 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -375,6 +375,7 @@
void arm_cpu_register(const ARMCPUInfo *info);
+void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from);
void register_cp_regs_for_features(ARMCPU *cpu);
void init_cpreg_list(ARMCPU *cpu);
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 44a0cf8..0befdb0 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -9,6 +9,7 @@
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "target/arm/gtimer.h"
+#include "hw/arm/machines-qom.h"
static bool vfp_needed(void *opaque)
{
@@ -1212,3 +1213,20 @@
NULL
}
};
+
+const InterfaceInfo arm_machine_interfaces[] = {
+ { TYPE_TARGET_ARM_MACHINE },
+ { TYPE_TARGET_AARCH64_MACHINE },
+ { }
+};
+
+const InterfaceInfo arm_aarch64_machine_interfaces[] = {
+ { TYPE_TARGET_ARM_MACHINE },
+ { TYPE_TARGET_AARCH64_MACHINE },
+ { }
+};
+
+const InterfaceInfo aarch64_machine_interfaces[] = {
+ { TYPE_TARGET_AARCH64_MACHINE },
+ { }
+};
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 23f6616..2e6b149 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -2352,7 +2352,7 @@
* CPUs with ARM_FEATURE_LPAE but not ARM_FEATURE_V7VE anyway.)
*/
if (device) {
- unsigned a_bits = memop_atomicity_bits(memop);
+ unsigned a_bits = memop_tlb_alignment_bits(memop, true);
if (address & ((1 << a_bits) - 1)) {
fi->type = ARMFault_Alignment;
goto do_fault;
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index d856e3b..3fb24c7 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -23,6 +23,7 @@
#if !defined(CONFIG_USER_ONLY)
#include "hw/intc/armv7m_nvic.h"
#endif
+#include "qemu/plugin.h"
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
uint32_t reg, uint32_t val)
@@ -2194,6 +2195,7 @@
CPUARMState *env = &cpu->env;
uint32_t lr;
bool ignore_stackfaults;
+ uint64_t last_pc = env->regs[15];
arm_log_exception(cs);
@@ -2361,6 +2363,7 @@
g_assert_not_reached();
#endif
env->regs[15] += env->thumb ? 2 : 4;
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
return;
case EXCP_BKPT:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
@@ -2427,6 +2430,8 @@
ignore_stackfaults = v7m_push_stack(cpu);
v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
+
+ arm_do_plugin_vcpu_discon_cb(cs, last_pc);
}
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 3292d7c..08b21d7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -3691,9 +3691,8 @@
* In all cases, issue one operation with the correct atomicity.
*/
mop = a->sz + 1;
- if (s->align_mem) {
- mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
- }
+ mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
+ mop |= (s->align_mem ? 0 : MO_ALIGN_TLB_ONLY);
mop = finalize_memop_pair(s, mop);
if (a->sz == 2) {
TCGv_i64 tmp = tcg_temp_new_i64();
@@ -3742,9 +3741,8 @@
* since that reuses the most code below.
*/
mop = a->sz + 1;
- if (s->align_mem) {
- mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
- }
+ mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
+ mop |= (s->align_mem ? 0 : MO_ALIGN_TLB_ONLY);
mop = finalize_memop_pair(s, mop);
if (a->sz == 2) {
int o2 = s->be_data == MO_LE ? 32 : 0;
diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c
index 844d2e2..e3c7d92 100644
--- a/target/arm/tcg/translate-neon.c
+++ b/target/arm/tcg/translate-neon.c
@@ -520,7 +520,7 @@
if (a->align) {
align = pow2_align(a->align + 2); /* 4 ** a->align */
} else {
- align = s->align_mem ? MO_ALIGN : 0;
+ align = MO_ALIGN | (s->align_mem ? 0 : MO_ALIGN_TLB_ONLY);
}
/*
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 9a85ea7..b62104b 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -744,8 +744,8 @@
*/
static inline MemOp finalize_memop_atom(DisasContext *s, MemOp opc, MemOp atom)
{
- if (s->align_mem && !(opc & MO_AMASK)) {
- opc |= MO_ALIGN;
+ if (!(opc & MO_AMASK)) {
+ opc |= MO_ALIGN | (s->align_mem ? 0 : MO_ALIGN_TLB_ONLY);
}
return opc | atom | s->be_data;
}
diff --git a/target/avr/helper.c b/target/avr/helper.c
index 4b29ab3..365c8c6 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -28,6 +28,7 @@
#include "exec/target_page.h"
#include "accel/tcg/cpu-ldst.h"
#include "exec/helper-proto.h"
+#include "qemu/plugin.h"
bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
@@ -102,6 +103,8 @@
env->sregI = 0; /* clear Global Interrupt Flag */
cs->exception_index = -1;
+
+ qemu_plugin_vcpu_interrupt_cb(cs, ret);
}
hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 191ae19..4e48692 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -24,6 +24,7 @@
#include "exec/helper-proto.h"
#include "hw/core/cpu.h"
#include "hw/hppa/hppa_hardware.h"
+#include "qemu/plugin.h"
static void eval_interrupt(HPPACPU *cpu)
{
@@ -95,6 +96,7 @@
CPUHPPAState *env = &cpu->env;
int i = cs->exception_index;
uint64_t old_psw, old_gva_offset_mask;
+ uint64_t last_pc = cs->cc->get_pc(cs);
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
@@ -212,6 +214,21 @@
env->iasq_f = 0;
env->iasq_b = 0;
+ switch (i) {
+ case EXCP_HPMC:
+ case EXCP_POWER_FAIL:
+ case EXCP_RC:
+ case EXCP_EXT_INTERRUPT:
+ case EXCP_LPMC:
+ case EXCP_PER_INTERRUPT:
+ case EXCP_TOC:
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ break;
+ }
+
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static const char * const names[] = {
[EXCP_HPMC] = "high priority machine check",
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index 6fb8036..32f2784 100644
--- a/target/i386/tcg/excp_helper.c
+++ b/target/i386/tcg/excp_helper.c
@@ -23,6 +23,7 @@
#include "system/runstate.h"
#include "exec/helper-proto.h"
#include "helper-tcg.h"
+#include "qemu/plugin.h"
G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno,
int next_eip_addend)
@@ -93,6 +94,7 @@
uintptr_t retaddr)
{
CPUState *cs = env_cpu(env);
+ uint64_t last_pc = env->eip + env->segs[R_CS].base;
if (!is_int) {
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
@@ -106,6 +108,7 @@
env->error_code = error_code;
env->exception_is_int = is_int;
env->exception_next_eip = env->eip + next_eip_addend;
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
cpu_loop_exit_restore(cs, retaddr);
}
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index f49fe85..667b1c3 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -29,6 +29,7 @@
#include "seg_helper.h"
#include "access.h"
#include "tcg-cpu.h"
+#include "qemu/plugin.h"
#ifdef TARGET_X86_64
#define SET_ESP(val, sp_mask) \
@@ -1192,6 +1193,7 @@
int error_code, target_ulong next_eip, int is_hw)
{
CPUX86State *env = &cpu->env;
+ uint64_t last_pc = env->eip + env->segs[R_CS].base;
if (qemu_loglevel_mask(CPU_LOG_INT)) {
if ((env->cr[0] & CR0_PE_MASK)) {
@@ -1263,6 +1265,8 @@
event_inj & ~SVM_EVTINJ_VALID);
}
#endif
+
+ qemu_plugin_vcpu_interrupt_cb(CPU(cpu), last_pc);
}
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index e80a92f..d74c3c3 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -236,7 +236,7 @@
cpu->ptw = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
if (kvm_enabled()) {
- /* PTW feature is only support in TCG mode now */
+ /* kvm feature detection in function kvm_arch_init_vcpu */
return;
}
@@ -406,14 +406,14 @@
static void loongarch_max_initfn(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
- /* '-cpu max' for TCG: we use cpu la464. */
+ /* '-cpu max': use it for max supported CPU features */
loongarch_la464_initfn(obj);
+ cpu->ptw = ON_OFF_AUTO_AUTO;
if (tcg_enabled()) {
cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1);
cpu->msgint = ON_OFF_AUTO_AUTO;
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, HPTW, 1);
- cpu->ptw = ON_OFF_AUTO_AUTO;
}
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index b1d6799..1a14469 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -279,6 +279,7 @@
LOONGARCH_FEATURE_PMU,
LOONGARCH_FEATURE_PV_IPI,
LOONGARCH_FEATURE_STEALTIME,
+ LOONGARCH_FEATURE_PTW,
};
typedef struct LoongArchBT {
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 4e4f4e7..26e40c9 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -931,6 +931,12 @@
ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
return (ret == 0);
+ case LOONGARCH_FEATURE_PTW:
+ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
+ attr.attr = KVM_LOONGARCH_VM_FEAT_PTW;
+ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
+ return (ret == 0);
+
default:
return false;
}
@@ -1029,6 +1035,29 @@
return 0;
}
+static int kvm_cpu_check_ptw(CPUState *cs, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = cpu_env(cs);
+ bool kvm_supported;
+
+ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PTW);
+ if (cpu->ptw == ON_OFF_AUTO_ON) {
+ if (!kvm_supported) {
+ error_setg(errp, "'ptw' feature not supported by KVM on the host");
+ return -ENOTSUP;
+ }
+ } else if (cpu->ptw != ON_OFF_AUTO_AUTO) {
+ /* disable pmu if ON_OFF_AUTO_OFF is set */
+ kvm_supported = false;
+ }
+
+ if (kvm_supported) {
+ env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, HPTW, 1);
+ }
+ return 0;
+}
+
static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
@@ -1123,6 +1152,12 @@
return ret;
}
+ ret = kvm_cpu_check_ptw(cs, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
+
return 0;
}
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 82b54e6..9d077c5 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -8,6 +8,7 @@
#include "qemu/accel.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
+#include "qemu/plugin.h"
#include "accel/accel-cpu-target.h"
#include "accel/tcg/cpu-ldst.h"
#include "accel/tcg/cpu-ops.h"
@@ -80,6 +81,7 @@
int cause = -1;
bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
+ uint64_t last_pc = env->pc;
if (cs->exception_index != EXCCODE_INT) {
qemu_log_mask(CPU_LOG_INT,
@@ -190,6 +192,7 @@
__func__, env->pc, env->CSR_ERA,
cause, env->CSR_BADV, env->CSR_DERA, vector,
env->CSR_ECFG, env->CSR_ESTAT);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
} else {
if (tlbfill) {
set_pc(env, env->CSR_TLBRENTRY);
@@ -208,6 +211,7 @@
tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
env->CSR_BADI, env->gpr[11], cs->cpu_index,
env->CSR_ASID);
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
}
cs->exception_index = -1;
}
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index f29ae12..e9c20a8 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -22,6 +22,7 @@
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst.h"
#include "semihosting/semihost.h"
+#include "qemu/plugin.h"
#if !defined(CONFIG_USER_ONLY)
@@ -183,6 +184,21 @@
return "Unassigned";
}
+static void do_plugin_vcpu_interrupt_cb(CPUState *cs, uint64_t from)
+{
+ switch (cs->exception_index) {
+ case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7:
+ qemu_plugin_vcpu_interrupt_cb(cs, from);
+ break;
+ case EXCP_SEMIHOSTING:
+ qemu_plugin_vcpu_hostcall_cb(cs, from);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, from);
+ break;
+ }
+}
+
static void cf_interrupt_all(CPUM68KState *env, int is_hw)
{
CPUState *cs = env_cpu(env);
@@ -203,6 +219,7 @@
return;
case EXCP_SEMIHOSTING:
do_m68k_semihosting(env, env->dregs[0]);
+ qemu_plugin_vcpu_hostcall_cb(cs, retaddr);
return;
}
}
@@ -239,6 +256,8 @@
env->aregs[7] = sp;
/* Jump to vector. */
env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
+
+ do_plugin_vcpu_interrupt_cb(cs, retaddr);
}
static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
@@ -277,6 +296,7 @@
uint32_t sp;
uint32_t vector;
uint16_t sr, oldsr;
+ uint64_t last_pc = env->pc;
if (!is_hw) {
switch (cs->exception_index) {
@@ -417,6 +437,8 @@
env->aregs[7] = sp;
/* Jump to vector. */
env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
+
+ do_plugin_vcpu_interrupt_cb(cs, last_pc);
}
static void do_interrupt_all(CPUM68KState *env, int is_hw)
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 14b1078..d26b933 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -87,6 +87,7 @@
#define ESR_ESS_FSL_OFFSET 5
#define ESR_ESS_MASK (0x7f << 5)
+#define ESR_ESS_DEC_OF (1 << 11) /* DEC: 0=DBZ, 1=OF */
#define ESR_EC_FSL 0
#define ESR_EC_UNALIGNED_DATA 1
diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c
index cf577a7..a1857b7 100644
--- a/target/microblaze/helper.c
+++ b/target/microblaze/helper.c
@@ -27,6 +27,7 @@
#include "qemu/host-utils.h"
#include "exec/log.h"
#include "exec/helper-proto.h"
+#include "qemu/plugin.h"
G_NORETURN
@@ -35,6 +36,7 @@
{
CPUMBState *env = cpu_env(cs);
uint32_t esr, iflags;
+ uint64_t last_pc = env->pc;
/* Recover the pc and iflags from the corresponding insn_start. */
cpu_restore_state(cs, retaddr);
@@ -54,6 +56,7 @@
env->ear = addr;
env->esr = esr;
cs->exception_index = EXCP_HW_EXCP;
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
cpu_loop_exit(cs);
}
@@ -152,6 +155,7 @@
CPUMBState *env = &cpu->env;
uint32_t t, msr = mb_cpu_read_msr(env);
bool set_esr;
+ uint64_t last_pc = env->pc;
/* IMM flag cannot propagate across a branch and into the dslot. */
assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG));
@@ -256,6 +260,12 @@
env->res_addr = RES_ADDR_NONE;
env->iflags = 0;
+ if (cs->exception_index == EXCP_IRQ) {
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ }
+
if (!set_esr) {
qemu_log_mask(CPU_LOG_INT,
" to pc=%08x msr=%08x\n", env->pc, msr);
diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c
index df93c42..31da2c7 100644
--- a/target/microblaze/op_helper.c
+++ b/target/microblaze/op_helper.c
@@ -69,38 +69,51 @@
cpu_loop_exit(cs);
}
-static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
+/* Raises ESR_EC_DIVZERO if exceptions are enabled. */
+static void raise_divzero(CPUMBState *env, uint32_t esr, uintptr_t unwind_pc)
{
- if (unlikely(b == 0)) {
- env->msr |= MSR_DZ;
+ env->msr |= MSR_DZ;
- if ((env->msr & MSR_EE) &&
- env_archcpu(env)->cfg.div_zero_exception) {
- CPUState *cs = env_cpu(env);
+ if ((env->msr & MSR_EE) && env_archcpu(env)->cfg.div_zero_exception) {
+ CPUState *cs = env_cpu(env);
- env->esr = ESR_EC_DIVZERO;
- cs->exception_index = EXCP_HW_EXCP;
- cpu_loop_exit_restore(cs, ra);
- }
- return false;
+ env->esr = esr;
+ cs->exception_index = EXCP_HW_EXCP;
+ cpu_loop_exit_restore(cs, unwind_pc);
}
- return true;
}
-uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
+uint32_t helper_divs(CPUMBState *env, uint32_t ra, uint32_t rb)
{
- if (!check_divz(env, a, b, GETPC())) {
+ if (!ra) {
+ raise_divzero(env, ESR_EC_DIVZERO, GETPC());
return 0;
}
- return (int32_t)a / (int32_t)b;
+
+ /*
+ * Check for division overflows.
+ *
+ * Spec: https://docs.amd.com/r/en-US/ug984-vivado-microblaze-ref/idiv
+ * UG984, Chapter 5 MicroBlaze Instruction Set Architecture, idiv.
+ *
+ * If the U bit is clear, the value of rA is -1, and the value of rB is
+ * -2147483648 (divide overflow), the DZO bit in MSR will be set and
+ * the value in rD will be -2147483648, unless an exception is generated.
+ */
+ if ((int32_t)ra == -1 && (int32_t)rb == INT32_MIN) {
+ raise_divzero(env, ESR_EC_DIVZERO | ESR_ESS_DEC_OF, GETPC());
+ return INT32_MIN;
+ }
+ return (int32_t)rb / (int32_t)ra;
}
-uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
+uint32_t helper_divu(CPUMBState *env, uint32_t ra, uint32_t rb)
{
- if (!check_divz(env, a, b, GETPC())) {
+ if (!ra) {
+ raise_divzero(env, ESR_EC_DIVZERO, GETPC());
return 0;
}
- return a / b;
+ return rb / ra;
}
/* raise FPU exception. */
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 6442a25..fefe5cb 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -450,16 +450,8 @@
DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
-/* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
-static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
-{
- gen_helper_divs(out, tcg_env, inb, ina);
-}
-
-static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
-{
- gen_helper_divu(out, tcg_env, inb, ina);
-}
+ENV_WRAPPER3(gen_idiv, gen_helper_divs)
+ENV_WRAPPER3(gen_idivu, gen_helper_divu)
DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c
index 1e89015..566924b 100644
--- a/target/mips/tcg/system/tlb_helper.c
+++ b/target/mips/tcg/system/tlb_helper.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
+#include "qemu/plugin.h"
#include "cpu.h"
#include "internal.h"
@@ -1034,6 +1035,7 @@
bool update_badinstr = 0;
target_ulong offset;
int cause = -1;
+ uint64_t last_pc = env->active_tc.PC;
if (qemu_loglevel_mask(CPU_LOG_INT)
&& cs->exception_index != EXCP_EXT_INTERRUPT) {
@@ -1052,6 +1054,7 @@
cs->exception_index = EXCP_NONE;
mips_semihosting(env);
env->active_tc.PC += env->error_code;
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
return;
case EXCP_DSS:
env->CP0_Debug |= 1 << CP0DB_DSS;
@@ -1336,6 +1339,14 @@
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
+ switch (cs->exception_index) {
+ case EXCP_NMI:
+ case EXCP_EXT_INTERRUPT:
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ }
cs->exception_index = EXCP_NONE;
}
diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c
index 4868230..d357aaa 100644
--- a/target/openrisc/interrupt.c
+++ b/target/openrisc/interrupt.c
@@ -25,11 +25,13 @@
#ifndef CONFIG_USER_ONLY
#include "hw/loader.h"
#endif
+#include "qemu/plugin.h"
void openrisc_cpu_do_interrupt(CPUState *cs)
{
CPUOpenRISCState *env = cpu_env(cs);
int exception = cs->exception_index;
+ uint64_t last_pc = env->pc;
env->epcr = env->pc;
@@ -98,6 +100,19 @@
cpu_abort(cs, "Unhandled exception 0x%x\n", exception);
}
+ switch (exception) {
+ case EXCP_RESET:
+ /* Resets are already exposed to plugins through a dedicated callback */
+ break;
+ case EXCP_TICK:
+ case EXCP_INT:
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ break;
+ }
+
cs->exception_index = -1;
}
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d8bca19..6d05b86 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "helper_regs.h"
#include "hw/ppc/ppc.h"
+#include "qemu/plugin.h"
#include "trace.h"
@@ -404,11 +405,31 @@
powerpc_checkstop(env, "machine check with MSR[ME]=0");
}
+static void powerpc_do_plugin_vcpu_interrupt_cb(CPUState *cs, int excp,
+ uint64_t from)
+{
+ switch (excp) {
+ case POWERPC_EXCP_NONE:
+ break;
+ case POWERPC_EXCP_FIT:
+ case POWERPC_EXCP_WDT:
+ case POWERPC_EXCP_PIT:
+ case POWERPC_EXCP_SMI:
+ case POWERPC_EXCP_PERFM:
+ case POWERPC_EXCP_THERM:
+ qemu_plugin_vcpu_interrupt_cb(cs, from);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, from);
+ }
+}
+
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
int srr0 = SPR_SRR0, srr1 = SPR_SRR1;
+ uint64_t last_pc = env->nip;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -456,6 +477,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
env->spr[SPR_40x_ESR] = ESR_FP;
@@ -510,12 +532,14 @@
env->spr[srr0] = env->nip;
env->spr[srr1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
+ uint64_t last_pc = env->nip;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -567,6 +591,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
/*
@@ -653,12 +678,14 @@
env->spr[SPR_SRR0] = env->nip;
env->spr[SPR_SRR1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
+ uint64_t last_pc = env->nip;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -708,6 +735,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
/*
@@ -758,6 +786,7 @@
if (lev == 1 && cpu->vhyp) {
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
return;
}
@@ -803,12 +832,14 @@
env->spr[SPR_SRR0] = env->nip;
env->spr[SPR_SRR1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
+ uint64_t last_pc = env->nip;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -858,6 +889,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
/*
@@ -908,6 +940,7 @@
if (lev == 1 && cpu->vhyp) {
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
return;
}
@@ -947,6 +980,7 @@
env->spr[SPR_SRR0] = env->nip;
env->spr[SPR_SRR1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
@@ -1073,6 +1107,7 @@
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
int srr0 = SPR_SRR0, srr1 = SPR_SRR1;
+ uint64_t last_pc = env->nip;
/*
* Book E does not play games with certain bits of xSRR1 being MSR save
@@ -1144,6 +1179,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
/*
@@ -1252,6 +1288,7 @@
env->spr[srr0] = env->nip;
env->spr[srr1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
/*
@@ -1373,6 +1410,7 @@
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
int srr0 = SPR_SRR0, srr1 = SPR_SRR1, lev = -1;
+ uint64_t last_pc = env->nip;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -1472,6 +1510,7 @@
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
trace_ppc_excp_fp_ignore();
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
return;
}
/*
@@ -1516,6 +1555,7 @@
if (lev == 1 && books_vhyp_handles_hcall(cpu)) {
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu);
+ qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
return;
}
if (env->insns_flags2 & PPC2_ISA310) {
@@ -1662,6 +1702,7 @@
ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector);
powerpc_set_excp_state(cpu, vector, new_msr);
}
+ powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
}
#else
static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 360db13..c4fb68b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -36,6 +36,7 @@
#include "cpu_bits.h"
#include "debug.h"
#include "pmp.h"
+#include "qemu/plugin.h"
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -2175,6 +2176,7 @@
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
const bool prev_virt = env->virt_enabled;
const target_ulong prev_priv = env->priv;
+ uint64_t last_pc = env->pc;
target_ulong tval = 0;
target_ulong tinst = 0;
target_ulong htval = 0;
@@ -2197,6 +2199,7 @@
case RISCV_EXCP_SEMIHOST:
do_common_semihosting(cs);
env->pc += 4;
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
return;
#endif
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
@@ -2466,6 +2469,12 @@
prev_priv, prev_virt);
}
+ if (async) {
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ }
+
/*
* Interrupt/exception/trap delivery is asynchronous event and as per
* zicfilp spec CPU should clear up the ELP state. No harm in clearing
diff --git a/target/rx/helper.c b/target/rx/helper.c
index 41c9606..ef47e32 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -22,6 +22,7 @@
#include "exec/log.h"
#include "accel/tcg/cpu-ldst.h"
#include "hw/irq.h"
+#include "qemu/plugin.h"
void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
{
@@ -46,6 +47,7 @@
CPURXState *env = cpu_env(cs);
int do_irq = cpu_test_interrupt(cs, INT_FLAGS);
uint32_t save_psw;
+ uint64_t last_pc = env->pc;
env->in_sleep = 0;
@@ -65,6 +67,7 @@
env->psw_ipl = 15;
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
qemu_set_irq(env->ack, env->ack_irq);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
} else if (do_irq & CPU_INTERRUPT_HARD) {
env->isp -= 4;
@@ -75,6 +78,7 @@
env->psw_ipl = env->ack_ipl;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
qemu_set_irq(env->ack, env->ack_irq);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT,
"interrupt 0x%02x raised\n", env->ack_irq);
}
@@ -92,6 +96,14 @@
} else {
env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
}
+
+ if (vec == 30) {
+ /* Non-maskable interrupt */
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
+ }
+
switch (vec) {
case 20:
expname = "privilege violation";
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index 0ae4e26..c664128 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -35,6 +35,7 @@
#include "hw/s390x/s390_flic.h"
#include "hw/boards.h"
#endif
+#include "qemu/plugin.h"
G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env,
uint32_t code, uintptr_t ra)
@@ -502,6 +503,7 @@
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
bool stopped = false;
+ uint64_t last_pc = cpu->env.psw.addr;
qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
__func__, cs->exception_index, env->psw.mask, env->psw.addr);
@@ -531,21 +533,27 @@
switch (cs->exception_index) {
case EXCP_PGM:
do_program_interrupt(env);
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
break;
case EXCP_SVC:
do_svc_interrupt(env);
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
break;
case EXCP_EXT:
do_ext_interrupt(env);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
break;
case EXCP_IO:
do_io_interrupt(env);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
break;
case EXCP_MCHK:
do_mchk_interrupt(env);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
break;
case EXCP_RESTART:
do_restart_interrupt(env);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
break;
case EXCP_STOP:
do_stop_interrupt(env);
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index 3b18a32..5d62956 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -24,6 +24,7 @@
#include "exec/page-protection.h"
#include "exec/target_page.h"
#include "exec/log.h"
+#include "qemu/plugin.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/sh4/sh_intc.h"
@@ -60,6 +61,7 @@
CPUSH4State *env = cpu_env(cs);
int do_irq = cpu_test_interrupt(cs, CPU_INTERRUPT_HARD);
int do_exp, irq_vector = cs->exception_index;
+ uint64_t last_pc = env->pc;
/* prioritize exceptions over interrupts */
@@ -176,12 +178,14 @@
env->pc = env->vbr + 0x100;
break;
}
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
return;
}
if (do_irq) {
env->intevt = irq_vector;
env->pc = env->vbr + 0x600;
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
return;
}
}
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index fdcaa0a..b29f693 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -24,6 +24,7 @@
#include "accel/tcg/cpu-ldst.h"
#include "exec/log.h"
#include "system/runstate.h"
+#include "qemu/plugin.h"
static const char * const excp_names[0x80] = {
[TT_TFAULT] = "Instruction Access Fault",
@@ -174,4 +175,10 @@
env->qemu_irq_ack(env, intno);
}
#endif
+
+ if (intno == TT_EXTINT) {
+ qemu_plugin_vcpu_interrupt_cb(cs, env->regwptr[9]);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs, env->regwptr[9]);
+ }
}
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index 96ef81c..60ab047 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -24,6 +24,7 @@
#include "exec/helper-proto.h"
#include "exec/log.h"
#include "trace.h"
+#include "qemu/plugin.h"
#define DEBUG_PCALL
@@ -256,6 +257,15 @@
}
env->npc = env->pc + 4;
cs->exception_index = -1;
+
+ switch (intno) {
+ case TT_EXTINT:
+ case TT_IVEC:
+ qemu_plugin_vcpu_interrupt_cb(cs, tsptr->tpc);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs, tsptr->tpc);
+ }
}
trap_state *cpu_tsptr(CPUSPARCState* env)
diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c
index 610f148..2c8281a 100644
--- a/target/tricore/op_helper.c
+++ b/target/tricore/op_helper.c
@@ -19,6 +19,7 @@
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst.h"
+#include "qemu/plugin.h"
#include <zlib.h> /* for crc32 */
@@ -29,8 +30,11 @@
uintptr_t pc, uint32_t fcd_pc)
{
CPUState *cs = env_cpu(env);
+ uint64_t last_pc;
+
/* in case we come from a helper-call we need to restore the PC */
cpu_restore_state(cs, pc);
+ last_pc = env->PC;
/* Tin is loaded into d[15] */
env->gpr_d[15] = tin;
@@ -90,6 +94,7 @@
/* Update PC using the trap vector table */
env->PC = env->BTV | (class << 5);
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
cpu_loop_exit(cs);
}
diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c
index b611c9b..fdc5226 100644
--- a/target/xtensa/exc_helper.c
+++ b/target/xtensa/exc_helper.c
@@ -32,6 +32,7 @@
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
#include "qemu/atomic.h"
+#include "qemu/plugin.h"
void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
{
@@ -207,6 +208,8 @@
CPUXtensaState *env = cpu_env(cs);
if (cs->exception_index == EXC_IRQ) {
+ uint64_t last_pc = env->pc;
+
qemu_log_mask(CPU_LOG_INT,
"%s(EXC_IRQ) level = %d, cintlevel = %d, "
"pc = %08x, a0 = %08x, ps = %08x, "
@@ -218,6 +221,7 @@
env->sregs[INTSET], env->sregs[INTENABLE],
env->sregs[CCOUNT]);
handle_interrupt(env);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
}
switch (cs->exception_index) {
@@ -238,9 +242,11 @@
env->sregs[CCOUNT]);
if (env->config->exception_vector[cs->exception_index]) {
uint32_t vector;
+ uint64_t last_pc = env->pc;
vector = env->config->exception_vector[cs->exception_index];
env->pc = relocated_vector(env, vector);
+ qemu_plugin_vcpu_exception_cb(cs, last_pc);
} else {
qemu_log_mask(CPU_LOG_INT,
"%s(pc = %08x) bad exception_index: %d\n",
diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index 552815e..28dfb29 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -35,6 +35,7 @@
#include "system/memory.h"
#include "qapi/error.h"
#include "qemu/log.h"
+#include "qemu/plugin.h"
enum {
TARGET_SYS_exit = 1,
@@ -197,6 +198,7 @@
CPUState *cs = env_cpu(env);
AddressSpace *as = cs->as;
uint32_t *regs = env->regs;
+ uint64_t last_pc = env->pc;
switch (regs[2]) {
case TARGET_SYS_exit:
@@ -433,4 +435,5 @@
regs[3] = TARGET_ENOSYS;
break;
}
+ qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
}
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index dfa5c38..ab7b409 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -1818,30 +1818,16 @@
tcg_gen_movi_i32(TCGV_LOW(ret), 0);
}
} else if (right) {
- if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) {
- tcg_gen_extract2_i32(TCGV_LOW(ret),
- TCGV_LOW(arg1), TCGV_HIGH(arg1), c);
- } else {
- tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
- tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(ret),
- TCGV_HIGH(arg1), 32 - c, c);
- }
+ tcg_gen_extract2_i32(TCGV_LOW(ret), TCGV_LOW(arg1),
+ TCGV_HIGH(arg1), c);
if (arith) {
tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
} else {
tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
}
} else {
- if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) {
- tcg_gen_extract2_i32(TCGV_HIGH(ret),
- TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c);
- } else {
- TCGv_i32 t0 = tcg_temp_ebb_new_i32();
- tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
- tcg_gen_deposit_i32(TCGV_HIGH(ret), t0,
- TCGV_HIGH(arg1), c, 32 - c);
- tcg_temp_free_i32(t0);
- }
+ tcg_gen_extract2_i32(TCGV_HIGH(ret), TCGV_LOW(arg1),
+ TCGV_HIGH(arg1), 32 - c);
tcg_gen_shli_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
}
}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 294762c..fbf09f5 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -3039,20 +3039,22 @@
case INDEX_op_qemu_ld2:
case INDEX_op_qemu_st2:
{
- const char *s_al, *s_op, *s_at;
+ const char *s_al, *s_tlb, *s_op, *s_at;
MemOpIdx oi = op->args[k++];
MemOp mop = get_memop(oi);
unsigned ix = get_mmuidx(oi);
+ s_tlb = mop & MO_ALIGN_TLB_ONLY ? "tlb+" : "";
s_al = alignment_name[(mop & MO_AMASK) >> MO_ASHIFT];
s_op = ldst_name[mop & (MO_BSWAP | MO_SSIZE)];
s_at = atom_name[(mop & MO_ATOM_MASK) >> MO_ATOM_SHIFT];
- mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE | MO_ATOM_MASK);
+ mop &= ~(MO_AMASK | MO_BSWAP | MO_SSIZE |
+ MO_ATOM_MASK | MO_ALIGN_TLB_ONLY);
/* If all fields are accounted for, print symbolically. */
if (!mop && s_al && s_op && s_at) {
- col += ne_fprintf(f, ",%s%s%s,%u",
- s_at, s_al, s_op, ix);
+ col += ne_fprintf(f, ",%s%s%s%s,%u",
+ s_at, s_al, s_tlb, s_op, ix);
} else {
mop = get_memop(oi);
col += ne_fprintf(f, ",$0x%x,%u", mop, ix);
diff --git a/tests/functional/mips/test_malta.py b/tests/functional/mips/test_malta.py
index 30279f0..7a734bc 100755
--- a/tests/functional/mips/test_malta.py
+++ b/tests/functional/mips/test_malta.py
@@ -9,6 +9,7 @@
import os
from qemu_test import LinuxKernelTest, Asset, wait_for_console_pattern
+from qemu_test import skipFlakyTest
from qemu_test import exec_command_and_wait_for_pattern
@@ -181,6 +182,7 @@ def test_mips_malta_cpio(self):
'debian_wheezy_mips_standard.qcow2'),
'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/3109")
def test_wheezy(self):
kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
image_path = self.ASSET_WHEEZY_DISK.fetch()
diff --git a/tests/functional/mips/test_replay.py b/tests/functional/mips/test_replay.py
index 4327481..747835b 100755
--- a/tests/functional/mips/test_replay.py
+++ b/tests/functional/mips/test_replay.py
@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset, skipSlowTest
+from qemu_test import skipFlakyTest
from replay_kernel import ReplayKernelBase
@@ -16,6 +17,7 @@ class MipsReplay(ReplayKernelBase):
'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb'),
'16ca524148afb0626f483163e5edf352bc1ab0e4fc7b9f9d473252762f2c7a43')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2013")
def test_replay_mips_malta(self):
self.set_machine('malta')
kernel_path = self.archive_extract(self.ASSET_KERNEL_2_63_2,
diff --git a/tests/functional/mips64/test_malta.py b/tests/functional/mips64/test_malta.py
index a553d3c..91c57c5 100755
--- a/tests/functional/mips64/test_malta.py
+++ b/tests/functional/mips64/test_malta.py
@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
+from qemu_test import skipFlakyTest
from mips.test_malta import mips_check_wheezy
@@ -20,6 +21,7 @@ class MaltaMachineConsole(LinuxKernelTest):
'debian_wheezy_mips_standard.qcow2'),
'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/3109")
def test_wheezy(self):
kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
image_path = self.ASSET_WHEEZY_DISK.fetch()
diff --git a/tests/functional/mips64el/test_malta.py b/tests/functional/mips64el/test_malta.py
index 170147b..e37463d 100755
--- a/tests/functional/mips64el/test_malta.py
+++ b/tests/functional/mips64el/test_malta.py
@@ -102,6 +102,7 @@ def test_mips64el_malta_5KEc_cpio(self):
'debian_wheezy_mipsel_standard.qcow2'),
'454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/3109")
def test_wheezy(self):
kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
image_path = self.ASSET_WHEEZY_DISK.fetch()
diff --git a/tests/functional/mips64el/test_replay.py b/tests/functional/mips64el/test_replay.py
index 26a6ccf..05cc585 100755
--- a/tests/functional/mips64el/test_replay.py
+++ b/tests/functional/mips64el/test_replay.py
@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset, skipUntrustedTest
+from qemu_test import skipFlakyTest
from replay_kernel import ReplayKernelBase
@@ -16,6 +17,7 @@ class Mips64elReplay(ReplayKernelBase):
'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb'),
'35eb476f03be589824b0310358f1c447d85e645b88cbcd2ac02b97ef560f9f8d')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2013")
def test_replay_mips64el_malta(self):
self.set_machine('malta')
kernel_path = self.archive_extract(self.ASSET_KERNEL_2_63_2,
diff --git a/tests/functional/mipsel/test_malta.py b/tests/functional/mipsel/test_malta.py
index 427e163..59ab4a6 100755
--- a/tests/functional/mipsel/test_malta.py
+++ b/tests/functional/mipsel/test_malta.py
@@ -10,6 +10,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import QemuSystemTest, LinuxKernelTest, Asset
+from qemu_test import skipFlakyTest
from qemu_test import interrupt_interactive_console_until_pattern
from qemu_test import wait_for_console_pattern
@@ -69,6 +70,7 @@ def test_mips_malta32el_nanomips_64k_dbg(self):
'debian_wheezy_mipsel_standard.qcow2'),
'454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914')
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/3109")
def test_wheezy(self):
kernel_path = self.ASSET_WHEEZY_KERNEL.fetch()
image_path = self.ASSET_WHEEZY_DISK.fetch()
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index 056cfb6..7fbdf6f 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -272,6 +272,7 @@
#
generate_yaml("ubuntu", "ubuntu-2404", "aarch64")
generate_yaml("ubuntu", "ubuntu-2404", "s390x")
+ generate_yaml("debian", "debian-13", "ppc64le")
sys.exit(0)
diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out
index 97f894c..9178474 100644
--- a/tests/qemu-iotests/094.out
+++ b/tests/qemu-iotests/094.out
@@ -23,6 +23,6 @@
{'execute': 'quit'}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
+{"return": {}}
*** done
diff --git a/tests/qemu-iotests/119.out b/tests/qemu-iotests/119.out
index 7b7f0f4..45f82a4 100644
--- a/tests/qemu-iotests/119.out
+++ b/tests/qemu-iotests/119.out
@@ -5,7 +5,7 @@
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
-{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
+{"return": {}}
*** done
diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out
index 146fc72..a023cd4 100644
--- a/tests/qemu-iotests/172.out
+++ b/tests/qemu-iotests/172.out
@@ -30,6 +30,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
@@ -59,6 +60,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -95,6 +97,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -109,6 +112,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -149,6 +153,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -163,6 +168,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -204,6 +210,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
dev: floppy, id ""
unit = 0 (0x0)
@@ -218,6 +225,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
@@ -247,6 +255,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -283,6 +292,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -297,6 +307,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -337,6 +348,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -351,6 +363,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -395,6 +408,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -431,6 +445,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -467,6 +482,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -481,6 +497,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -531,6 +548,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -545,6 +563,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -586,6 +605,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -600,6 +620,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -641,6 +662,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 1 (0x1)
@@ -655,6 +677,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -696,6 +719,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 1 (0x1)
@@ -710,6 +734,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -760,6 +785,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -774,6 +800,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -815,6 +842,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@@ -829,6 +857,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@@ -876,6 +905,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -942,6 +972,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
Testing: -device floppy,drive-type=120
@@ -968,6 +999,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "120"
Testing: -device floppy,drive-type=144
@@ -994,6 +1026,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
Testing: -device floppy,drive-type=288
@@ -1020,6 +1053,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
@@ -1049,6 +1083,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "120"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -1085,6 +1120,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "288"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -1124,6 +1160,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@@ -1160,6 +1197,7 @@
share-rw = false
account-invalid = "auto"
account-failed = "auto"
+ stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
index e4cbcd8..6d0afe9 100755
--- a/tests/qemu-iotests/184
+++ b/tests/qemu-iotests/184
@@ -45,8 +45,9 @@
run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
- | _filter_qemu_io | _filter_generated_node_ids
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
+ | _filter_qemu_io | _filter_generated_node_ids \
+ | _filter_img_info
}
test_throttle=$($QEMU_IMG --help|grep throttle)
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index ef99bb2..52692b6 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -41,12 +41,6 @@
},
"iops_wr": 0,
"ro": false,
- "children": [
- {
- "node-name": "disk0",
- "child": "file"
- }
- ],
"node-name": "throttle0",
"backing_file_depth": 1,
"drv": "throttle",
@@ -75,8 +69,6 @@
},
"iops_wr": 0,
"ro": false,
- "children": [
- ],
"node-name": "disk0",
"backing_file_depth": 0,
"drv": "null-co",
diff --git a/tests/qemu-iotests/267.out b/tests/qemu-iotests/267.out
index f6f5d87..37b7ebd 100644
--- a/tests/qemu-iotests/267.out
+++ b/tests/qemu-iotests/267.out
@@ -8,7 +8,7 @@
(qemu) savevm snap0
Error: no block device can store vmstate for snapshot
(qemu) info snapshots
-no block device can store vmstate for snapshot
+Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: no block device can store vmstate for snapshot
(qemu) quit
@@ -22,7 +22,7 @@
(qemu) savevm snap0
Error: Device 'none0' is writable but does not support snapshots
(qemu) info snapshots
-no block device can store vmstate for snapshot
+Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'none0' is writable but does not support snapshots
(qemu) quit
@@ -58,7 +58,7 @@
(qemu) savevm snap0
Error: Device 'virtio0' is writable but does not support snapshots
(qemu) info snapshots
-no block device can store vmstate for snapshot
+Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'virtio0' is writable but does not support snapshots
(qemu) quit
@@ -83,7 +83,7 @@
(qemu) savevm snap0
Error: Device 'file' is writable but does not support snapshots
(qemu) info snapshots
-no block device can store vmstate for snapshot
+Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'file' is writable but does not support snapshots
(qemu) quit
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 511a55b..26e6b45 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -229,6 +229,7 @@
discard=0
regex_json_spec_start='^ *"format-specific": \{'
regex_json_child_start='^ *"children": \['
+ regex_json_limit_start='^ *"limits": \{'
gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
@@ -261,7 +262,7 @@
discard=1
elif [[ $line =~ "Child node '/" ]]; then
discard=1
- elif [[ $line =~ $regex_json_spec_start ]]; then
+ elif [[ $line =~ $regex_json_spec_start || $line =~ $regex_json_limit_start ]]; then
discard=2
regex_json_end="^${line%%[^ ]*}\\},? *$"
elif [[ $line =~ $regex_json_child_start ]]; then
diff --git a/tests/qemu-iotests/tests/fuse-allow-other.out b/tests/qemu-iotests/tests/fuse-allow-other.out
index 543fa52..3219fc3 100644
--- a/tests/qemu-iotests/tests/fuse-allow-other.out
+++ b/tests/qemu-iotests/tests/fuse-allow-other.out
@@ -28,9 +28,9 @@
cat: fuse-export: Permission denied
stat: cannot statx 'fuse-export': Permission denied
{'execute': 'quit'}
-{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
+{"return": {}}
--- allow-other=on ---
{'execute': 'qmp_capabilities'}
@@ -55,9 +55,9 @@
cat: fuse-export: Permission denied
Permissions seen by nobody: 440
{'execute': 'quit'}
-{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
+{"return": {}}
--- allow-other=auto ---
{'execute': 'qmp_capabilities'}
@@ -82,7 +82,7 @@
cat: fuse-export: Permission denied
Permissions seen by nobody: 440
{'execute': 'quit'}
-{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
+{"return": {}}
*** done
diff --git a/tests/qemu-iotests/tests/inactive-node-nbd b/tests/qemu-iotests/tests/inactive-node-nbd
index a95b37e..664157b 100755
--- a/tests/qemu-iotests/tests/inactive-node-nbd
+++ b/tests/qemu-iotests/tests/inactive-node-nbd
@@ -24,6 +24,7 @@
from iotests import filter_qemu_io, filter_qtest, filter_qmp_testfiles
iotests.script_initialize(supported_fmts=['generic'],
+ unsupported_fmts=['luks'],
supported_protocols=['file'],
supported_platforms=['linux'])
diff --git a/tests/qemu-iotests/tests/resize-below-filter b/tests/qemu-iotests/tests/resize-below-filter
new file mode 100755
index 0000000..f55619c
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-filter
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Test what happens when a node below filter nodes is resized.
+#
+# Copyright (C) Proxmox Server Solutions GmbH
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import iotests
+from iotests import imgfmt, qemu_img_create, QMPTestCase
+
+image_size = 1 * 1024 * 1024
+image = os.path.join(iotests.test_dir, 'test.img')
+
+class TestResizeBelowFilter(QMPTestCase):
+ def setUp(self) -> None:
+ qemu_img_create('-f', imgfmt, image, str(image_size))
+
+ self.vm = iotests.VM()
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': imgfmt,
+ 'node-name': 'node0',
+ 'file': {
+ 'driver': 'file',
+ 'filename': image,
+ }
+ }))
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'compress',
+ 'node-name': 'comp0',
+ 'file': 'node0',
+ }))
+ self.vm.add_object('throttle-group,id=thrgr0')
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'throttle',
+ 'node-name': 'thr0',
+ 'throttle-group': 'thrgr0',
+ 'file': 'comp0',
+ }))
+ self.vm.add_object('throttle-group,id=thrgr1')
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': 'throttle',
+ 'node-name': 'thr1',
+ 'throttle-group': 'thrgr1',
+ 'file': 'node0',
+ }))
+ self.vm.launch()
+
+ def tearDown(self) -> None:
+ self.vm.shutdown()
+ os.remove(image)
+
+ def assert_size(self, size: int) -> None:
+ nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
+ self.assertEqual(len(nodes), 5)
+ for node in nodes:
+ if node['drv'] == 'file':
+ continue
+ self.assertEqual(node['image']['virtual-size'], size)
+
+ def test_resize_below_filter(self) -> None:
+ self.assert_size(image_size)
+ self.vm.qmp('block_resize', node_name='thr0', size=2*image_size)
+ self.assert_size(2*image_size)
+ self.vm.qmp('block_resize', node_name='comp0', size=3*image_size)
+ self.assert_size(3*image_size)
+ self.vm.qmp('block_resize', node_name='node0', size=4*image_size)
+ self.assert_size(4*image_size)
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/resize-below-filter.out b/tests/qemu-iotests/tests/resize-below-filter.out
new file mode 100644
index 0000000..ae1213e
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-filter.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/tests/resize-below-raw b/tests/qemu-iotests/tests/resize-below-raw
new file mode 100755
index 0000000..3c9241c
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-raw
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# group: rw quick
+#
+# Test what happens when a 'file' node below a 'raw' node is resized.
+#
+# Copyright (C) Proxmox Server Solutions GmbH
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import iotests
+from iotests import imgfmt, qemu_img_create, QMPTestCase
+
+image_size = 1 * 1024 * 1024
+image = os.path.join(iotests.test_dir, 'test.img')
+
+class TestResizeBelowRaw(QMPTestCase):
+ def setUp(self) -> None:
+ qemu_img_create('-f', imgfmt, image, str(image_size))
+
+ self.vm = iotests.VM()
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': imgfmt,
+ 'node-name': 'node0',
+ 'file': {
+ 'driver': 'file',
+ 'filename': image,
+ 'node-name': 'file0',
+ }
+ }))
+ self.vm.launch()
+
+ def tearDown(self) -> None:
+ self.vm.shutdown()
+ os.remove(image)
+
+ def assert_size(self, size: int) -> None:
+ nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
+ self.assertEqual(len(nodes), 2)
+ for node in nodes:
+ if node['drv'] == 'file':
+ continue
+ self.assertEqual(node['image']['virtual-size'], size)
+
+ def test_resize_below_raw(self) -> None:
+ self.assert_size(image_size)
+ self.vm.qmp('block_resize', node_name='file0', size=2*image_size)
+ self.assert_size(2*image_size)
+ self.vm.qmp('block_resize', node_name='node0', size=3*image_size)
+ self.assert_size(3*image_size)
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['raw'], supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/resize-below-raw.out b/tests/qemu-iotests/tests/resize-below-raw.out
new file mode 100644
index 0000000..ae1213e
--- /dev/null
+++ b/tests/qemu-iotests/tests/resize-below-raw.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/tcg/plugins/discons.c b/tests/tcg/plugins/discons.c
new file mode 100644
index 0000000..2e0e664
--- /dev/null
+++ b/tests/tcg/plugins/discons.c
@@ -0,0 +1,221 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2025, Julian Ganz <neither@nut.email>
+ *
+ * This plugin exercises the discontinuity plugin API and asserts some
+ * of its behaviour regarding reported program counters.
+ */
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+struct cpu_state {
+ uint64_t last_pc;
+ uint64_t from_pc;
+ uint64_t next_pc;
+ uint64_t has_from;
+ bool has_next;
+ enum qemu_plugin_discon_type next_type;
+};
+
+struct insn_data {
+ uint64_t addr;
+ uint64_t next_pc;
+ bool next_valid;
+};
+
+static struct qemu_plugin_scoreboard *states;
+
+static qemu_plugin_u64 last_pc;
+static qemu_plugin_u64 from_pc;
+static qemu_plugin_u64 has_from;
+
+static bool abort_on_mismatch;
+static bool trace_all_insns;
+
+static bool addr_eq(uint64_t a, uint64_t b)
+{
+ if (a == b) {
+ return true;
+ }
+
+ uint64_t a_hw;
+ uint64_t b_hw;
+ if (!qemu_plugin_translate_vaddr(a, &a_hw) ||
+ !qemu_plugin_translate_vaddr(b, &b_hw))
+ {
+ return false;
+ }
+
+ return a_hw == b_hw;
+}
+
+static void report_mismatch(const char *pc_name, unsigned int vcpu_index,
+ enum qemu_plugin_discon_type type, uint64_t last,
+ uint64_t expected, uint64_t encountered)
+{
+ gchar *report;
+ const char *discon_type_name = "unknown";
+
+ if (addr_eq(expected, encountered)) {
+ return;
+ }
+
+ switch (type) {
+ case QEMU_PLUGIN_DISCON_INTERRUPT:
+ discon_type_name = "interrupt";
+ break;
+ case QEMU_PLUGIN_DISCON_EXCEPTION:
+ discon_type_name = "exception";
+ break;
+ case QEMU_PLUGIN_DISCON_HOSTCALL:
+ discon_type_name = "hostcall";
+ break;
+ default:
+ break;
+ }
+
+ report = g_strdup_printf("Discon %s PC mismatch on VCPU %d\n"
+ "Expected: %"PRIx64"\nEncountered: %"
+ PRIx64"\nExecuted Last: %"PRIx64
+ "\nEvent type: %s\n",
+ pc_name, vcpu_index, expected, encountered, last,
+ discon_type_name);
+ if (abort_on_mismatch) {
+ /*
+ * The qemu log infrastructure may lose messages when aborting. Using
+ * fputs directly ensures the final report is visible to developers.
+ */
+ fputs(report, stderr);
+ g_abort();
+ } else {
+ qemu_plugin_outs(report);
+ }
+ g_free(report);
+}
+
+static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index,
+ enum qemu_plugin_discon_type type, uint64_t from_pc,
+ uint64_t to_pc)
+{
+ struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
+
+ if (type == QEMU_PLUGIN_DISCON_EXCEPTION &&
+ addr_eq(state->last_pc, from_pc))
+ {
+ /*
+ * For some types of exceptions, insn_exec will be called for the
+ * instruction that caused the exception. This is valid behaviour and
+ * does not need to be reported.
+ */
+ } else if (state->has_next) {
+ /*
+ * We may encounter discontinuity chains without any instructions
+ * being executed in between.
+ */
+ report_mismatch("source", vcpu_index, type, state->last_pc,
+ state->next_pc, from_pc);
+ } else if (state->has_from) {
+ report_mismatch("source", vcpu_index, type, state->last_pc,
+ state->from_pc, from_pc);
+ }
+
+ state->has_from = false;
+
+ state->next_pc = to_pc;
+ state->next_type = type;
+ state->has_next = true;
+}
+
+static void insn_exec(unsigned int vcpu_index, void *userdata)
+{
+ struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
+
+ if (state->has_next) {
+ report_mismatch("target", vcpu_index, state->next_type, state->last_pc,
+ state->next_pc, state->last_pc);
+ state->has_next = false;
+ }
+
+ if (trace_all_insns) {
+ g_autoptr(GString) report = g_string_new(NULL);
+ g_string_append_printf(report, "Exec insn at %"PRIx64" on VCPU %d\n",
+ state->last_pc, vcpu_index);
+ qemu_plugin_outs(report->str);
+ }
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ size_t n_insns = qemu_plugin_tb_n_insns(tb);
+ for (size_t i = 0; i < n_insns; i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+ uint64_t pc = qemu_plugin_insn_vaddr(insn);
+ uint64_t next_pc = pc + qemu_plugin_insn_size(insn);
+ uint64_t has_next = (i + 1) < n_insns;
+
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ last_pc, pc);
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ from_pc, next_pc);
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ has_from, has_next);
+ qemu_plugin_register_vcpu_insn_exec_cb(insn, insn_exec,
+ QEMU_PLUGIN_CB_NO_REGS, NULL);
+ }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info,
+ int argc, char **argv)
+{
+ if (!info->system_emulation) {
+ qemu_plugin_outs("Testing of the disontinuity plugin API is only"
+ " possible in system emulation mode.");
+ return 0;
+ }
+
+ /* Set defaults */
+ abort_on_mismatch = true;
+ trace_all_insns = false;
+
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "abort") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &abort_on_mismatch)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "trace-all") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &trace_all_insns)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ states = qemu_plugin_scoreboard_new(sizeof(struct cpu_state));
+ last_pc = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
+ last_pc);
+ from_pc = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
+ from_pc);
+ has_from = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
+ has_from);
+
+ qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL,
+ vcpu_discon);
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+
+ return 0;
+}
diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
index 61a007d..5615841 100644
--- a/tests/tcg/plugins/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -1,6 +1,6 @@
t = []
if get_option('plugins')
- foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
+ foreach i : ['bb', 'discons', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index 3ca5953..eb1ce65 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -24,5 +24,17 @@
run-test-mepc-masking: test-mepc-masking
$(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
+EXTRA_RUNS += run-plugin-doubletrap
+run-plugin-doubletrap: doubletrap
+ $(call run-test, $<, \
+ $(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
+ $(QEMU_OPTS)$<)
+
+EXTRA_RUNS += run-plugin-interruptedmemory
+run-plugin-interruptedmemory: interruptedmemory
+ $(call run-test, $<, \
+ $(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
+ $(QEMU_OPTS)$<)
+
# We don't currently support the multiarch system tests
undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/doubletrap.S b/tests/tcg/riscv64/doubletrap.S
new file mode 100644
index 0000000..b61089c
--- /dev/null
+++ b/tests/tcg/riscv64/doubletrap.S
@@ -0,0 +1,73 @@
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ # Set up vectored interrupts
+ lla t0, trap
+ add t0, t0, 1
+ csrw mtvec, t0
+
+ # Enable sw interrupts
+ csrrsi zero, mie, 0x8
+ csrrsi zero, mstatus, 0x8
+
+ # Engage the double trap: we trigger an machine-level software
+ # interrupt, which will trap to an illegal instruction
+ lui t1, 0x02000
+ li t0, 1
+ sw t0, 0(t1)
+
+ # If we still not went out via the software interrupt route after a
+ # short while, we failed the test.
+ lui t0, 0x1
+0:
+ addi t0, t0, -1
+ bnez t0, 0b
+ j fail
+
+trap:
+ j illegal_insn # Exceptions
+ j fail # Supervisor software interrupt
+ j fail
+ .insn i CUSTOM_0, 0, x0, x0, 0 # Machine software interrupt
+ j fail
+ j fail # Supervisor timer interrupt
+ j fail
+ j fail # Machine timer interrupt
+ j fail
+ j fail # Supervisor external interrupt
+ j fail
+ j fail # Machine external interrupt
+ j fail
+ j fail # Counter overflow interrupt
+ j fail
+ j fail
+
+illegal_insn:
+ # Check whether we really got an illegal instruction
+ csrr t0, mcause
+ li t1, 2
+ bne t0, t1, fail
+ li a0, 0
+ j _exit
+fail:
+ li a0, 1
+_exit:
+ lla a1, semiargs
+ li t0, 0x20026 # ADP_Stopped_ApplicationExit
+ sd t0, 0(a1)
+ sd a0, 8(a1)
+ li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED
+
+ # Semihosting call sequence
+ .balign 16
+ slli zero, zero, 0x1f
+ ebreak
+ srai zero, zero, 0x7
+ j .
+
+ .data
+ .balign 16
+semiargs:
+ .space 16
diff --git a/tests/tcg/riscv64/interruptedmemory.S b/tests/tcg/riscv64/interruptedmemory.S
new file mode 100644
index 0000000..cd9073e
--- /dev/null
+++ b/tests/tcg/riscv64/interruptedmemory.S
@@ -0,0 +1,97 @@
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ # Set up trap vector
+ lla t0, trap
+ csrw mtvec, t0
+
+ # Set up timer
+ lui t1, 0x02004
+ sd zero, 0(t1) # MTIMECMP0
+
+ # Enable timer interrupts
+ li t0, 0x80
+ csrrs zero, mie, t0
+ csrrsi zero, mstatus, 0x8
+
+ # Set up UART
+ lui t1, 0x10000
+ li a0, 0x80 # DLAB=1
+ sb a0, 3(t1)
+ li a0, 1 # Full speed
+ sw a0, 0(t1)
+ li a0, 0x03 # 8N1, DLAB=0
+ sb a0, 3(t1)
+
+ # Run test for around 60s
+ call rtc_get
+ li t0, 30
+ slli t0, t0, 30 # Approx. 10e9 ns
+ add t0, t0, a0
+0:
+ # Tight loop with memory accesses
+ li a1, 1000000
+ la a2, semiargs
+1:
+ ld a0, 0(a2)
+ sd a0, 0(a2)
+ addi a1, a1, -1
+ bnez a1, 1b
+
+ li a0, '.'
+ call send_byte
+ call rtc_get
+ bltu a0, t0, 0b
+
+ li a0, '\n'
+ call send_byte
+
+ # Exit
+ li a0, 0
+ lla a1, semiargs
+ li t0, 0x20026 # ADP_Stopped_ApplicationExit
+ sd t0, 0(a1)
+ sd a0, 8(a1)
+ li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED
+
+ # Semihosting call sequence
+ .balign 16
+ slli zero, zero, 0x1f
+ ebreak
+ srai zero, zero, 0x7
+
+ j .
+
+rtc_get:
+ # Get current time from the goldfish RTC
+ lui t3, 0x0101
+ lw a0, 0(t3)
+ lw t3, 4(t3)
+ slli t3, t3, 32
+ add a0, a0, t3
+ ret
+
+send_byte:
+ # Send a single byte over the serial
+ lui t3, 0x10000
+ lb a1, 5(t3)
+ andi a1, a1, 0x20
+ beqz a1, send_byte
+ sb a0, 0(t3)
+ ret
+
+ .balign 4
+trap:
+ lui t5, 0x0200c
+ ld t6, -0x8(t5) # MTIME
+ addi t6, t6, 100
+ lui t5, 0x02004
+ sd t6, 0(t5) # MTIMECMP
+ mret
+
+ .data
+ .balign 16
+semiargs:
+ .space 16