From 52f45faa4f843617ae09e7965aec963fab3fb564 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:16 +0900 Subject: [PATCH 01/97] qdev-properties: Add DEFINE_PROP_ON_OFF_AUTO_BIT64() DEFINE_PROP_ON_OFF_AUTO_BIT64() corresponds to DEFINE_PROP_ON_OFF_AUTO() as DEFINE_PROP_BIT64() corresponds to DEFINE_PROP_BOOL(). The difference is that DEFINE_PROP_ON_OFF_AUTO_BIT64() exposes OnOffAuto instead of bool. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-1-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/qdev-properties.c | 67 +++++++++++++++++++++++++++++++++++- include/hw/qdev-properties.h | 18 ++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 147b3ffd16..b7e8a89ba5 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -2,6 +2,7 @@ #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qapi/qapi-types-misc.h" +#include "qapi/qapi-visit-common.h" #include "qobject/qlist.h" #include "qemu/ctype.h" #include "qemu/error-report.h" @@ -180,7 +181,8 @@ const PropertyInfo qdev_prop_bit = { static uint64_t qdev_get_prop_mask64(const Property *prop) { - assert(prop->info == &qdev_prop_bit64); + assert(prop->info == &qdev_prop_bit64 || + prop->info == &qdev_prop_on_off_auto_bit64); return 0x1ull << prop->bitnr; } @@ -225,6 +227,69 @@ const PropertyInfo qdev_prop_bit64 = { .set_default_value = set_default_value_bool, }; +static void prop_get_on_off_auto_bit64(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Property *prop = opaque; + OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop); + OnOffAuto value; + uint64_t mask = qdev_get_prop_mask64(prop); + + if (p->auto_bits & mask) { + value = ON_OFF_AUTO_AUTO; + } else if (p->on_bits & mask) { + value = ON_OFF_AUTO_ON; + } else { + value = ON_OFF_AUTO_OFF; + } + + visit_type_OnOffAuto(v, name, &value, errp); +} + +static void prop_set_on_off_auto_bit64(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Property *prop = opaque; + OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop); + OnOffAuto value; + uint64_t mask = qdev_get_prop_mask64(prop); + + if (!visit_type_OnOffAuto(v, name, &value, errp)) { + return; + } + + switch (value) { + case ON_OFF_AUTO_AUTO: + p->on_bits &= ~mask; + p->auto_bits |= mask; + break; + + case ON_OFF_AUTO_ON: + p->on_bits |= mask; + p->auto_bits &= ~mask; + break; + + case ON_OFF_AUTO_OFF: + p->on_bits &= ~mask; + p->auto_bits &= ~mask; + break; + + case ON_OFF_AUTO__MAX: + g_assert_not_reached(); + } +} + +const PropertyInfo qdev_prop_on_off_auto_bit64 = { + .type = "OnOffAuto", + .description = "on/off/auto", + .enum_table = &OnOffAuto_lookup, + .get = prop_get_on_off_auto_bit64, + .set = prop_set_on_off_auto_bit64, + .set_default_value = qdev_propinfo_set_default_value_enum, +}; + /* --- bool --- */ static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque, diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 2c99856caa..0197aa4995 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -43,11 +43,22 @@ struct PropertyInfo { ObjectPropertyRelease *release; }; +/** + * struct OnOffAutoBit64 - OnOffAuto storage with 64 elements. + * @on_bits: Bitmap of elements with "on". + * @auto_bits: Bitmap of elements with "auto". + */ +typedef struct OnOffAutoBit64 { + uint64_t on_bits; + uint64_t auto_bits; +} OnOffAutoBit64; + /*** qdev-properties.c ***/ extern const PropertyInfo qdev_prop_bit; extern const PropertyInfo qdev_prop_bit64; +extern const PropertyInfo qdev_prop_on_off_auto_bit64; extern const PropertyInfo qdev_prop_bool; extern const PropertyInfo qdev_prop_uint8; extern const PropertyInfo qdev_prop_uint16; @@ -100,6 +111,13 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) +#define DEFINE_PROP_ON_OFF_AUTO_BIT64(_name, _state, _field, _bit, _defval) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_on_off_auto_bit64, \ + OnOffAutoBit64, \ + .bitnr = (_bit), \ + .set_default = true, \ + .defval.i = (OnOffAuto)_defval) + #define DEFINE_PROP_BOOL(_name, _state, _field, _defval) \ DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \ .set_default = true, \ From 14f521f491063136bb4aa282c9d29735c78ee433 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:17 +0900 Subject: [PATCH 02/97] net/vhost-vdpa: Report hashing capability Report hashing capability so that virtio-net can deliver the correct capability information to the guest. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-2-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/net/net.h | 3 +++ net/net.c | 9 +++++++++ net/vhost-vdpa.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/include/net/net.h b/include/net/net.h index cdd5b109b0..545f4339ce 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -60,6 +60,7 @@ typedef bool (HasVnetHdrLen)(NetClientState *, int); typedef void (SetOffload)(NetClientState *, int, int, int, int, int, int, int); typedef int (GetVnetHdrLen)(NetClientState *); typedef void (SetVnetHdrLen)(NetClientState *, int); +typedef bool (GetVnetHashSupportedTypes)(NetClientState *, uint32_t *); typedef int (SetVnetLE)(NetClientState *, bool); typedef int (SetVnetBE)(NetClientState *, bool); typedef struct SocketReadState SocketReadState; @@ -89,6 +90,7 @@ typedef struct NetClientInfo { SetVnetHdrLen *set_vnet_hdr_len; SetVnetLE *set_vnet_le; SetVnetBE *set_vnet_be; + GetVnetHashSupportedTypes *get_vnet_hash_supported_types; NetAnnounce *announce; SetSteeringEBPF *set_steering_ebpf; NetCheckPeerType *check_peer_type; @@ -189,6 +191,7 @@ void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo, int uso4, int uso6); int qemu_get_vnet_hdr_len(NetClientState *nc); void qemu_set_vnet_hdr_len(NetClientState *nc, int len); +bool qemu_get_vnet_hash_supported_types(NetClientState *nc, uint32_t *types); int qemu_set_vnet_le(NetClientState *nc, bool is_le); int qemu_set_vnet_be(NetClientState *nc, bool is_be); void qemu_macaddr_default_if_unset(MACAddr *macaddr); diff --git a/net/net.c b/net/net.c index 39d6f28158..d0ae3db0d8 100644 --- a/net/net.c +++ b/net/net.c @@ -573,6 +573,15 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len) nc->info->set_vnet_hdr_len(nc, len); } +bool qemu_get_vnet_hash_supported_types(NetClientState *nc, uint32_t *types) +{ + if (!nc || !nc->info->get_vnet_hash_supported_types) { + return false; + } + + return nc->info->get_vnet_hash_supported_types(nc, types); +} + int qemu_set_vnet_le(NetClientState *nc, bool is_le) { #if HOST_BIG_ENDIAN diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 58d738945d..cb63e09453 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -252,6 +252,32 @@ static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc) return true; } +static bool vhost_vdpa_get_vnet_hash_supported_types(NetClientState *nc, + uint32_t *types) +{ + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + uint64_t features = s->vhost_vdpa.dev->features; + int fd = s->vhost_vdpa.shared->device_fd; + struct { + struct vhost_vdpa_config hdr; + uint32_t supported_hash_types; + } config; + + if (!virtio_has_feature(features, VIRTIO_NET_F_HASH_REPORT) && + !virtio_has_feature(features, VIRTIO_NET_F_RSS)) { + return false; + } + + config.hdr.off = offsetof(struct virtio_net_config, supported_hash_types); + config.hdr.len = sizeof(config.supported_hash_types); + + assert(!ioctl(fd, VHOST_VDPA_GET_CONFIG, &config)); + *types = le32_to_cpu(config.supported_hash_types); + + return true; +} + static bool vhost_vdpa_has_ufo(NetClientState *nc) { assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); @@ -428,6 +454,7 @@ static NetClientInfo net_vhost_vdpa_info = { .stop = vhost_vdpa_net_client_stop, .cleanup = vhost_vdpa_cleanup, .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .get_vnet_hash_supported_types = vhost_vdpa_get_vnet_hash_supported_types, .has_ufo = vhost_vdpa_has_ufo, .set_vnet_le = vhost_vdpa_set_vnet_le, .check_peer_type = vhost_vdpa_check_peer_type, @@ -1284,6 +1311,7 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { .stop = vhost_vdpa_net_cvq_stop, .cleanup = vhost_vdpa_cleanup, .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .get_vnet_hash_supported_types = vhost_vdpa_get_vnet_hash_supported_types, .has_ufo = vhost_vdpa_has_ufo, .check_peer_type = vhost_vdpa_check_peer_type, .set_steering_ebpf = vhost_vdpa_set_steering_ebpf, From 2deec9ab7d25d7cd8f57033bd0421c1f9f28d905 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:18 +0900 Subject: [PATCH 03/97] virtio-net: Move virtio_net_get_features() down Move virtio_net_get_features() to the later part of the file so that it can call other functions. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-3-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 146 ++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index eb93607b8c..34fe5909c5 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -752,79 +752,6 @@ static void virtio_net_set_queue_pairs(VirtIONet *n) static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); -static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, - Error **errp) -{ - VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_queue(n->nic); - - /* Firstly sync all virtio-net possible supported features */ - features |= n->host_features; - - virtio_add_feature(&features, VIRTIO_NET_F_MAC); - - if (!peer_has_vnet_hdr(n)) { - virtio_clear_feature(&features, VIRTIO_NET_F_CSUM); - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4); - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6); - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN); - - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN); - - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6); - - virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); - } - - if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) { - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO); - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO); - } - - if (!peer_has_uso(n)) { - virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4); - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6); - } - - if (!get_vhost_net(nc->peer)) { - return features; - } - - if (!ebpf_rss_is_loaded(&n->ebpf_rss)) { - virtio_clear_feature(&features, VIRTIO_NET_F_RSS); - } - features = vhost_net_get_features(get_vhost_net(nc->peer), features); - vdev->backend_features = features; - - if (n->mtu_bypass_backend && - (n->host_features & 1ULL << VIRTIO_NET_F_MTU)) { - features |= (1ULL << VIRTIO_NET_F_MTU); - } - - /* - * Since GUEST_ANNOUNCE is emulated the feature bit could be set without - * enabled. This happens in the vDPA case. - * - * Make sure the feature set is not incoherent, as the driver could refuse - * to start. - * - * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes, - * helping guest to notify the new location with vDPA devices that does not - * support it. - */ - if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) { - virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE); - } - - return features; -} - static uint64_t virtio_net_bad_features(VirtIODevice *vdev) { uint64_t features = 0; @@ -3076,6 +3003,79 @@ static int virtio_net_pre_load_queues(VirtIODevice *vdev) return 0; } +static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_queue(n->nic); + + /* Firstly sync all virtio-net possible supported features */ + features |= n->host_features; + + virtio_add_feature(&features, VIRTIO_NET_F_MAC); + + if (!peer_has_vnet_hdr(n)) { + virtio_clear_feature(&features, VIRTIO_NET_F_CSUM); + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4); + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6); + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN); + + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN); + + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6); + + virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); + } + + if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) { + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO); + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO); + } + + if (!peer_has_uso(n)) { + virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4); + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6); + } + + if (!get_vhost_net(nc->peer)) { + return features; + } + + if (!ebpf_rss_is_loaded(&n->ebpf_rss)) { + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); + } + features = vhost_net_get_features(get_vhost_net(nc->peer), features); + vdev->backend_features = features; + + if (n->mtu_bypass_backend && + (n->host_features & 1ULL << VIRTIO_NET_F_MTU)) { + features |= (1ULL << VIRTIO_NET_F_MTU); + } + + /* + * Since GUEST_ANNOUNCE is emulated the feature bit could be set without + * enabled. This happens in the vDPA case. + * + * Make sure the feature set is not incoherent, as the driver could refuse + * to start. + * + * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes, + * helping guest to notify the new location with vDPA devices that does not + * support it. + */ + if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) { + virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE); + } + + return features; +} + static int virtio_net_post_load_device(void *opaque, int version_id) { VirtIONet *n = opaque; From 7b6e7e49905d0682f67ae4d02fc9edc4a2ec7df5 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:19 +0900 Subject: [PATCH 04/97] virtio-net: Retrieve peer hashing capability Retrieve peer hashing capability instead of hardcoding. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-4-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 71 +++++++++++++++++++++++++++------- include/hw/virtio/virtio-net.h | 5 ++- net/vhost-vdpa.c | 4 +- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 34fe5909c5..9888ff22bd 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -158,7 +158,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) virtio_host_has_feature(vdev, VIRTIO_NET_F_RSS) ? VIRTIO_NET_RSS_MAX_TABLE_LEN : 1); virtio_stl_p(vdev, &netcfg.supported_hash_types, - VIRTIO_NET_RSS_SUPPORTED_HASHES); + n->rss_data.supported_hash_types); memcpy(config, &netcfg, n->config_size); /* @@ -1178,7 +1178,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data, { config->redirect = data->redirect; config->populate_hash = data->populate_hash; - config->hash_types = data->hash_types; + config->hash_types = data->runtime_hash_types; config->indirections_len = data->indirections_len; config->default_queue = data->default_queue; } @@ -1213,6 +1213,10 @@ static void virtio_net_detach_ebpf_rss(VirtIONet *n) static void virtio_net_commit_rss_config(VirtIONet *n) { + if (n->rss_data.peer_hash_available) { + return; + } + if (n->rss_data.enabled) { n->rss_data.enabled_software_rss = n->rss_data.populate_hash; if (n->rss_data.populate_hash) { @@ -1227,7 +1231,7 @@ static void virtio_net_commit_rss_config(VirtIONet *n) } trace_virtio_net_rss_enable(n, - n->rss_data.hash_types, + n->rss_data.runtime_hash_types, n->rss_data.indirections_len, sizeof(n->rss_data.key)); } else { @@ -1338,7 +1342,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, err_value = (uint32_t)s; goto error; } - n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types); + n->rss_data.runtime_hash_types = virtio_ldl_p(vdev, &cfg.hash_types); n->rss_data.indirections_len = virtio_lduw_p(vdev, &cfg.indirection_table_mask); if (!do_rss) { @@ -1401,12 +1405,12 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, err_value = temp.b; goto error; } - if (!temp.b && n->rss_data.hash_types) { + if (!temp.b && n->rss_data.runtime_hash_types) { err_msg = "No key provided"; err_value = 0; goto error; } - if (!temp.b && !n->rss_data.hash_types) { + if (!temp.b && !n->rss_data.runtime_hash_types) { virtio_net_disable_rss(n); return queue_pairs; } @@ -1808,7 +1812,7 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len); net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto); net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto, - n->rss_data.hash_types); + n->rss_data.runtime_hash_types); if (net_hash_type > NetPktRssIpV6UdpEx) { if (n->rss_data.populate_hash) { hdr->hash_value = VIRTIO_NET_HASH_REPORT_NONE; @@ -3008,6 +3012,14 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, { VirtIONet *n = VIRTIO_NET(vdev); NetClientState *nc = qemu_get_queue(n->nic); + uint32_t supported_hash_types = n->rss_data.supported_hash_types; + uint32_t peer_hash_types = n->rss_data.peer_hash_types; + bool use_own_hash = + (supported_hash_types & VIRTIO_NET_RSS_SUPPORTED_HASHES) == + supported_hash_types; + bool use_peer_hash = + n->rss_data.peer_hash_available && + (supported_hash_types & peer_hash_types) == supported_hash_types; /* Firstly sync all virtio-net possible supported features */ features |= n->host_features; @@ -3044,12 +3056,28 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, } if (!get_vhost_net(nc->peer)) { + if (!use_own_hash) { + virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); + } else if (virtio_has_feature(features, VIRTIO_NET_F_RSS)) { + virtio_net_load_ebpf(n, errp); + } + return features; } - if (!ebpf_rss_is_loaded(&n->ebpf_rss)) { - virtio_clear_feature(&features, VIRTIO_NET_F_RSS); + if (!use_peer_hash) { + virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); + + if (!use_own_hash || !virtio_net_attach_ebpf_to_backend(n->nic, -1)) { + if (!virtio_net_load_ebpf(n, errp)) { + return features; + } + + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); + } } + features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -3314,6 +3342,17 @@ static const VMStateDescription vmstate_virtio_net_has_vnet = { }, }; +static int virtio_net_rss_post_load(void *opaque, int version_id) +{ + VirtIONet *n = VIRTIO_NET(opaque); + + if (version_id == 1) { + n->rss_data.supported_hash_types = VIRTIO_NET_RSS_SUPPORTED_HASHES; + } + + return 0; +} + static bool virtio_net_rss_needed(void *opaque) { return VIRTIO_NET(opaque)->rss_data.enabled; @@ -3321,14 +3360,16 @@ static bool virtio_net_rss_needed(void *opaque) static const VMStateDescription vmstate_virtio_net_rss = { .name = "virtio-net-device/rss", - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, + .post_load = virtio_net_rss_post_load, .needed = virtio_net_rss_needed, .fields = (const VMStateField[]) { VMSTATE_BOOL(rss_data.enabled, VirtIONet), VMSTATE_BOOL(rss_data.redirect, VirtIONet), VMSTATE_BOOL(rss_data.populate_hash, VirtIONet), - VMSTATE_UINT32(rss_data.hash_types, VirtIONet), + VMSTATE_UINT32(rss_data.runtime_hash_types, VirtIONet), + VMSTATE_UINT32_V(rss_data.supported_hash_types, VirtIONet, 2), VMSTATE_UINT16(rss_data.indirections_len, VirtIONet), VMSTATE_UINT16(rss_data.default_queue, VirtIONet), VMSTATE_UINT8_ARRAY(rss_data.key, VirtIONet, @@ -3915,8 +3956,12 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) net_rx_pkt_init(&n->rx_pkt); - if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) { - virtio_net_load_ebpf(n, errp); + if (qemu_get_vnet_hash_supported_types(qemu_get_queue(n->nic)->peer, + &n->rss_data.peer_hash_types)) { + n->rss_data.peer_hash_available = true; + n->rss_data.supported_hash_types = n->rss_data.peer_hash_types; + } else { + n->rss_data.supported_hash_types = VIRTIO_NET_RSS_SUPPORTED_HASHES; } } diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index b9ea9e824e..c4957c44c0 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -144,7 +144,10 @@ typedef struct VirtioNetRssData { bool enabled_software_rss; bool redirect; bool populate_hash; - uint32_t hash_types; + bool peer_hash_available; + uint32_t runtime_hash_types; + uint32_t supported_hash_types; + uint32_t peer_hash_types; uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; uint16_t indirections_len; uint16_t *indirections_table; diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index cb63e09453..3452835ca9 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -865,13 +865,13 @@ static int vhost_vdpa_net_load_rss(VhostVDPAState *s, const VirtIONet *n, * configuration only at live migration. */ if (!n->rss_data.enabled || - n->rss_data.hash_types == VIRTIO_NET_HASH_REPORT_NONE) { + n->rss_data.runtime_hash_types == VIRTIO_NET_HASH_REPORT_NONE) { return 0; } table = g_malloc_n(n->rss_data.indirections_len, sizeof(n->rss_data.indirections_table[0])); - cfg.hash_types = cpu_to_le32(n->rss_data.hash_types); + cfg.hash_types = cpu_to_le32(n->rss_data.runtime_hash_types); if (do_rss) { /* From abef963a12e2bc266884b27677ff3cf94c09e512 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:20 +0900 Subject: [PATCH 05/97] net/vhost-vdpa: Remove dummy SetSteeringEBPF It is no longer used. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-5-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 3452835ca9..0f782ed444 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -239,12 +239,6 @@ static void vhost_vdpa_cleanup(NetClientState *nc) g_free(s->vhost_vdpa.shared); } -/** Dummy SetSteeringEBPF to support RSS for vhost-vdpa backend */ -static bool vhost_vdpa_set_steering_ebpf(NetClientState *nc, int prog_fd) -{ - return true; -} - static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc) { assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); @@ -458,7 +452,6 @@ static NetClientInfo net_vhost_vdpa_info = { .has_ufo = vhost_vdpa_has_ufo, .set_vnet_le = vhost_vdpa_set_vnet_le, .check_peer_type = vhost_vdpa_check_peer_type, - .set_steering_ebpf = vhost_vdpa_set_steering_ebpf, }; static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index, @@ -1314,7 +1307,6 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { .get_vnet_hash_supported_types = vhost_vdpa_get_vnet_hash_supported_types, .has_ufo = vhost_vdpa_has_ufo, .check_peer_type = vhost_vdpa_check_peer_type, - .set_steering_ebpf = vhost_vdpa_set_steering_ebpf, }; /* From 729b5734197d1afad364bb025a827438bb85e050 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 13:33:21 +0900 Subject: [PATCH 06/97] virtio-net: Add hash type options By default, virtio-net limits the hash types that will be advertised to the guest so that all hash types are covered by the offloading capability the client provides. This change allows to override this behavior and to advertise hash types that require user-space hash calculation by specifying "on" for the corresponding properties. Signed-off-by: Akihiko Odaki Message-Id: <20250530-vdpa-v1-6-5af4109b1c19@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 45 ++++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-net.h | 1 + 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9888ff22bd..6af230bca9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3959,9 +3959,14 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) if (qemu_get_vnet_hash_supported_types(qemu_get_queue(n->nic)->peer, &n->rss_data.peer_hash_types)) { n->rss_data.peer_hash_available = true; - n->rss_data.supported_hash_types = n->rss_data.peer_hash_types; + n->rss_data.supported_hash_types = + n->rss_data.specified_hash_types.on_bits | + (n->rss_data.specified_hash_types.auto_bits & + n->rss_data.peer_hash_types); } else { - n->rss_data.supported_hash_types = VIRTIO_NET_RSS_SUPPORTED_HASHES; + n->rss_data.supported_hash_types = + n->rss_data.specified_hash_types.on_bits | + n->rss_data.specified_hash_types.auto_bits; } } @@ -4178,6 +4183,42 @@ static const Property virtio_net_properties[] = { VIRTIO_NET_F_GUEST_USO6, true), DEFINE_PROP_BIT64("host_uso", VirtIONet, host_features, VIRTIO_NET_F_HOST_USO, true), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv4", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_IPv4 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp4", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_TCPv4 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp4", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_UDPv4 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv6", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_IPv6 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp6", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_TCPv6 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp6", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_UDPv6 - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv6ex", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_IPv6_EX - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp6ex", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_TCPv6_EX - 1, + ON_OFF_AUTO_AUTO), + DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp6ex", VirtIONet, + rss_data.specified_hash_types, + VIRTIO_NET_HASH_REPORT_UDPv6_EX - 1, + ON_OFF_AUTO_AUTO), }; static void virtio_net_class_init(ObjectClass *klass, const void *data) diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index c4957c44c0..73fdefc0dc 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -148,6 +148,7 @@ typedef struct VirtioNetRssData { uint32_t runtime_hash_types; uint32_t supported_hash_types; uint32_t peer_hash_types; + OnOffAutoBit64 specified_hash_types; uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; uint16_t indirections_len; uint16_t *indirections_table; From 9f749129e2629b19f424df106c92c5a5647e396c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 3 Jun 2025 13:13:36 +0200 Subject: [PATCH 07/97] vhost: Fix used memslot tracking when destroying a vhost device When we unplug a vhost device, we end up calling vhost_dev_cleanup() where we do a memory_listener_unregister(). This memory_listener_unregister() call will end up disconnecting the listener from the address space through listener_del_address_space(). In that process, we effectively communicate the removal of all memory regions from that listener, resulting in region_del() + commit() callbacks getting triggered. So in case of vhost, we end up calling vhost_commit() with no remaining memory slots (0). In vhost_commit() we end up overwriting the global variables used_memslots / used_shared_memslots, used for detecting the number of free memslots. With used_memslots / used_shared_memslots set to 0 by vhost_commit() during device removal, we'll later assume that the other vhost devices still have plenty of memslots left when calling vhost_get_free_memslots(). Let's fix it by simply removing the global variables and depending only on the actual per-device count. Easy to reproduce by adding two vhost-user devices to a VM and then hot-unplugging one of them. While at it, detect unexpected underflows in vhost_get_free_memslots() and issue a warning. Reported-by: yuanminghao Link: https://lore.kernel.org/qemu-devel/20241121060755.164310-1-yuanmh12@chinatelecom.cn/ Fixes: 2ce68e4cf5be ("vhost: add vhost_has_free_slot() interface") Cc: Igor Mammedov Cc: Michael S. Tsirkin Cc: Stefano Garzarella Signed-off-by: David Hildenbrand Message-Id: <20250603111336.1858888-1-david@redhat.com> Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index fc43853704..c87861b31f 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -47,12 +47,6 @@ static struct vhost_log *vhost_log[VHOST_BACKEND_TYPE_MAX]; static struct vhost_log *vhost_log_shm[VHOST_BACKEND_TYPE_MAX]; static QLIST_HEAD(, vhost_dev) vhost_log_devs[VHOST_BACKEND_TYPE_MAX]; -/* Memslots used by backends that support private memslots (without an fd). */ -static unsigned int used_memslots; - -/* Memslots used by backends that only support shared memslots (with an fd). */ -static unsigned int used_shared_memslots; - static QLIST_HEAD(, vhost_dev) vhost_devices = QLIST_HEAD_INITIALIZER(vhost_devices); @@ -74,15 +68,15 @@ unsigned int vhost_get_free_memslots(void) QLIST_FOREACH(hdev, &vhost_devices, entry) { unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); - unsigned int cur_free; + unsigned int cur_free = r - hdev->mem->nregions; - if (hdev->vhost_ops->vhost_backend_no_private_memslots && - hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { - cur_free = r - used_shared_memslots; + if (unlikely(r < hdev->mem->nregions)) { + warn_report_once("used (%u) vhost backend memory slots exceed" + " the device limit (%u).", hdev->mem->nregions, r); + free = 0; } else { - cur_free = r - used_memslots; + free = MIN(free, cur_free); } - free = MIN(free, cur_free); } return free; } @@ -666,13 +660,6 @@ static void vhost_commit(MemoryListener *listener) dev->mem = g_realloc(dev->mem, regions_size); dev->mem->nregions = dev->n_mem_sections; - if (dev->vhost_ops->vhost_backend_no_private_memslots && - dev->vhost_ops->vhost_backend_no_private_memslots(dev)) { - used_shared_memslots = dev->mem->nregions; - } else { - used_memslots = dev->mem->nregions; - } - for (i = 0; i < dev->n_mem_sections; i++) { struct vhost_memory_region *cur_vmr = dev->mem->regions + i; struct MemoryRegionSection *mrs = dev->mem_sections + i; @@ -1619,15 +1606,11 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); /* - * The listener we registered properly updated the corresponding counter. - * So we can trust that these values are accurate. + * The listener we registered properly setup the number of required + * memslots in vhost_commit(). */ - if (hdev->vhost_ops->vhost_backend_no_private_memslots && - hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { - used = used_shared_memslots; - } else { - used = used_memslots; - } + used = hdev->mem->nregions; + /* * We assume that all reserved memslots actually require a real memslot * in our vhost backend. This might not be true, for example, if the From 260f826cf8f2fe54f3cf4de541d761cf616e15ea Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 10 Jun 2025 00:25:45 +0300 Subject: [PATCH 08/97] softmmu/runstate: add a way to detect force shutdowns This can be useful for devices that might take too long to shut down gracefully, but may have a way to shutdown quickly otherwise if needed or explicitly requested by a force shutdown. For now we only consider SIGTERM or the QMP quit() command a force shutdown, since those bypass the guest entirely and are equivalent to pulling the power plug. Signed-off-by: Daniil Tatianin Message-Id: <20250609212547.2859224-2-d-tatianin@yandex-team.ru> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/system/runstate.h | 1 + system/runstate.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/system/runstate.h b/include/system/runstate.h index fdd5c4a517..b406a3960e 100644 --- a/include/system/runstate.h +++ b/include/system/runstate.h @@ -107,6 +107,7 @@ void qemu_system_vmstop_request(RunState reason); void qemu_system_vmstop_request_prepare(void); bool qemu_vmstop_requested(RunState *r); ShutdownCause qemu_shutdown_requested_get(void); +bool qemu_force_shutdown_requested(void); ShutdownCause qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); void qemu_system_reset(ShutdownCause reason); diff --git a/system/runstate.c b/system/runstate.c index 38900c935a..e18eb8cb0c 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -437,6 +437,7 @@ static ShutdownCause reset_requested; static ShutdownCause shutdown_requested; static int shutdown_exit_code = EXIT_SUCCESS; static int shutdown_signal; +static bool force_shutdown; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; @@ -457,6 +458,11 @@ ShutdownCause qemu_shutdown_requested_get(void) return shutdown_requested; } +bool qemu_force_shutdown_requested(void) +{ + return force_shutdown; +} + ShutdownCause qemu_reset_requested_get(void) { return reset_requested; @@ -805,6 +811,7 @@ void qemu_system_killed(int signal, pid_t pid) * we are in a signal handler. */ shutdown_requested = SHUTDOWN_CAUSE_HOST_SIGNAL; + force_shutdown = true; qemu_notify_event(); } @@ -820,6 +827,9 @@ void qemu_system_shutdown_request(ShutdownCause reason) trace_qemu_system_shutdown_request(reason); replay_shutdown_request(reason); shutdown_requested = reason; + if (reason == SHUTDOWN_CAUSE_HOST_QMP_QUIT) { + force_shutdown = true; + } qemu_notify_event(); } From 2f527fff460a2c67fd37298dbd7fe42fffdb738b Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 10 Jun 2025 00:25:46 +0300 Subject: [PATCH 09/97] vhost: add a helper for force stopping a device This adds an ability to skip GET_VRING_BASE during device stop entirely, and thus the expensive drain operation that this call entails as well, which may be useful during a non-graceful shutdown in case the guest operating system hangs or refuses to react to a previously requested ACPI shutdown for whatever reason. Signed-off-by: Daniil Tatianin Message-Id: <20250609212547.2859224-3-d-tatianin@yandex-team.ru> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 52 +++++++++++++++++++++++++++++---------- include/hw/virtio/vhost.h | 15 +++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index c87861b31f..c30ea1156e 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1354,25 +1354,30 @@ fail_alloc_desc: return r; } -int vhost_virtqueue_stop(struct vhost_dev *dev, - struct VirtIODevice *vdev, - struct vhost_virtqueue *vq, - unsigned idx) +static int do_vhost_virtqueue_stop(struct vhost_dev *dev, + struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, + unsigned idx, bool force) { int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx); struct vhost_vring_state state = { .index = vhost_vq_index, }; - int r; + int r = 0; if (virtio_queue_get_desc_addr(vdev, idx) == 0) { /* Don't stop the virtqueue which might have not been started */ return 0; } - r = dev->vhost_ops->vhost_get_vring_base(dev, &state); - if (r < 0) { - VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r); + if (!force) { + r = dev->vhost_ops->vhost_get_vring_base(dev, &state); + if (r < 0) { + VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r); + } + } + + if (r < 0 || force) { /* Connection to the backend is broken, so let's sync internal * last avail idx to the device used idx. */ @@ -1401,6 +1406,14 @@ int vhost_virtqueue_stop(struct vhost_dev *dev, return r; } +int vhost_virtqueue_stop(struct vhost_dev *dev, + struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, + unsigned idx) +{ + return do_vhost_virtqueue_stop(dev, vdev, vq, idx, false); +} + static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, int n, uint32_t timeout) { @@ -2119,7 +2132,8 @@ fail_features: } /* Host notifiers must be enabled at this point. */ -int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) +static int do_vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, + bool vrings, bool force) { int i; int rc = 0; @@ -2141,10 +2155,11 @@ int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) vhost_dev_set_vring_enable(hdev, false); } for (i = 0; i < hdev->nvqs; ++i) { - rc |= vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - hdev->vq_index + i); + rc |= do_vhost_virtqueue_stop(hdev, + vdev, + hdev->vqs + i, + hdev->vq_index + i, + force); } if (hdev->vhost_ops->vhost_reset_status) { hdev->vhost_ops->vhost_reset_status(hdev); @@ -2164,6 +2179,17 @@ int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) return rc; } +int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) +{ + return do_vhost_dev_stop(hdev, vdev, vrings, false); +} + +int vhost_dev_force_stop(struct vhost_dev *hdev, VirtIODevice *vdev, + bool vrings) +{ + return do_vhost_dev_stop(hdev, vdev, vrings, true); +} + int vhost_net_set_backend(struct vhost_dev *hdev, struct vhost_vring_file *file) { diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 38800a7156..eb3dd7616b 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -237,6 +237,21 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); */ int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); +/** + * vhost_dev_force_stop() - force stop the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * @vrings: true to have vrings disabled in this call + * + * Force stop the vhost device. After the device is stopped the notifiers + * can be disabled (@vhost_dev_disable_notifiers) and the device can + * be torn down (@vhost_dev_cleanup). Unlike @vhost_dev_stop, this doesn't + * attempt to flush in-flight backend requests by skipping GET_VRING_BASE + * entirely. + */ +int vhost_dev_force_stop(struct vhost_dev *hdev, VirtIODevice *vdev, + bool vrings); + /** * DOC: vhost device configuration handling * From 07fde5901b5254d3b9706df22dbb16cfacf966d5 Mon Sep 17 00:00:00 2001 From: Daniil Tatianin Date: Tue, 10 Jun 2025 00:25:47 +0300 Subject: [PATCH 10/97] vhost-user-blk: add an option to skip GET_VRING_BASE for force shutdown If we have a server running disk requests that is for whatever reason hanging or not able to process any more IO requests but still has some in-flight requests previously issued by the guest OS, QEMU will still try to drain the vring before shutting down even if it was explicitly asked to do a "force shutdown" via SIGTERM or QMP quit. This is not useful since the guest is no longer running at this point since it was killed by QEMU earlier in the process. At this point, we don't care about whatever in-flight IO it might have pending, we just want QEMU to shut down. Add an option called "skip-get-vring-base-on-force-shutdown" to allow SIGTERM/QMP quit() to actually act like a "force shutdown" at least for vhost-user-blk devices since those require the drain operation to shut down gracefully unlike, for example, network devices. Signed-off-by: Daniil Tatianin Message-Id: <20250609212547.2859224-4-d-tatianin@yandex-team.ru> Acked-by: Raphael Norwitz Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/vhost-user-blk.c | 9 ++++++++- include/hw/virtio/vhost-user-blk.h | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 0eebbcd80d..c0cc5f6942 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -210,6 +210,7 @@ static int vhost_user_blk_stop(VirtIODevice *vdev) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); int ret; + bool force_stop = false; if (!s->started_vu) { return 0; @@ -220,7 +221,11 @@ static int vhost_user_blk_stop(VirtIODevice *vdev) return 0; } - ret = vhost_dev_stop(&s->dev, vdev, true); + force_stop = s->skip_get_vring_base_on_force_shutdown && + qemu_force_shutdown_requested(); + + ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) : + vhost_dev_stop(&s->dev, vdev, true); if (k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); @@ -584,6 +589,8 @@ static const Property vhost_user_blk_properties[] = { VIRTIO_BLK_F_DISCARD, true), DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features, VIRTIO_BLK_F_WRITE_ZEROES, true), + DEFINE_PROP_BOOL("skip-get-vring-base-on-force-shutdown", VHostUserBlk, + skip_get_vring_base_on_force_shutdown, false), }; static void vhost_user_blk_class_init(ObjectClass *klass, const void *data) diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h index ea085ee1ed..a10f785672 100644 --- a/include/hw/virtio/vhost-user-blk.h +++ b/include/hw/virtio/vhost-user-blk.h @@ -50,6 +50,8 @@ struct VHostUserBlk { bool connected; /* vhost_user_blk_start/vhost_user_blk_stop */ bool started_vu; + + bool skip_get_vring_base_on_force_shutdown; }; #endif From f3bc2c3f33cc875a3b7e5349aa4141ea6789a01d Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Jun 2025 17:03:17 +0800 Subject: [PATCH 11/97] tests/acpi: Add empty ACPI data files for LoongArch Add empty acpi table for LoongArch virt machine, it is only empty file and there is no data in these files. Signed-off-by: Bibo Mao Message-Id: <20250612090321.3416594-2-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/loongarch64/virt/APIC | 0 tests/data/acpi/loongarch64/virt/DSDT | 0 tests/data/acpi/loongarch64/virt/FACP | 0 tests/data/acpi/loongarch64/virt/MCFG | 0 tests/data/acpi/loongarch64/virt/PPTT | 0 tests/data/acpi/loongarch64/virt/SLIT | 0 tests/data/acpi/loongarch64/virt/SPCR | 0 tests/data/acpi/loongarch64/virt/SRAT | 0 tests/qtest/bios-tables-test-allowed-diff.h | 8 ++++++++ 9 files changed, 8 insertions(+) create mode 100644 tests/data/acpi/loongarch64/virt/APIC create mode 100644 tests/data/acpi/loongarch64/virt/DSDT create mode 100644 tests/data/acpi/loongarch64/virt/FACP create mode 100644 tests/data/acpi/loongarch64/virt/MCFG create mode 100644 tests/data/acpi/loongarch64/virt/PPTT create mode 100644 tests/data/acpi/loongarch64/virt/SLIT create mode 100644 tests/data/acpi/loongarch64/virt/SPCR create mode 100644 tests/data/acpi/loongarch64/virt/SRAT diff --git a/tests/data/acpi/loongarch64/virt/APIC b/tests/data/acpi/loongarch64/virt/APIC new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/DSDT b/tests/data/acpi/loongarch64/virt/DSDT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/FACP b/tests/data/acpi/loongarch64/virt/FACP new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/MCFG b/tests/data/acpi/loongarch64/virt/MCFG new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/PPTT b/tests/data/acpi/loongarch64/virt/PPTT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/SLIT b/tests/data/acpi/loongarch64/virt/SLIT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/SPCR b/tests/data/acpi/loongarch64/virt/SPCR new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/loongarch64/virt/SRAT b/tests/data/acpi/loongarch64/virt/SRAT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..bad1380eec 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,9 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/loongarch64/virt/APIC", +"tests/data/acpi/loongarch64/virt/DSDT", +"tests/data/acpi/loongarch64/virt/FACP", +"tests/data/acpi/loongarch64/virt/MCFG", +"tests/data/acpi/loongarch64/virt/PPTT", +"tests/data/acpi/loongarch64/virt/SLIT", +"tests/data/acpi/loongarch64/virt/SPCR", +"tests/data/acpi/loongarch64/virt/SRAT", From 73e2cba058c74c9a0d5b640711a1ff2428551952 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Jun 2025 17:03:18 +0800 Subject: [PATCH 12/97] tests/qtest/bios-tables-test: Add basic testing for LoongArch Add basic ACPI table test case for LoongArch, including cpu topology, numa memory, memory hotplug and oem-id test cases. Signed-off-by: Bibo Mao Message-Id: <20250612090321.3416594-3-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 79 ++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 80 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 4dbc07ec5e..f41e638014 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -2439,6 +2439,74 @@ static void test_acpi_aarch64_virt_oem_fields(void) g_free(args); } +#define LOONGARCH64_INIT_TEST_DATA(data) \ + test_data data = { \ + .machine = "virt", \ + .arch = "loongarch64", \ + .tcg_only = true, \ + .uefi_fl1 = "pc-bios/edk2-loongarch64-code.fd", \ + .uefi_fl2 = "pc-bios/edk2-loongarch64-vars.fd", \ + .cd = "tests/data/uefi-boot-images/" \ + "bios-tables-test.loongarch64.iso.qcow2", \ + .ram_start = 0, \ + .scan_len = 128ULL * MiB, \ + } + +static void test_acpi_loongarch64_virt(void) +{ + LOONGARCH64_INIT_TEST_DATA(data); + + test_acpi_one("-cpu la464 ", &data); + free_test_data(&data); +} + +static void test_acpi_loongarch64_virt_topology(void) +{ + LOONGARCH64_INIT_TEST_DATA(data); + + data.variant = ".topology"; + test_acpi_one("-cpu la464 -smp sockets=1,cores=2,threads=2", &data); + free_test_data(&data); +} + +static void test_acpi_loongarch64_virt_numamem(void) +{ + LOONGARCH64_INIT_TEST_DATA(data); + + data.variant = ".numamem"; + test_acpi_one(" -cpu la464 -m 128" + " -object memory-backend-ram,id=ram0,size=64M" + " -object memory-backend-ram,id=ram1,size=64M" + " -numa node,memdev=ram0 -numa node,memdev=ram1" + " -numa dist,src=0,dst=1,val=21", + &data); + free_test_data(&data); +} + +static void test_acpi_loongarch64_virt_memhp(void) +{ + LOONGARCH64_INIT_TEST_DATA(data); + + data.variant = ".memhp"; + test_acpi_one(" -cpu la464 -m 128,slots=2,maxmem=256M" + " -object memory-backend-ram,id=ram0,size=128M", + &data); + free_test_data(&data); +} + +static void test_acpi_loongarch64_virt_oem_fields(void) +{ + LOONGARCH64_INIT_TEST_DATA(data); + char *args; + + args = test_acpi_create_args(&data, "-cpu la464 "OEM_TEST_ARGS); + data.qts = qtest_init(args); + test_acpi_load_tables(&data); + test_oem_fields(&data); + qtest_quit(data.qts); + free_test_data(&data); + g_free(args); +} int main(int argc, char *argv[]) { @@ -2614,6 +2682,17 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/virt/numamem", test_acpi_riscv64_virt_tcg_numamem); } + } else if (strcmp(arch, "loongarch64") == 0) { + if (has_tcg) { + qtest_add_func("acpi/virt", test_acpi_loongarch64_virt); + qtest_add_func("acpi/virt/topology", + test_acpi_loongarch64_virt_topology); + qtest_add_func("acpi/virt/numamem", + test_acpi_loongarch64_virt_numamem); + qtest_add_func("acpi/virt/memhp", test_acpi_loongarch64_virt_memhp); + qtest_add_func("acpi/virt/oem-fields", + test_acpi_loongarch64_virt_oem_fields); + } } ret = g_test_run(); boot_sector_cleanup(disk); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 5ad969f616..669d07c06b 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -148,6 +148,7 @@ qtests_hppa = \ qtests_loongarch64 = qtests_filter + \ (config_all_devices.has_key('CONFIG_LOONGARCH_VIRT') ? ['numa-test'] : []) + \ + (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ ['boot-serial-test', 'cpu-plug-test'] From c43ca0de62749286ee099baaf628b7f7b6e9844f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Jun 2025 17:03:19 +0800 Subject: [PATCH 13/97] rebuild-expected-aml.sh: Add support for LoongArch Update the list of supported architectures to include LoongArch. Signed-off-by: Bibo Mao Message-Id: <20250612090321.3416594-4-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/rebuild-expected-aml.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh index c1092fb8ba..cbf9ffe0dd 100755 --- a/tests/data/acpi/rebuild-expected-aml.sh +++ b/tests/data/acpi/rebuild-expected-aml.sh @@ -12,7 +12,7 @@ # This work is licensed under the terms of the GNU GPLv2. # See the COPYING.LIB file in the top-level directory. -qemu_arches="x86_64 aarch64 riscv64" +qemu_arches="x86_64 aarch64 riscv64 loongarch64" if [ ! -e "tests/qtest/bios-tables-test" ]; then echo "Test: bios-tables-test is required! Run make check before this script." @@ -37,7 +37,7 @@ if [ -z "$qemu_bins" ]; then echo "Only the following architectures are currently supported: $qemu_arches" echo "None of these configured!" echo "To fix, run configure \ - --target-list=x86_64-softmmu,aarch64-softmmu,riscv64-softmmu" + --target-list=x86_64-softmmu,aarch64-softmmu,riscv64-softmmu,loongarch64-softmmu" exit 1; fi From 67fbf12288df10eb1ea76d4f48d6a8efa46ae65c Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Jun 2025 17:03:20 +0800 Subject: [PATCH 14/97] tests/acpi: Fill acpi table data for LoongArch The acpi table data is filled for LoongArch virt machine with the following command: tests/data/acpi/rebuild-expected-aml.sh Signed-off-by: Bibo Mao Message-Id: <20250612090321.3416594-5-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/loongarch64/virt/APIC | Bin 0 -> 108 bytes tests/data/acpi/loongarch64/virt/APIC.topology | Bin 0 -> 153 bytes tests/data/acpi/loongarch64/virt/DSDT | Bin 0 -> 4641 bytes tests/data/acpi/loongarch64/virt/DSDT.memhp | Bin 0 -> 5862 bytes tests/data/acpi/loongarch64/virt/DSDT.numamem | Bin 0 -> 4647 bytes tests/data/acpi/loongarch64/virt/DSDT.topology | Bin 0 -> 4943 bytes tests/data/acpi/loongarch64/virt/FACP | Bin 0 -> 268 bytes tests/data/acpi/loongarch64/virt/MCFG | Bin 0 -> 60 bytes tests/data/acpi/loongarch64/virt/PPTT | Bin 0 -> 76 bytes tests/data/acpi/loongarch64/virt/PPTT.topology | Bin 0 -> 176 bytes tests/data/acpi/loongarch64/virt/SLIT.numamem | Bin 0 -> 48 bytes tests/data/acpi/loongarch64/virt/SPCR | Bin 0 -> 80 bytes tests/data/acpi/loongarch64/virt/SRAT | Bin 0 -> 104 bytes tests/data/acpi/loongarch64/virt/SRAT.memhp | Bin 0 -> 144 bytes tests/data/acpi/loongarch64/virt/SRAT.numamem | Bin 0 -> 144 bytes tests/data/acpi/loongarch64/virt/SRAT.topology | Bin 0 -> 152 bytes 16 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/data/acpi/loongarch64/virt/APIC.topology create mode 100644 tests/data/acpi/loongarch64/virt/DSDT.memhp create mode 100644 tests/data/acpi/loongarch64/virt/DSDT.numamem create mode 100644 tests/data/acpi/loongarch64/virt/DSDT.topology create mode 100644 tests/data/acpi/loongarch64/virt/PPTT.topology create mode 100644 tests/data/acpi/loongarch64/virt/SLIT.numamem create mode 100644 tests/data/acpi/loongarch64/virt/SRAT.memhp create mode 100644 tests/data/acpi/loongarch64/virt/SRAT.numamem create mode 100644 tests/data/acpi/loongarch64/virt/SRAT.topology diff --git a/tests/data/acpi/loongarch64/virt/APIC b/tests/data/acpi/loongarch64/virt/APIC index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3477789f422cad54f16734b3ec9ad1ff5135165d 100644 GIT binary patch literal 108 zcmZ<^@N~{$U|?YU>g4b25v<@85#X$#prF9Wz`y`vgJ=ejJOcxRAU}-90Ah&nGBPv# o{|}O7U=S5%WMKH958^m5FfbfoU| z7UXASVqjnZVUUm@KO-{(0|N+yxFWoa%nbkkgN$Ne5EW)*VECX9;y5rcFdSfDU=R}o PsS*GQF$gd)I4}SJQ#cF( literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/DSDT b/tests/data/acpi/loongarch64/virt/DSDT index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f32e732b11a557ae01c7f383625d3b6f459ac9f7 100644 GIT binary patch literal 4641 zcmZ<>b_r1wVqjq0Sl4Rmx zc=(l-H#sLiIa@caC^fIJG&L`|k^$9?hFIJPavdHwLfv+s8IK#CDRiR?G#q_E;b?@# zja*Fl0}|@E`z&}I=|W9M8e?-LGk!-x9e1AQ+$h(|Um5Q|X|F}P7)AXgzpEZiti z#3Gv&gvBg~7^+!F;g2wj8P#3ESj>Wm!Oe1-9N_GU6k3i37N9H(&Bl%f#ta5aI!eb20fC7#P7g%svJN#tcHdEIj}JGcthm7{YlV zT}BK-d=NRXK4SzIq|*SZmI>SSWz0_lX=!VK04a{)60NGD7w zGeoB$R3|e;C(ITWuuhl@Sim}AN?9N}VUA~k=!DtA3f2j80V`N1OerfwC(QAz5S=hv z*uXkrE?@)egehf%=!7|*4Wbif3p-dR%mwUVoiL^B5S=i`vqN;kY~cXwgt>qNtP`e` z1ELe=cn*k8m@S-OoiG=0f_1`_azb>%9M1{S3A2R@tP|z}F0f9RQZ9&2nB%!1I$^eO zgLT4Ozzx<3Q_2m|33EI*L?_G^9x3!ggXn}go)4lEW(z-9C(H%>V4X0f{1BZm$MZvU!fX)$ z>x8*L0IUFs1SkoiNACLv$K3i15TaJ2^5e;bCB4P=GX}{aCr8I(QkFKtc=*^$ZLQ4Git# z42(R?;I=aZ1H=FQ3=9ko3=#|n7#L7n++cB#ivRyX8etkhv;&B!WZ(!64G3W1a1IIb zVGwcSjQ0kR(J{03=xe;)BGO zWH01{h=VLKT#_xK8}AbA%d$Wb;+hNQC!YqJR{2g8f8{HA*x7dh=j1GgC4$V1j39y` zy2+O%$Tb+Lk>hM&1ZtlI1q&K;8DNBu0w^5*|NpNJqLDBMh+WAL-Q>*?qX+8txVyT< zLt4R(&H=471uf*x66O!v@5S zZt~%TxG5mWH5lwB9>)t@Y~U^!uX8}Cf=7NyK~8D9LQ!gQerZv1YB57JqjP|dH#8gs zx%k>R85rdm_yj_? z8Gr~kMh0eQXI~eN=tiM{px_W@XOO2D6r5cgLlmN$oQxo@a}EfFxQ-VZVg?}lJzYSK zWfc*04snZQTEI0qgQ3mYz`!6=#Dmp2IK+`NS{dqXkncdQ{{O!q16e58)u(_VVS(6W zWI>Qi3%K|bqSaAEeY}?>i1@OATuz+9jL6zuy$mqS6LA*@#RUfzXL30ExrPfd{pWCY z_3{y7`d`41T)>#J$W?f93S$97N&#a+0YhQ|L+ToSew@e{w3<{{qI8r3L5;7AT;E4k!u>k~=`|OJpcbEMQDP zQvixykOEgPpHzm@)B?tY(&Pe$q(wGUlM)M>!5Whol0i|H%vg{dZHVb=lz{W}3ocCp z>9?GklnT=C>g5B|&&5nYbC7RXX%c3*J90St2Z!)r33trof#MivUzdVRv;ZpLVnP-H zDak?>aB&R5a6xpF2MZ{rf^!@+O&gd)yGbHE@xdXE97{k+n1LhS*D*wpn~Q^igMk4w zx*@_B?;jk(4e|g(MrM|X0@N;0p#n-x3{XBO%YgXNO_HFp0Adqph{f5!8ER2b_sbV#=yY1!^z*-BUr&HBEVTeK|z6$fq?@*!&W?;6@y1UD^x`JRq$MAn<_kfjo%5&jg`C zY%qqZ=wxHyWOQO+V5nr^h<6Eg5i({H6y_2Tx$*zjuDl-Ku8DhQ@Aq2FC?vxuB+10X z@bD`uZ*oq4a<*<-QEFacX=+|_B?GD(4Y9ZpKl(Il{!W_>6(FwDK6|58H0#>k2m{L}VPMG6aAv$5U zuz_{LT)+m_2~)}j(Ft=r8$>6}7Iv^smXNTy7*}?(V33CAlSSL&= z2Sg{#@f;AHFk3jmI$L3F}w5eDmoxj-1K6Q)!cq7&wLVTewcEh1o@Fc*k`b;6X2Ky<@`*gt3fOW!@%0P6& z94`aW3A05OtP|z}S+Gu+Qdx*jnB!$3I$^fRfpx-MAP3e7Qz{4133I$0L?_G^d9Y5H z3*^B%VM^s8I$@5Nhv+n75aEe;c5-A`!o$G8pa5w``>}FGb?`DUfrJKPaq8W`He z85nt(!EI*-28RFp85kHG7$g`DFfgFDxWVEe761Q(G{Q81Xa^8c$-ogD8W6z1;T#g= z!yw|u8SfwL%+i(3;Or7^xWI#bat5dY9_@SE_`AG}!?f@c#{;(4)4H;`Se#wLjk>bA zIGkO=jSD~=kU1cRG03QD5Wyu6A{Piunw-g43o;O_+Hir`q{$#%AW4X@07$X`#0QBl z$zI3@5eHdfxFlOdH{K=Kmt}z>#5EVpPd*Jct@52H{>oSKu(R(1&dFH}O9Yu289@X? zbdxVjkZUkfBgfgm2-H3a3KlfxGQbEQ1yDHr|NmbdL?dAi5WA8gy2+UP?aDjIR`uYMK}4eLLBMq5#R!GB&c8JXkZ3u#PRy3=H?ewDrDrB6y%hq zD-@*`=a&{Grxrs4Mv#lIjgx_qg@I2%0_t{;0N)@69*_u^M0As@3*3BXZ05Uo`uZxQ zq?ToZ&GdEg3*usmZq$Oh6XYt8dCa~+PCg30K~5eDzCk`9mXC*mZ$L!6LUf}Bnp#H& z2QFXN;CMz~PrqPB-yq*GMqgL2c*f{P1vHh+zMvrW^>+$=HIK84O?pxhI4DQ^3U! zQ=K580!%H3Z;+V@Jh{R%Iw(nk@W1~M0AhnMg!lh{B|{fTBNv~qr=Jgm zDdg+v=K*1=`MAPFwR~J*qGG;|5m2>KzK#(d1)%5wX#z2PKn4}~2Kjh^G=LaBAVZ2k z!XO4nFNgz{2I*cPG8H5Sk}m@B89~GXL9ifW35Ww00kM2QET07~?2|#l3>>~e#zvrS zM!Prz1EOpLc@^eGu=k9OxVU^h{o=bo>bdxQ9V4JjF&|gI_yUm4An5|IGaMu03qbA! zNkL->qz%qAGZ9ho4T$h%M2~<1P^v^klZLNB3#lqf*sDI)yfq`U-_rl9b5IDLNF;36m2TrzV4nxq@V53&4Iu7I5};Ss*+WS;WOL zBzfrqzKN3)x&BX1<@#U1n6k70UBLo{$;d*WC@e_s0J$%bp)|38F#$~hD0)E(T)li! z8A?+N7!yj93mB3X*-TAJENBL6Okzj|MOiXqL2|SqrmIl`&eJcrGzp~Na%xg4NWZI> z4@^H7GXc#(zG0k*avElI2$-at&46lbn}5V(tP}a z{0$5YO`&p-W-qi!!oa{F!@$762x^Iev_Qw_P_=-Dbc2Eg5n5y+S_A}QKm%H)@j~n@ JT&xTX3;Mb literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/DSDT.numamem b/tests/data/acpi/loongarch64/virt/DSDT.numamem new file mode 100644 index 0000000000000000000000000000000000000000..9b462869cd4911714e7c2a22025c465afa2a7d52 GIT binary patch literal 4647 zcmZ<>b_r1zVqjpjbMklg2v%^42yj+VP*7lGU|;~TL9~D~SA4Kjd~}mHr?bDW0Y|)t zrwea@Ux0zBfguA&e5j`j14q2Gvm+x%ymL^npbeL0mo@_f4@fHm2s~hXAP=JNGeKw& z8;qeUI@uUF8J!py7%CY!;$4DWgp8R4g}DSoZv4NsE3e15YvP{S`@I%33dt}ENiy*; zJp9Vao1BxMoUNNyl$uvqnwpnf$$;ucLo99txekvTp>Dg+jK_`66uQv`8je1oa5Tc= zMlL4&0SR^7eHJ{9bfKmrjj=hB8NVZ;j=Rr_$C0j-IWoG*lf}ot04XUt8@R!fVn9%^ zARiZZCmRDJV*u15P{KqN6Jd)F4hm+38ikZ%;6^cW#3LIOh{Y&~7~Ci?kgJd)7H$+M zVv)@X!eSOg4Am^8@JE=%jOwmnEM`H(;AS~Z4siBF3N1$i3s9DYW@ASKV+M}+U{`kr zj(8_0KX^C>hXe`AbIAlSI5T)Mq%tTl7%(U>xGbiy3Z2GI$#g&nLD<^p!GPMA`5h)$T}*&#Y%ws3%T!d$=s)(KO} z0nrI_JO@N4%oa|tPM8Zg!8&0|IUzb>j^~8vgxSIc)(LX~7g#4uDHlX1%<)_hoiJOt z!8&0s;0Ei2DdmRfggKrYq7!Bd4_GJ61w3G#Fr_>YoiNAqKy<=v;RWl2xqug}6Q-0G zq7&wLUWiVZEqq{|Fc zb;4XA0M-dpDge<5bG!gVC(IT>uuhl@1i?CCN(CW0VU8Ds=!DrK1l9?2fe=_HOsNn= zC(Q9e5S=hvguyytE)WLmgeet<=!7|57@`wqiwIaJ%mpG~oiL>$5S=i`i$HY3Y!L

m@Q&poiG=Ofpx-^ia~V394`jZ3A05UtP|z}aj;I9QgMh* znB&DEI$^d*fOW!LAOY41Qz`+`33I#zL?_G^Nw7|s3nalhVM-+-I$@5Ngy@9XA_dk7 zbAc3CCrqgnL?_JgQV^XmTcp7{VJ?sc>x3zlhUkPjUK*kkW{V71C(H#hV4X0fG7z0G z$IC!;!fcTR>x8*L7OWGdR2HHW=6G3%PM9rnV4W}*$bogjl*&PL!W=IL(FwCf9;_4Q z0(r1bm{NI&PMG86Av%p1M0nzzog5jK@GvkiC_tLgeym(k9lQ)oARz{ZdIkoD28MQV z21XucaNC)If#Lst1_lNP1__1(3=F6(Zm>8=#sB{xjW7)$+5tpVGH?Wk1_Us0IEMuJ zFo?Ku#`_05vvg%MIJ<-!F7RNVoB?WpNBiD3{w^=$FfF{q@qq31w61I}7H5}mqpoZ& z4riBe;{p%|WDba73^J-3L~zN2$OQtECTB9%f(!(!He4V!X);I`ND?9}0Fo>K@j>EC zvKR6}#6gxAF3A?rjduz5Wm%vIam@wulTU+9t9&Plzw(tl?CiUMb8;5L5#>0<}+qf(4Da3^2k+0Td4Z|NmD9(MXsB#I9tBZt~`c(F1jR++AJb zA+2CX=KxOw14B?_Db&-2*WDG|?}0ZqnHk-|EwShZ*C1DS1|9|mJ^?P4=tgc3*V#4L z)ki_ZEZ#LNgtGv|Nmw8-xjKOh)JACw2oG}NYFHov65wFq;)u~_hFR?#?CdAtX9MC! zH~DZv+!PSx8Vq(5kK+X{HgFe=*Et|m!6UzTiGJ^g|ior8SC7@b|c z3_ye%BLlOuv#$$BbfZu}P;dydGssg63eGN$Aqvq=9!3z?IR}J7T*nIyF$0kOo-QEA zvWf^ghqy&DE#R7*!O-SxU|^6b;=$@19OB3stqk=x$af%D|Nmc*fh-j4>Qlgwut01w zvLMK%1zh|I(dsCoKHf_bM0{C5E+@`lMr7@-UIrNEiMWe{;(`NtKW(juFwNr?r`V2w!($)G4pW-LgKHpFx_O2B#g1(zm) z^jl6%N(Je6_40w~=VB(HImkDxGzl}@9XXu+gF|?*gga*PKyi$-uS-EDS^yPrF(He9 zlw=_bxHyJjxFEX8j|G%c!8s0^rVY%Y-6Rp7_}~ynjwPTZ%)k-v>lh-)&BejM!N33- z-4Nl6_YV%?26=!XBQuL5J|M!EK|}#+BdBNrr6~p|ACz%G{OBf0P>BGs4>Zu?Y~T#F zF1pFk%?DP>`S=C-8yFaxLggU!1~ij1Ffhn4FfcHJiZYNEXa^Tn3usIvC|D4oMHZq( UKp+OxBQ%W{VrSuEWnf?c0BwsUJpcdz literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/DSDT.topology b/tests/data/acpi/loongarch64/virt/DSDT.topology new file mode 100644 index 0000000000000000000000000000000000000000..65111aa822663a907b83487cb496be38a4bdff05 GIT binary patch literal 4943 zcmZ<>b_wwpW?*1cbMklg2v%^42yj+VP*7lGU|;~TL9~D~SA4Kjd~}mHr?bDW0Y|)t zrwea@Ux0zBfguA&e5j`j14q2Gvm+x%ymL^npbeL0mo@_f4@fHm2s~hXAP=JNGeKw& z8;qeUI@uUF8J!py7%CY!;$4DWgp8R4g}DSoZv4NsE3e15YvP{S`@I%33dt}ENiy*; zJp9Vao1BxMoUNNyl$uvqnwpnf$$;ucLo99txekvTp>Dg+jK_`66uQv`8je1oa5Tc= zMlL4&0SR^7eHJ{9bfKmrjj=hB8NVZ;j=Rr_$C0j-IWoG*lf}ot04XUt8@R!fVn9%^ zARiZZCmRDJV*u15P{KqN6Jd)F4hm+38ikZ%;6^cW#3LIOh{Y&~7~Ci?kgJd)7H$+M zVv)@X!eSOg4Am^8@JE=%jOwmnEM`H(;AS~Z4siBF3N1$i3s9DYW@ASKV+M}+U{`kr zj(8_0KX^C>hXe`AbIAlSI5T)Mq%tTl7%(U>xGbiy3Z2GI$#g&nLD<^p!GPMA`5h)$T}*&#Y%ws3%T!d$=s)(KO} z0nrI_JO@N4%oa|tPM8Zg!8&0|IUzb>j^~8vgxSIc)(LX~7g#4uDHlX1%<)_hoiJOt z!8&0s;0Ei2DdmRfggKrYq7!Bd4_GJ61w3G#Fr_>YoiNAqKy<=v;RWl2xqug}6Q-0G zq7&wLUWiVZEqq{|Fc zb;4XA0M-dpDge<5bG!gVC(IT>uuhl@1i?CCN(CW0VU8Ds=!DrK1l9?2fe=_HOsNn= zC(Q9e5S=hvguyytE)WLmgeet<=!7|57@`wqiwIaJ%mpG~oiL>$5S=i`i$HY3Y!L

m@Q&poiG=Ofpx-^ia~V394`jZ3A05UtP|z}aj;I9QgMh* znB&DEI$^d*fOW!LAOY41Qz`+`33I#zL?_G^Nw7|s3nalhVM-+-I$@5Ngy@9XA_dk7 zbAc3CCrqgnL?_JgQV^XmTcp7{VJ?sc>x3zlhUkPjUK*kkW{V71C(H#hV4X0fG7z0G z$IC!;!fcTR>x8*L7OWGdR2HHW=6G3%PM9rnV4W}*$bogjl*&PL!W=IL(FwCf9;_4Q z0(r1bm{NI&PMG86Av%p1M0nzzog5jK@GvkiC_tLgeym(k9lQ)oARz{ZdIkoD28MQV z21XucaNC)If#Lst1_lNP1__1(3=F6(Zm>8=#sB{xjW7)$+5tpVGH?Wk1_Us0IEMuJ zFo?Ku#`_05vvg%MIJ<-!F7RNVoB?WpNBiD3{w^=$FfF{q@qq31w61I}7H5}mqpoZ& z4riBe;{p%|WDba73^J-3L~zN2$OQtECTB9%f(!(!He4V!X);I`ND?9}0Fo>K@j>EC zvKR6}#6gxAF3A?rjduz5Wm%vIam@wulTU+9t9&Plzw(tl?CiUMb8;5L5#>0<}+qf(4Da3^2k+0Td4Z|NmD9(MXsB#I9tBZt~`c(F1jR++AJb zA+2CX=KxOw14B?_Db&-2*WDG|?}0ZqnHk-|EwShZ*C1DS1|9|mJ^?P4=tgc3*V#4L z)ki_ZEZ#LNgtGv|Nmw8-xjKOh)JACw2oG}NYFHov65wFq;)u~_hFR?#?CdAt<`3dV zH~DZv+!PSx8Vq(5kK+X{HgFe=*Et|m!6UzTiGJ^g|ior8SC7@b|c z3_ye%BLlOuv#$$BbfZu}P;dydGssg63eGN$Aqvq=4z3W_IR}J7T*nIyF$0kOo-QEA zvWl2Ehqy&DE#R7*!O-SxU|^65Vlsl5hM5bvCueXmf!Ib6HZzEAoGIeL>Kq*6$Qi8+ z4H-}XfIRm9e?bPaP_U~{0Ykz9vB}7SAkP$V@h3#9qlo%=FG&#bWdV7PID;9HwYz#5 zV3;T3Ar6Wz4lK^(aQ1Tz7h?L);q2<=BgFK-fFZenF=dgP@Z=Q60)~_V#)JZf!~%xY zMebY^CMPgXP3B@LU`QxPMz#{{Ib;E6UzY{KQ;|hn97B?qF5sIuIg#uCQW;893m6khlM5J<7THWqN-Ssw zYfNHD21RQ!V?lDXA*QQQLeA4KxHJi*-*ReFDoDSpmk&%o7c&9PLB3(7Ntgle$l>fC z9KwSo;4#w&iesF8T?#VM0;qtC30VZBBnw%<#W4iK1<_3&ETGg3&Xv$~Z(t7XN{R5q z2ZuOvECHoq299`N#}GkoE)E6`1_sawhzMW2e{cvl$O8-+nOV_IF09T52G9;EBnQDv zVnjBH5y>P*MzBfT@z9)Vz=&ijBiK|Akg3qVDXOVlOd`Ap2ZFk)a2GN$fz9QCo6E%{ z!Vh;Y7Zbu{XipW*WM&kTnUP$~%#3a_GqTCd8JSrk3eZpo6~Um4#Q^1l3K$SSx=9jL zazer!G$7?{;0z7&=q5uqA6RYR;}_&_U|?tpm4no;(87>`fkB3Wfq@ZJBbPnKQWME+Ra`Jcf2v%^42yj+VP*7lGU|;~TK{Nw30gC_w0|x_x90Q*K$XF*3 SL2t~#z#s#)ALJHUC>sDQ_Xhz0 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/MCFG b/tests/data/acpi/loongarch64/virt/MCFG index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5f93b05abe1669fe4239edbba8aaf4fe666f5b95 100644 GIT binary patch literal 60 ucmeZuc5}C3U|?XJP=GS)K{Nm*r3V23 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/PPTT b/tests/data/acpi/loongarch64/virt/PPTT index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7a1258ecf123555b24462c98ccbb76b4ac1d0c2b 100644 GIT binary patch literal 76 zcmWFt2nq3FU|?Wc;pFe^5v<@85#X$#prF9Wz`y`vgJ=d31_m(AfCNMs7`PZ17*vpi E0HXp20RR91 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/PPTT.topology b/tests/data/acpi/loongarch64/virt/PPTT.topology new file mode 100644 index 0000000000000000000000000000000000000000..d91e55b2399d9949dbb8e4c8cf634af1a0e56df4 GIT binary patch literal 176 zcmWFt2npH1z`($y@8s|75v<@85#X$#prF9Wz`y`vgJ=d31_m(AfCNM!Y!wIvAw?J% k_!t-%EFe4xi6jO$14%Ek7)Wmk$Sn|^3?O@9V$4u60J3}u0RR91 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/SLIT.numamem b/tests/data/acpi/loongarch64/virt/SLIT.numamem new file mode 100644 index 0000000000000000000000000000000000000000..67f00813af7b2356fe74eed943ab8dcf2291578b GIT binary patch literal 48 ucmWIc@eDCwU|?W;;pFe^5v<@85#X$#prF9Wz`y`vgJ>oO2;dSGHuiR2LS*8 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/SRAT.memhp b/tests/data/acpi/loongarch64/virt/SRAT.memhp new file mode 100644 index 0000000000000000000000000000000000000000..525321890138de509ceaf9723f0a4565048e823f GIT binary patch literal 144 zcmWFzatxWkz`(%h<>c?|5v<@85#X$#prF9Wz`y`vgJ=+DfB^vp24p^?2227@bHG?Q Q)WPIoGy^kC0|NsC0BRNo0RR91 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/SRAT.numamem b/tests/data/acpi/loongarch64/virt/SRAT.numamem new file mode 100644 index 0000000000000000000000000000000000000000..2972a9abdcface5b943078d61b4946da80176ea2 GIT binary patch literal 144 zcmWFzatxWkz`(#5?&R<65v<@85#X$#prF9Wz`y`vgJ=+DfB^vp24p^?2227@v%pxW N>fk(>Jd8#$4*+jN2LS*8 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/loongarch64/virt/SRAT.topology b/tests/data/acpi/loongarch64/virt/SRAT.topology new file mode 100644 index 0000000000000000000000000000000000000000..4a44831f475b5fda1db9bed12c2e63a79d6d6e71 GIT binary patch literal 152 zcmWFzatxWlz`(%h>g4b25v<@85#X$#prF9Wz`y`vgJ=+DfB^vp1~fh+8lMS`&y37x O)PNZTr#WCOWOV?bSqA|C literal 0 HcmV?d00001 From 85240876b2f6f9edd72a6f324cac0ee9ee28ab0a Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Jun 2025 17:03:21 +0800 Subject: [PATCH 15/97] tests/acpi: Remove stale allowed tables Remove stale allowed tables for LoongArch virt machine. Signed-off-by: Bibo Mao Message-Id: <20250612090321.3416594-6-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index bad1380eec..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,9 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/loongarch64/virt/APIC", -"tests/data/acpi/loongarch64/virt/DSDT", -"tests/data/acpi/loongarch64/virt/FACP", -"tests/data/acpi/loongarch64/virt/MCFG", -"tests/data/acpi/loongarch64/virt/PPTT", -"tests/data/acpi/loongarch64/virt/SLIT", -"tests/data/acpi/loongarch64/virt/SPCR", -"tests/data/acpi/loongarch64/virt/SRAT", From d7fb5693d9ffbeb9b49c981e1f9774392f1d41e5 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Fri, 13 Jun 2025 16:51:10 +0800 Subject: [PATCH 16/97] hw/acpi: Fix GPtrArray memory leak in crs_range_merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This leak was detected by the valgrind. The crs_range_merge() function unconditionally allocated a GPtrArray 'even when range->len was zero, causing an early return without freeing the allocated array. This resulted in a memory leak when an empty range was processed. Instead of moving the allocation after the check (as previously attempted), use g_autoptr for automatic cleanup. This ensures the array is freed even on early returns, and also removes the need for the explicit free at the end of the function. Signed-off-by: Li Zhijian Message-Id: <20250613085110.111204-1-lizhijian@fujitsu.com> Reviewed-by: Daniel P. BerrangĂ© Reviewed-by: Ani Sinha Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index f8f93a9f66..cb817a0f31 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -160,7 +160,7 @@ void crs_replace_with_free_ranges(GPtrArray *ranges, */ static void crs_range_merge(GPtrArray *range) { - GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free); + g_autoptr(GPtrArray) tmp = g_ptr_array_new_with_free_func(crs_range_free); CrsRangeEntry *entry; uint64_t range_base, range_limit; int i; @@ -191,7 +191,6 @@ static void crs_range_merge(GPtrArray *range) entry = g_ptr_array_index(tmp, i); crs_range_insert(range, entry->base, entry->limit); } - g_ptr_array_free(tmp, true); } static void From 091c7d7924f33781c2fb8e7297dc54971e0c3785 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:20 +0000 Subject: [PATCH 17/97] amd_iommu: Fix Miscellaneous Information Register 0 encoding The definitions encoding the maximum Virtual, Physical, and Guest Virtual Address sizes supported by the IOMMU are using incorrect offsets i.e. the VASize and GVASize offsets are switched. The value in the GVAsize field is also modified, since it was incorrectly encoded. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Co-developed-by: Ethan MILON Signed-off-by: Ethan MILON Signed-off-by: Alejandro Jimenez Message-Id: <20250617150427.20585-2-alejandro.j.jimenez@oracle.com> Reviewed-by: Vasant Hegde Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 5672bdef89..3b1d2e9da5 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -196,9 +196,9 @@ #define AMDVI_PAGE_SHIFT_4K 12 #define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1)) -#define AMDVI_MAX_VA_ADDR (48UL << 5) -#define AMDVI_MAX_PH_ADDR (40UL << 8) -#define AMDVI_MAX_GVA_ADDR (48UL << 15) +#define AMDVI_MAX_GVA_ADDR (2UL << 5) +#define AMDVI_MAX_PH_ADDR (40UL << 8) +#define AMDVI_MAX_VA_ADDR (48UL << 15) /* Completion Wait data size */ #define AMDVI_COMPLETION_DATA_SIZE 8 From c63b8d1425ba8b3b08ee4f7346457fd8a7f12a24 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:21 +0000 Subject: [PATCH 18/97] amd_iommu: Fix Device ID decoding for INVALIDATE_IOTLB_PAGES command The DeviceID bits are extracted using an incorrect offset in the call to amdvi_iotlb_remove_page(). This field is read (correctly) earlier, so use the value already retrieved for devid. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-3-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 963aa2450c..c27efa504d 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -508,7 +508,7 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd) static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) { - uint16_t devid = extract64(cmd[0], 0, 16); + uint16_t devid = cpu_to_le16(extract64(cmd[0], 0, 16)); if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) || extract64(cmd[1], 6, 6)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), @@ -521,7 +521,7 @@ static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) &devid); } else { amdvi_iotlb_remove_page(s, cpu_to_le64(extract64(cmd[1], 12, 52)) << 12, - cpu_to_le16(extract64(cmd[1], 0, 16))); + devid); } trace_amdvi_iotlb_inval(); } From ff3dcb3bf652912466dcc1cd10d3267f185c212e Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:22 +0000 Subject: [PATCH 19/97] amd_iommu: Update bitmasks representing DTE reserved fields The DTE validation method verifies that all bits in reserved DTE fields are unset. Update them according to the latest definition available in AMD I/O Virtualization Technology (IOMMU) Specification - Section 2.2.2.1 Device Table Entry Format. Remove the magic numbers and use a macro helper to generate bitmasks covering the specified ranges for better legibility. Note that some reserved fields specify that events are generated when they contain non-zero bits, or checks are skipped under certain configurations. This change only updates the reserved masks, checks for special conditions are not yet implemented. Cc: qemu-stable@nongnu.org Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-4-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 7 ++++--- hw/i386/amd_iommu.h | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index c27efa504d..6e78047919 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -848,9 +848,10 @@ static inline uint64_t amdvi_get_perms(uint64_t entry) static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid, uint64_t *dte) { - if ((dte[0] & AMDVI_DTE_LOWER_QUAD_RESERVED) - || (dte[1] & AMDVI_DTE_MIDDLE_QUAD_RESERVED) - || (dte[2] & AMDVI_DTE_UPPER_QUAD_RESERVED) || dte[3]) { + if ((dte[0] & AMDVI_DTE_QUAD0_RESERVED) || + (dte[1] & AMDVI_DTE_QUAD1_RESERVED) || + (dte[2] & AMDVI_DTE_QUAD2_RESERVED) || + (dte[3] & AMDVI_DTE_QUAD3_RESERVED)) { amdvi_log_illegaldevtab_error(s, devid, s->devtab + devid * AMDVI_DEVTAB_ENTRY_SIZE, 0); diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 3b1d2e9da5..aacb29b617 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -25,6 +25,8 @@ #include "hw/i386/x86-iommu.h" #include "qom/object.h" +#define GENMASK64(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l)) + /* Capability registers */ #define AMDVI_CAPAB_BAR_LOW 0x04 #define AMDVI_CAPAB_BAR_HIGH 0x08 @@ -162,9 +164,10 @@ #define AMDVI_FEATURE_PC (1ULL << 9) /* Perf counters */ /* reserved DTE bits */ -#define AMDVI_DTE_LOWER_QUAD_RESERVED 0x80300000000000fc -#define AMDVI_DTE_MIDDLE_QUAD_RESERVED 0x0000000000000100 -#define AMDVI_DTE_UPPER_QUAD_RESERVED 0x08f0000000000000 +#define AMDVI_DTE_QUAD0_RESERVED (GENMASK64(6, 2) | GENMASK64(63, 63)) +#define AMDVI_DTE_QUAD1_RESERVED 0 +#define AMDVI_DTE_QUAD2_RESERVED GENMASK64(53, 52) +#define AMDVI_DTE_QUAD3_RESERVED (GENMASK64(14, 0) | GENMASK64(53, 48)) /* AMDVI paging mode */ #define AMDVI_GATS_MODE (2ULL << 12) From 108e10ff69099c3ebe147f505246be7c2ad2a499 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:23 +0000 Subject: [PATCH 20/97] amd_iommu: Fix masks for various IOMMU MMIO Registers Address various issues with definitions of the MMIO registers e.g. for the Device Table Address Register, the size mask currently encompasses reserved bits [11:9], so change it to only extract the bits [8:0] encoding size. Convert masks to use GENMASK64 for consistency, and make unrelated definitions independent. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-5-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index aacb29b617..988a485f80 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -68,34 +68,34 @@ #define AMDVI_MMIO_SIZE 0x4000 -#define AMDVI_MMIO_DEVTAB_SIZE_MASK ((1ULL << 12) - 1) -#define AMDVI_MMIO_DEVTAB_BASE_MASK (((1ULL << 52) - 1) & ~ \ - AMDVI_MMIO_DEVTAB_SIZE_MASK) +#define AMDVI_MMIO_DEVTAB_SIZE_MASK GENMASK64(8, 0) +#define AMDVI_MMIO_DEVTAB_BASE_MASK GENMASK64(51, 12) + #define AMDVI_MMIO_DEVTAB_ENTRY_SIZE 32 #define AMDVI_MMIO_DEVTAB_SIZE_UNIT 4096 /* some of this are similar but just for readability */ #define AMDVI_MMIO_CMDBUF_SIZE_BYTE (AMDVI_MMIO_COMMAND_BASE + 7) #define AMDVI_MMIO_CMDBUF_SIZE_MASK 0x0f -#define AMDVI_MMIO_CMDBUF_BASE_MASK AMDVI_MMIO_DEVTAB_BASE_MASK -#define AMDVI_MMIO_CMDBUF_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) -#define AMDVI_MMIO_CMDBUF_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_CMDBUF_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_CMDBUF_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_CMDBUF_TAIL_MASK GENMASK64(18, 4) #define AMDVI_MMIO_EVTLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) -#define AMDVI_MMIO_EVTLOG_SIZE_MASK AMDVI_MMIO_CMDBUF_SIZE_MASK -#define AMDVI_MMIO_EVTLOG_BASE_MASK AMDVI_MMIO_CMDBUF_BASE_MASK -#define AMDVI_MMIO_EVTLOG_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) -#define AMDVI_MMIO_EVTLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_EVTLOG_SIZE_MASK 0x0f +#define AMDVI_MMIO_EVTLOG_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_EVTLOG_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_EVTLOG_TAIL_MASK GENMASK64(18, 4) -#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) -#define AMDVI_MMIO_PPRLOG_HEAD_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK -#define AMDVI_MMIO_PPRLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK -#define AMDVI_MMIO_PPRLOG_BASE_MASK AMDVI_MMIO_EVTLOG_BASE_MASK -#define AMDVI_MMIO_PPRLOG_SIZE_MASK AMDVI_MMIO_EVTLOG_SIZE_MASK +#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_PPR_BASE + 7) +#define AMDVI_MMIO_PPRLOG_SIZE_MASK 0x0f +#define AMDVI_MMIO_PPRLOG_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_PPRLOG_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_PPRLOG_TAIL_MASK GENMASK64(18, 4) #define AMDVI_MMIO_EXCL_ENABLED_MASK (1ULL << 0) #define AMDVI_MMIO_EXCL_ALLOW_MASK (1ULL << 1) -#define AMDVI_MMIO_EXCL_LIMIT_MASK AMDVI_MMIO_DEVTAB_BASE_MASK +#define AMDVI_MMIO_EXCL_LIMIT_MASK GENMASK64(51, 12) #define AMDVI_MMIO_EXCL_LIMIT_LOW 0xfff /* mmio control register flags */ @@ -132,14 +132,14 @@ #define AMDVI_DEV_TRANSLATION_VALID (1ULL << 1) #define AMDVI_DEV_MODE_MASK 0x7 #define AMDVI_DEV_MODE_RSHIFT 9 -#define AMDVI_DEV_PT_ROOT_MASK 0xffffffffff000 +#define AMDVI_DEV_PT_ROOT_MASK GENMASK64(51, 12) #define AMDVI_DEV_PT_ROOT_RSHIFT 12 #define AMDVI_DEV_PERM_SHIFT 61 #define AMDVI_DEV_PERM_READ (1ULL << 61) #define AMDVI_DEV_PERM_WRITE (1ULL << 62) /* Device table entry bits 64:127 */ -#define AMDVI_DEV_DOMID_ID_MASK ((1ULL << 16) - 1) +#define AMDVI_DEV_DOMID_ID_MASK GENMASK64(15, 0) /* Event codes and flags, as stored in the info field */ #define AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY (0x1U << 12) @@ -197,7 +197,7 @@ #define AMDVI_PAGE_SIZE (1ULL << AMDVI_PAGE_SHIFT) #define AMDVI_PAGE_SHIFT_4K 12 -#define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1)) +#define AMDVI_PAGE_MASK_4K GENMASK64(63, 12) #define AMDVI_MAX_GVA_ADDR (2UL << 5) #define AMDVI_MAX_PH_ADDR (40UL << 8) From 123cf4bdd378f746dfa2f5415ba084148dded3e3 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:24 +0000 Subject: [PATCH 21/97] amd_iommu: Fix mask to retrieve Interrupt Table Root Pointer from DTE Fix an off-by-one error in the definition of AMDVI_IR_PHYS_ADDR_MASK. The current definition masks off the most significant bit of the Interrupt Table Root ptr i.e. it only generates a mask with bits [50:6] set. See the AMD I/O Virtualization Technology (IOMMU) Specification for the Interrupt Table Root Pointer[51:6] field in the Device Table Entry format. Cc: qemu-stable@nongnu.org Fixes: b44159fe0078 ("x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-6-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 988a485f80..96fc5b621e 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -231,7 +231,7 @@ #define AMDVI_IR_INTCTL_PASS 1 #define AMDVI_IR_INTCTL_REMAP 2 -#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6) +#define AMDVI_IR_PHYS_ADDR_MASK GENMASK64(51, 6) /* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */ #define AMDVI_IRTE_OFFSET 0x7ff From 67d3077ee403472d45794399e97c9f329242fce9 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:25 +0000 Subject: [PATCH 22/97] amd_iommu: Fix the calculation for Device Table size Correctly calculate the Device Table size using the format encoded in the Device Table Base Address Register (MMIO Offset 0000h). Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-7-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 6e78047919..92f94dc788 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -665,8 +665,8 @@ static inline void amdvi_handle_devtab_write(AMDVIState *s) uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE); s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK); - /* set device table length */ - s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 * + /* set device table length (i.e. number of entries table can hold) */ + s->devtab_len = (((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1) * (AMDVI_MMIO_DEVTAB_SIZE_UNIT / AMDVI_MMIO_DEVTAB_ENTRY_SIZE)); } From 5959b641c98b5ae9677e2c1d89902dac31b344d9 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:26 +0000 Subject: [PATCH 23/97] amd_iommu: Remove duplicated definitions No functional change. Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-8-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 96fc5b621e..8b42913ed8 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -206,10 +206,6 @@ /* Completion Wait data size */ #define AMDVI_COMPLETION_DATA_SIZE 8 -#define AMDVI_COMMAND_SIZE 16 -/* Completion Wait data size */ -#define AMDVI_COMPLETION_DATA_SIZE 8 - #define AMDVI_COMMAND_SIZE 16 #define AMDVI_INT_ADDR_FIRST 0xfee00000 From 5788929e05e18ed5f76dc8ade4210f022c9ba5a1 Mon Sep 17 00:00:00 2001 From: Ethan Milon Date: Tue, 17 Jun 2025 15:04:27 +0000 Subject: [PATCH 24/97] amd_iommu: Fix truncation of oldval in amdvi_writeq The variable `oldval` was incorrectly declared as a 32-bit `uint32_t`. This could lead to truncation and incorrect behavior where the upper read-only 32 bits are significant. Fix the type of `oldval` to match the return type of `ldq_le_p()`. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Ethan Milon Message-Id: <20250617150427.20585-9-alejandro.j.jimenez@oracle.com> Reviewed-by: Vasant Hegde Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 92f94dc788..5a24c17548 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -140,7 +140,7 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val) { uint64_t romask = ldq_le_p(&s->romask[addr]); uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); - uint32_t oldval = ldq_le_p(&s->mmior[addr]); + uint64_t oldval = ldq_le_p(&s->mmior[addr]); stq_le_p(&s->mmior[addr], ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask)); } From 54401d5abd13c7f2ff5d1cb65e73a067743230e3 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Wed, 28 May 2025 18:53:35 +0800 Subject: [PATCH 25/97] acpi: Add machine option to disable SPCR table The ACPI SPCR (Serial Port Console Redirection) table allows firmware to specify a preferred serial console device to the operating system. On ARM64 systems, Linux by default respects this table: even if the kernel command line does not include a hardware serial console (e.g., "console=ttyAMA0"), the kernel still register the serial device referenced by SPCR as a printk console. While this behavior is standard-compliant, it can lead to situations where guest console behavior is influenced by platform firmware rather than user-specified configuration. To make guest console behavior more predictable and under user control, this patch introduces a machine option to explicitly disable SPCR table exposure: -machine spcr=off By default, the option is enabled (spcr=on), preserving existing behavior. When disabled, QEMU will omit the SPCR table from the guest's ACPI namespace, ensuring that only consoles explicitly declared in the kernel command line are registered. Signed-off-by: Li Chen Reviewed-by: Bibo Mao Acked-by: Michael S. Tsirkin Reviewed-by: Gavin Shan Reviewed-by: Sunil V L Message-Id: <20250528105404.457729-2-me@linux.beauty> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt-acpi-build.c | 5 ++++- hw/core/machine.c | 22 ++++++++++++++++++++++ hw/loongarch/virt-acpi-build.c | 4 +++- hw/riscv/virt-acpi-build.c | 5 ++++- include/hw/boards.h | 1 + qemu-options.hx | 5 +++++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 0dfb8ec2c3..782b17b966 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -1023,7 +1023,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) } acpi_add_table(table_offsets, tables_blob); - spcr_setup(tables_blob, tables->linker, vms); + + if (ms->acpi_spcr_enabled) { + spcr_setup(tables_blob, tables->linker, vms); + } acpi_add_table(table_offsets, tables_blob); build_dbg2(tables_blob, tables->linker, vms); diff --git a/hw/core/machine.c b/hw/core/machine.c index e869821b22..ceee058cad 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -577,6 +577,20 @@ static void machine_set_nvdimm(Object *obj, bool value, Error **errp) ms->nvdimms_state->is_enabled = value; } +static bool machine_get_spcr(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->acpi_spcr_enabled; +} + +static void machine_set_spcr(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->acpi_spcr_enabled = value; +} + static bool machine_get_hmat(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -1281,6 +1295,14 @@ static void machine_initfn(Object *obj) "Table (HMAT)"); } + /* SPCR */ + ms->acpi_spcr_enabled = true; + object_property_add_bool(obj, "spcr", machine_get_spcr, machine_set_spcr); + object_property_set_description(obj, "spcr", + "Set on/off to enable/disable " + "ACPI Serial Port Console Redirection " + "Table (spcr)"); + /* default to mc->default_cpus */ ms->smp.cpus = mc->default_cpus; ms->smp.max_cpus = mc->default_cpus; diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c index 2cd2d9d842..8c2228a772 100644 --- a/hw/loongarch/virt-acpi-build.c +++ b/hw/loongarch/virt-acpi-build.c @@ -557,7 +557,9 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, machine); acpi_add_table(table_offsets, tables_blob); - spcr_setup(tables_blob, tables->linker, machine); + + if (machine->acpi_spcr_enabled) + spcr_setup(tables_blob, tables->linker, machine); if (machine->numa_state->num_nodes) { if (machine->numa_state->have_numa_distance) { diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 8b5683dbde..ee1416d264 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -894,7 +894,10 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) } acpi_add_table(table_offsets, tables_blob); - spcr_setup(tables_blob, tables->linker, s); + + if (ms->acpi_spcr_enabled) { + spcr_setup(tables_blob, tables->linker, s); + } acpi_add_table(table_offsets, tables_blob); { diff --git a/include/hw/boards.h b/include/hw/boards.h index f424b2b505..f94713e6e2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -443,6 +443,7 @@ struct MachineState { SmpCache smp_cache; struct NVDIMMState *nvdimms_state; struct NumaState *numa_state; + bool acpi_spcr_enabled; }; /* diff --git a/qemu-options.hx b/qemu-options.hx index 1f862b19a6..9b2d5f4b7a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,6 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " nvdimm=on|off controls NVDIMM support (default=off)\n" " memory-encryption=@var{} memory encryption object to use (default=none)\n" " hmat=on|off controls ACPI HMAT support (default=off)\n" + " spcr=on|off controls ACPI SPCR support (default=on)\n" #ifdef CONFIG_POSIX " aux-ram-share=on|off allocate auxiliary guest RAM as shared (default: off)\n" #endif @@ -105,6 +106,10 @@ SRST Enables or disables ACPI Heterogeneous Memory Attribute Table (HMAT) support. The default is off. + ``spcr=on|off`` + Enables or disables ACPI Serial Port Console Redirection Table + (SPCR) support. The default is on. + ``aux-ram-share=on|off`` Allocate auxiliary guest RAM as an anonymous file that is shareable with an external process. This option applies to From 9ce87106c7bcb1c2ada17e578db87f13ac29ae92 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Wed, 28 May 2025 18:53:36 +0800 Subject: [PATCH 26/97] tests/qtest/bios-tables-test: Add test for disabling SPCR on AArch64 Add ACPI SPCR table test case for ARM when SPCR was off. Signed-off-by: Li Chen Message-Id: <20250528105404.457729-3-me@linux.beauty> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index f41e638014..c84cf1070d 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1789,6 +1789,24 @@ static void test_acpi_aarch64_virt_tcg_pxb(void) free_test_data(&data); } +static void test_acpi_aarch64_virt_tcg_acpi_spcr(void) +{ + test_data data = { + .machine = "virt", + .arch = "aarch64", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 128ULL * 1024 * 1024, + .variant = ".acpispcr", + }; + + test_acpi_one("-cpu cortex-a57 " + " -machine spcr=off", &data); + free_test_data(&data); +} static void test_acpi_tcg_acpi_hmat(const char *machine, const char *arch) { test_data data = {}; @@ -2672,6 +2690,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/virt/pxb", test_acpi_aarch64_virt_tcg_pxb); qtest_add_func("acpi/virt/oem-fields", test_acpi_aarch64_virt_oem_fields); + qtest_add_func("acpi/virt/acpispcr", + test_acpi_aarch64_virt_tcg_acpi_spcr); if (qtest_has_device("virtio-iommu-pci")) { qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot); } From da77fc6c2e28a17249a6f459213247720e22e170 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Wed, 28 May 2025 18:53:37 +0800 Subject: [PATCH 27/97] tests/qtest/bios-tables-test: Add test for disabling SPCR on RISC-V Add ACPI SPCR table test case for RISC-V when SPCR was off. Signed-off-by: Li Chen Reviewed-by: Sunil V L Message-Id: <20250528105404.457729-4-me@linux.beauty> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index c84cf1070d..e988deac02 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1807,6 +1807,26 @@ static void test_acpi_aarch64_virt_tcg_acpi_spcr(void) " -machine spcr=off", &data); free_test_data(&data); } + +static void test_acpi_riscv64_virt_tcg_acpi_spcr(void) +{ + test_data data = { + .machine = "virt", + .arch = "riscv64", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-riscv-code.fd", + .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2", + .ram_start = 0x80000000ULL, + .scan_len = 128ULL * 1024 * 1024, + .variant = ".acpispcr", + }; + + test_acpi_one("-cpu rva22s64 " + "-machine spcr=off", &data); + free_test_data(&data); +} + static void test_acpi_tcg_acpi_hmat(const char *machine, const char *arch) { test_data data = {}; @@ -2701,6 +2721,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg); qtest_add_func("acpi/virt/numamem", test_acpi_riscv64_virt_tcg_numamem); + qtest_add_func("acpi/virt/acpispcr", + test_acpi_riscv64_virt_tcg_acpi_spcr); } } else if (strcmp(arch, "loongarch64") == 0) { if (has_tcg) { From 4bf06bcf072968c702712ed7fcb2a53f5a252216 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 14 Jul 2025 16:42:12 -0400 Subject: [PATCH 28/97] rust: bindings: allow any number of params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to be adding more parameters, and this makes rust unhappy: Functions with lots of parameters are considered bad style and reduce readability (“what does the 5th parameter mean?”). Consider grouping some parameters into a new type. Specifically: error: this function has too many arguments (8/7) --> /builds/mstredhat/qemu/build/rust/qemu-api/rust-qemu-api-tests.p/structured/bindings.inc.rs:3840:5 | 3840 | / pub fn new_bitfield_1( 3841 | | secure: std::os::raw::c_uint, 3842 | | space: std::os::raw::c_uint, 3843 | | user: std::os::raw::c_uint, ... | 3848 | | address_type: std::os::raw::c_uint, 3849 | | ) -> __BindgenBitfieldUnit<[u8; 4usize]> { | |____________________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments = note: `-D clippy::too-many-arguments` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]` Reviewed-by: Philippe Mathieu-DaudĂ© Acked-by: Paolo Bonzini Message-Id: Signed-off-by: Michael S. Tsirkin --- rust/qemu-api/src/bindings.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 057de4b646..c4f1f755ce 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -13,7 +13,8 @@ clippy::missing_const_for_fn, clippy::ptr_offset_with_cast, clippy::useless_transmute, - clippy::missing_safety_doc + clippy::missing_safety_doc, + clippy::too_many_arguments )] //! `bindgen`-generated declarations. From 06895f7948a32e833a8686d8394064ca2a4d66cc Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:03:58 +0000 Subject: [PATCH 29/97] pci: Add a memory attribute for pre-translated DMA operations The address_type bit will be set to PCI_AT_TRANSLATED by devices that use cached addresses obtained via ATS. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-2-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/exec/memattrs.h | 3 +++ include/hw/pci/pci.h | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index 8db1d30464..52ee955249 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -54,6 +54,9 @@ typedef struct MemTxAttrs { */ unsigned int pid:8; + /* PCI - IOMMU operations, see PCIAddressType */ + unsigned int address_type:1; + /* * Bus masters which don't specify any attributes will get this * (via the MEMTXATTRS_UNSPECIFIED constant), so that we can diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index df3cc7b875..6b7d3ac8a3 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -134,6 +134,15 @@ struct PCIHostDeviceAddress { unsigned int function; }; +/* + * Represents the Address Type (AT) field in a PCI request, + * see MemTxAttrs.address_type + */ +typedef enum PCIAddressType { + PCI_AT_UNTRANSLATED = 0, /* Default when no attribute is set */ + PCI_AT_TRANSLATED = 1, +} PCIAddressType; + typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, uint32_t address, uint32_t data, int len); typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, From 4b05c720aaf32c404003a3235300466b7b3342c3 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:03:59 +0000 Subject: [PATCH 30/97] memory: Add permissions in IOMMUAccessFlags This will be necessary for devices implementing ATS. We also define a new macro IOMMU_ACCESS_FLAG_FULL in addition to IOMMU_ACCESS_FLAG to support more access flags. IOMMU_ACCESS_FLAG is kept for convenience and backward compatibility. Here are the flags added (defined by the PCIe 5 specification) : - Execute Requested - Privileged Mode Requested - Global - Untranslated Only IOMMU_ACCESS_FLAG sets the additional flags to 0 Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-3-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/system/memory.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/system/memory.h b/include/system/memory.h index 46248d4a52..1672622d70 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -109,15 +109,34 @@ struct MemoryRegionSection { typedef struct IOMMUTLBEntry IOMMUTLBEntry; -/* See address_space_translate: bit 0 is read, bit 1 is write. */ +/* + * See address_space_translate: + * - bit 0 : read + * - bit 1 : write + * - bit 2 : exec + * - bit 3 : priv + * - bit 4 : global + * - bit 5 : untranslated only + */ typedef enum { IOMMU_NONE = 0, IOMMU_RO = 1, IOMMU_WO = 2, IOMMU_RW = 3, + IOMMU_EXEC = 4, + IOMMU_PRIV = 8, + IOMMU_GLOBAL = 16, + IOMMU_UNTRANSLATED_ONLY = 32, } IOMMUAccessFlags; -#define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | ((w) ? IOMMU_WO : 0)) +#define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | \ + ((w) ? IOMMU_WO : 0)) +#define IOMMU_ACCESS_FLAG_FULL(r, w, x, p, g, uo) \ + (IOMMU_ACCESS_FLAG(r, w) | \ + ((x) ? IOMMU_EXEC : 0) | \ + ((p) ? IOMMU_PRIV : 0) | \ + ((g) ? IOMMU_GLOBAL : 0) | \ + ((uo) ? IOMMU_UNTRANSLATED_ONLY : 0)) struct IOMMUTLBEntry { AddressSpace *target_as; From 1f81edd7007f00be44966148daaf415158f49009 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:00 +0000 Subject: [PATCH 31/97] memory: Allow to store the PASID in IOMMUTLBEntry This will be useful for devices that support ATS and need to store entries in an ATC (device IOTLB). Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-4-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/system/memory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/system/memory.h b/include/system/memory.h index 1672622d70..d6d069fd50 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -144,6 +144,7 @@ struct IOMMUTLBEntry { hwaddr translated_addr; hwaddr addr_mask; /* 0xfff = 4k translation */ IOMMUAccessFlags perm; + uint32_t pasid; }; /* From f8eee3452ffb6257bbb3537b987e1e95c2bd5d95 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:02 +0000 Subject: [PATCH 32/97] intel_iommu: Fill the PASID field when creating an IOMMUTLBEntry PASID value must be used by devices as a key (or part of a key) when populating their ATC with the IOTLB entries returned by the IOMMU. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-5-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 69d72ad35c..0fb4350d48 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2503,6 +2503,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, .translated_addr = 0, .addr_mask = size - 1, .perm = IOMMU_NONE, + .pasid = vtd_as->pasid, }, }; memory_region_notify_iommu(&vtd_as->iommu, 0, event); @@ -3090,6 +3091,7 @@ static void do_invalidate_device_tlb(VTDAddressSpace *vtd_dev_as, event.entry.iova = addr; event.entry.perm = IOMMU_NONE; event.entry.translated_addr = 0; + event.entry.pasid = vtd_dev_as->pasid; memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event); } @@ -3672,6 +3674,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr, IOMMUTLBEntry iotlb = { /* We'll fill in the rest later. */ .target_as = &address_space_memory, + .pasid = vtd_as->pasid, }; bool success; From 9b3725eec592140ec3d6557ec0f4c86991af7bd9 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:03 +0000 Subject: [PATCH 33/97] intel_iommu: Declare supported PASID size the PSS field of the extended capabilities stores the supported PASID size minus 1. This commit adds support for 8bits PASIDs (limited by MemTxAttrs::pid). Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-6-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 2 +- hw/i386/intel_iommu_internal.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0fb4350d48..71497f1936 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4590,7 +4590,7 @@ static void vtd_cap_init(IntelIOMMUState *s) } if (s->pasid) { - s->ecap |= VTD_ECAP_PASID; + s->ecap |= VTD_ECAP_PASID | VTD_ECAP_PSS; } } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e8b211e8b0..360e937989 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -192,6 +192,7 @@ #define VTD_ECAP_SC (1ULL << 7) #define VTD_ECAP_MHMV (15ULL << 20) #define VTD_ECAP_SRS (1ULL << 31) +#define VTD_ECAP_PSS (7ULL << 35) /* limit: MemTxAttrs::pid */ #define VTD_ECAP_PASID (1ULL << 40) #define VTD_ECAP_SMTS (1ULL << 43) #define VTD_ECAP_SLTS (1ULL << 46) From d6f6467b7cad6615bba78a40f1a1ed703a667f44 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:05 +0000 Subject: [PATCH 34/97] intel_iommu: Implement vtd_get_iotlb_info from PCIIOMMUOps Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-7-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 71497f1936..affa7768e6 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4733,10 +4733,20 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } +static void vtd_get_iotlb_info(void *opaque, uint8_t *addr_width, + uint32_t *min_page_size) +{ + IntelIOMMUState *s = opaque; + + *addr_width = s->aw_bits; + *min_page_size = VTD_PAGE_SIZE; +} + static PCIIOMMUOps vtd_iommu_ops = { .get_address_space = vtd_host_dma_iommu, .set_iommu_device = vtd_dev_set_iommu_device, .unset_iommu_device = vtd_dev_unset_iommu_device, + .get_iotlb_info = vtd_get_iotlb_info, }; static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) From 838efe99fde22f7ee120cddae3cce732653db869 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:07 +0000 Subject: [PATCH 35/97] intel_iommu: Implement the PCIIOMMUOps callbacks related to invalidations of device-IOTLB Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-8-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index affa7768e6..234c452849 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4733,6 +4733,15 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } +static void vtd_init_iotlb_notifier(PCIBus *bus, void *opaque, int devfn, + IOMMUNotifier *n, IOMMUNotify fn, + void *user_opaque) +{ + n->opaque = user_opaque; + iommu_notifier_init(n, fn, IOMMU_NOTIFIER_DEVIOTLB_EVENTS, 0, + HWADDR_MAX, 0); +} + static void vtd_get_iotlb_info(void *opaque, uint8_t *addr_width, uint32_t *min_page_size) { @@ -4742,11 +4751,37 @@ static void vtd_get_iotlb_info(void *opaque, uint8_t *addr_width, *min_page_size = VTD_PAGE_SIZE; } +static void vtd_register_iotlb_notifier(PCIBus *bus, void *opaque, + int devfn, uint32_t pasid, + IOMMUNotifier *n) +{ + IntelIOMMUState *s = opaque; + VTDAddressSpace *vtd_as; + + vtd_as = vtd_find_add_as(s, bus, devfn, pasid); + memory_region_register_iommu_notifier(MEMORY_REGION(&vtd_as->iommu), n, + &error_fatal); +} + +static void vtd_unregister_iotlb_notifier(PCIBus *bus, void *opaque, + int devfn, uint32_t pasid, + IOMMUNotifier *n) +{ + IntelIOMMUState *s = opaque; + VTDAddressSpace *vtd_as; + + vtd_as = vtd_find_add_as(s, bus, devfn, pasid); + memory_region_unregister_iommu_notifier(MEMORY_REGION(&vtd_as->iommu), n); +} + static PCIIOMMUOps vtd_iommu_ops = { .get_address_space = vtd_host_dma_iommu, .set_iommu_device = vtd_dev_set_iommu_device, .unset_iommu_device = vtd_dev_unset_iommu_device, .get_iotlb_info = vtd_get_iotlb_info, + .init_iotlb_notifier = vtd_init_iotlb_notifier, + .register_iotlb_notifier = vtd_register_iotlb_notifier, + .unregister_iotlb_notifier = vtd_unregister_iotlb_notifier, }; static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) From 35b47759c720cc6a3b5ce51c76f981b45df64a7d Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:08 +0000 Subject: [PATCH 36/97] intel_iommu: Return page walk level even when the translation fails We will use this information in vtd_do_iommu_translate to populate the IOMMUTLBEntry and indicate the correct page mask. This prevents ATS devices from sending many useless translation requests when a megapage or gigapage is not present. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-9-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 234c452849..bff307b9bc 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1987,9 +1987,9 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce, uint32_t pasid) { dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid); - uint32_t level = vtd_get_iova_level(s, ce, pasid); uint32_t offset; uint64_t flpte, flag_ad = VTD_FL_A; + *flpte_level = vtd_get_iova_level(s, ce, pasid); if (!vtd_iova_fl_check_canonical(s, iova, ce, pasid)) { error_report_once("%s: detected non canonical IOVA (iova=0x%" PRIx64 "," @@ -1998,11 +1998,11 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce, } while (true) { - offset = vtd_iova_level_offset(iova, level); + offset = vtd_iova_level_offset(iova, *flpte_level); flpte = vtd_get_pte(addr, offset); if (flpte == (uint64_t)-1) { - if (level == vtd_get_iova_level(s, ce, pasid)) { + if (*flpte_level == vtd_get_iova_level(s, ce, pasid)) { /* Invalid programming of pasid-entry */ return -VTD_FR_PASID_ENTRY_FSPTPTR_INV; } else { @@ -2028,15 +2028,15 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce, if (is_write && !(flpte & VTD_FL_RW)) { return -VTD_FR_SM_WRITE; } - if (vtd_flpte_nonzero_rsvd(flpte, level)) { + if (vtd_flpte_nonzero_rsvd(flpte, *flpte_level)) { error_report_once("%s: detected flpte reserved non-zero " "iova=0x%" PRIx64 ", level=0x%" PRIx32 "flpte=0x%" PRIx64 ", pasid=0x%" PRIX32 ")", - __func__, iova, level, flpte, pasid); + __func__, iova, *flpte_level, flpte, pasid); return -VTD_FR_FS_PAGING_ENTRY_RSVD; } - if (vtd_is_last_pte(flpte, level) && is_write) { + if (vtd_is_last_pte(flpte, *flpte_level) && is_write) { flag_ad |= VTD_FL_D; } @@ -2044,14 +2044,13 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce, return -VTD_FR_FS_BIT_UPDATE_FAILED; } - if (vtd_is_last_pte(flpte, level)) { + if (vtd_is_last_pte(flpte, *flpte_level)) { *flptep = flpte; - *flpte_level = level; return 0; } addr = vtd_get_pte_addr(flpte, aw_bits); - level--; + (*flpte_level)--; } } From 580b926344a88997264b0a72576bba35f76c59e1 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:09 +0000 Subject: [PATCH 37/97] intel_iommu: Set address mask when a translation fails and adjust W permission Implements the behavior defined in section 10.2.3.5 of PCIe spec rev 5. This is needed by devices that support ATS. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-10-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index bff307b9bc..1b1b0b5632 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2091,7 +2091,8 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, uint8_t bus_num = pci_bus_num(bus); VTDContextCacheEntry *cc_entry; uint64_t pte, page_mask; - uint32_t level, pasid = vtd_as->pasid; + uint32_t level = UINT32_MAX; + uint32_t pasid = vtd_as->pasid; uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn); int ret_fr; bool is_fpd_set = false; @@ -2250,14 +2251,19 @@ out: entry->iova = addr & page_mask; entry->translated_addr = vtd_get_pte_addr(pte, s->aw_bits) & page_mask; entry->addr_mask = ~page_mask; - entry->perm = access_flags; + entry->perm = (is_write ? access_flags : (access_flags & (~IOMMU_WO))); return true; error: vtd_iommu_unlock(s); entry->iova = 0; entry->translated_addr = 0; - entry->addr_mask = 0; + /* + * Set the mask for ATS (the range must be present even when the + * translation fails : PCIe rev 5 10.2.3.5) + */ + entry->addr_mask = (level != UINT32_MAX) ? + (~vtd_pt_level_page_mask(level)) : (~VTD_PAGE_MASK_4K); entry->perm = IOMMU_NONE; return false; } From c049bf5bb9dd2cd12d6089cb102aeee268d06423 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Sat, 28 Jun 2025 18:04:10 +0000 Subject: [PATCH 38/97] intel_iommu: Add support for ATS Signed-off-by: Clement Mathieu--Drif Message-Id: <20250628180226.133285-11-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1b1b0b5632..fe9a5f2872 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4738,6 +4738,68 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } +static IOMMUTLBEntry vtd_iommu_ats_do_translate(IOMMUMemoryRegion *iommu, + hwaddr addr, + IOMMUAccessFlags flags) +{ + IOMMUTLBEntry entry; + VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); + + if (vtd_is_interrupt_addr(addr)) { + vtd_report_ir_illegal_access(vtd_as, addr, flags & IOMMU_WO); + entry.target_as = &address_space_memory; + entry.iova = 0; + entry.translated_addr = 0; + entry.addr_mask = ~VTD_PAGE_MASK_4K; + entry.perm = IOMMU_NONE; + entry.pasid = PCI_NO_PASID; + } else { + entry = vtd_iommu_translate(iommu, addr, flags, 0); + } + + return entry; +} + +static ssize_t vtd_ats_request_translation(PCIBus *bus, void *opaque, + int devfn, uint32_t pasid, + bool priv_req, bool exec_req, + hwaddr addr, size_t length, + bool no_write, IOMMUTLBEntry *result, + size_t result_length, + uint32_t *err_count) +{ + IntelIOMMUState *s = opaque; + VTDAddressSpace *vtd_as; + IOMMUAccessFlags flags = IOMMU_ACCESS_FLAG_FULL(true, !no_write, exec_req, + priv_req, false, false); + ssize_t res_index = 0; + hwaddr target_address = addr + length; + IOMMUTLBEntry entry; + + vtd_as = vtd_find_add_as(s, bus, devfn, pasid); + *err_count = 0; + + while ((addr < target_address) && (res_index < result_length)) { + entry = vtd_iommu_ats_do_translate(&vtd_as->iommu, addr, flags); + entry.perm &= ~IOMMU_GLOBAL; /* Spec 4.1.2: Global Mapping never set */ + + if ((entry.perm & flags) != flags) { + *err_count += 1; /* Less than expected */ + } + + result[res_index] = entry; + res_index += 1; + addr = (addr & (~entry.addr_mask)) + (entry.addr_mask + 1); + } + + /* Buffer too small */ + if (addr < target_address) { + return -ENOMEM; + } + + return res_index; +} + static void vtd_init_iotlb_notifier(PCIBus *bus, void *opaque, int devfn, IOMMUNotifier *n, IOMMUNotify fn, void *user_opaque) @@ -4787,6 +4849,7 @@ static PCIIOMMUOps vtd_iommu_ops = { .init_iotlb_notifier = vtd_init_iotlb_notifier, .register_iotlb_notifier = vtd_register_iotlb_notifier, .unregister_iotlb_notifier = vtd_unregister_iotlb_notifier, + .ats_request_translation = vtd_ats_request_translation, }; static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) From fafcff5f306ee91b20b7838ad1817ff6738642ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:12 +0200 Subject: [PATCH 39/97] target/qmp: Use target_cpu_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Message-Id: <20250708215320.70426-2-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- target/arm/arm-qmp-cmds.c | 3 ++- target/loongarch/loongarch-qmp-cmds.c | 3 ++- target/mips/system/mips-qmp-cmds.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c index cefd235263..d292c974c4 100644 --- a/target/arm/arm-qmp-cmds.c +++ b/target/arm/arm-qmp-cmds.c @@ -21,6 +21,7 @@ */ #include "qemu/osdep.h" +#include "qemu/target-info.h" #include "hw/boards.h" #include "kvm_arm.h" #include "qapi/error.h" @@ -241,7 +242,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) CpuDefinitionInfoList *cpu_list = NULL; GSList *list; - list = object_class_get_list(TYPE_ARM_CPU, false); + list = object_class_get_list(target_cpu_type(), false); g_slist_foreach(list, arm_cpu_add_definition, &cpu_list); g_slist_free(list); diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c index f5f1cd0009..1d8cd32f5f 100644 --- a/target/loongarch/loongarch-qmp-cmds.c +++ b/target/loongarch/loongarch-qmp-cmds.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "qemu/target-info.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" #include "cpu.h" @@ -32,7 +33,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) CpuDefinitionInfoList *cpu_list = NULL; GSList *list; - list = object_class_get_list(TYPE_LOONGARCH_CPU, false); + list = object_class_get_list(target_cpu_type(), false); g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list); g_slist_free(list); diff --git a/target/mips/system/mips-qmp-cmds.c b/target/mips/system/mips-qmp-cmds.c index d98d6623f2..b6a2874f2d 100644 --- a/target/mips/system/mips-qmp-cmds.c +++ b/target/mips/system/mips-qmp-cmds.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "qemu/target-info.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" #include "cpu.h" @@ -40,7 +41,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) CpuDefinitionInfoList *cpu_list = NULL; GSList *list; - list = object_class_get_list(TYPE_MIPS_CPU, false); + list = object_class_get_list(target_cpu_type(), false); g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); g_slist_free(list); From 0af00042a9290626e3c9f05cdc35b6e3d62ecd49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:13 +0200 Subject: [PATCH 40/97] qemu/target-info: Factor target_arch() out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To keep "qemu/target-info.h" self-contained to native types, declare target_arch() -- which returns a QAPI type -- in "qemu/target-info-qapi.h". No logical change. Keeping native types in "qemu/target-info.h" is necessary to keep building tests such tests/tcg/plugins/mem.c, as per the comment added in commit ecbcc9ead2f ("tests/tcg: add a system test to check memory instrumentation"): /* * plugins should not include anything from QEMU aside from the * API header. However as this is a test plugin to exercise the * internals of QEMU and we want to avoid needless code duplication we * do so here. bswap.h is pretty self-contained although it needs a * few things provided by compiler.h. */ Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Message-Id: <20250708215320.70426-3-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/machine-qmp-cmds.c | 8 +++----- include/qemu/target-info-qapi.h | 21 +++++++++++++++++++++ include/qemu/target-info.h | 2 +- target-info.c | 8 ++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 include/qemu/target-info-qapi.h diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index d82043e1c6..cd98daedd1 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -19,7 +19,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/type-helpers.h" #include "qemu/uuid.h" -#include "qemu/target-info.h" +#include "qemu/target-info-qapi.h" #include "qom/qom-qobject.h" #include "system/hostmem.h" #include "system/hw_accel.h" @@ -37,8 +37,7 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) MachineState *ms = MACHINE(qdev_get_machine()); MachineClass *mc = MACHINE_GET_CLASS(ms); CpuInfoFastList *head = NULL, **tail = &head; - SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), - -1, &error_abort); + SysEmuTarget target = target_arch(); CPUState *cpu; CPU_FOREACH(cpu) { @@ -139,8 +138,7 @@ QemuTargetInfo *qmp_query_target(Error **errp) { QemuTargetInfo *info = g_malloc0(sizeof(*info)); - info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, - &error_abort); + info->arch = target_arch(); return info; } diff --git a/include/qemu/target-info-qapi.h b/include/qemu/target-info-qapi.h new file mode 100644 index 0000000000..a337c867bf --- /dev/null +++ b/include/qemu/target-info-qapi.h @@ -0,0 +1,21 @@ +/* + * QEMU target info API (returning QAPI types) + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QEMU_TARGET_INFO_EXTRA_H +#define QEMU_TARGET_INFO_EXTRA_H + +#include "qapi/qapi-types-machine.h" + +/** + * target_arch: + * + * Returns: QAPI SysEmuTarget enum (e.g. SYS_EMU_TARGET_X86_64). + */ +SysEmuTarget target_arch(void); + +#endif diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index 850a2958b9..dde0e7d968 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -1,5 +1,5 @@ /* - * QEMU target info API + * QEMU target info API (returning native types) * * Copyright (c) Linaro * diff --git a/target-info.c b/target-info.c index 16fdca7aaa..9ebabec988 100644 --- a/target-info.c +++ b/target-info.c @@ -8,7 +8,9 @@ #include "qemu/osdep.h" #include "qemu/target-info.h" +#include "qemu/target-info-qapi.h" #include "qemu/target-info-impl.h" +#include "qapi/error.h" const char *target_name(void) { @@ -20,6 +22,12 @@ unsigned target_long_bits(void) return target_info()->long_bits; } +SysEmuTarget target_arch(void) +{ + return qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, + &error_abort); +} + const char *target_cpu_type(void) { return target_info()->cpu_type; From 536613be40c7005a956a52487c1fed4530d6613f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:14 +0200 Subject: [PATCH 41/97] qemu/target-info: Add %target_arch field to TargetInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Pierrick Bouvier Message-Id: <20250708215320.70426-4-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/qemu/target-info-impl.h | 4 +++- target-info-stub.c | 1 + target-info.c | 9 +++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index 1b51cbcfe1..a8b34d150a 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -9,11 +9,13 @@ #ifndef QEMU_TARGET_INFO_IMPL_H #define QEMU_TARGET_INFO_IMPL_H -#include "qemu/target-info.h" +#include "qapi/qapi-types-machine.h" typedef struct TargetInfo { /* runtime equivalent of TARGET_NAME definition */ const char *target_name; + /* related to TARGET_ARCH definition */ + SysEmuTarget target_arch; /* runtime equivalent of TARGET_LONG_BITS definition */ unsigned long_bits; /* runtime equivalent of CPU_RESOLVING_TYPE definition */ diff --git a/target-info-stub.c b/target-info-stub.c index fecc0e7128..2e4407ff04 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -14,6 +14,7 @@ static const TargetInfo target_info_stub = { .target_name = TARGET_NAME, + .target_arch = SYS_EMU_TARGET__MAX, .long_bits = TARGET_LONG_BITS, .cpu_type = CPU_RESOLVING_TYPE, .machine_typename = TYPE_MACHINE, diff --git a/target-info.c b/target-info.c index 9ebabec988..8e29553b4e 100644 --- a/target-info.c +++ b/target-info.c @@ -24,8 +24,13 @@ unsigned target_long_bits(void) SysEmuTarget target_arch(void) { - return qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, - &error_abort); + SysEmuTarget arch = target_info()->target_arch; + + if (arch == SYS_EMU_TARGET__MAX) { + arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, + &error_abort); + } + return arch; } const char *target_cpu_type(void) From a37aec2e7d8f7191d29c700629850da5057e446b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:15 +0200 Subject: [PATCH 42/97] qemu/target-info: Add target_endian_mode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit target_endian_mode() returns the default endianness (QAPI type) of a target. Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-Id: <20250708215320.70426-5-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/qemu/target-info-impl.h | 2 ++ include/qemu/target-info-qapi.h | 8 ++++++++ target-info-stub.c | 1 + target-info.c | 5 +++++ 4 files changed, 16 insertions(+) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index a8b34d150a..17887f64e2 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -22,6 +22,8 @@ typedef struct TargetInfo { const char *cpu_type; /* QOM typename machines for this binary must implement */ const char *machine_typename; + /* related to TARGET_BIG_ENDIAN definition */ + EndianMode endianness; } TargetInfo; /** diff --git a/include/qemu/target-info-qapi.h b/include/qemu/target-info-qapi.h index a337c867bf..d5ce052323 100644 --- a/include/qemu/target-info-qapi.h +++ b/include/qemu/target-info-qapi.h @@ -9,6 +9,7 @@ #ifndef QEMU_TARGET_INFO_EXTRA_H #define QEMU_TARGET_INFO_EXTRA_H +#include "qapi/qapi-types-common.h" #include "qapi/qapi-types-machine.h" /** @@ -18,4 +19,11 @@ */ SysEmuTarget target_arch(void); +/** + * target_endian_mode: + * + * Returns: QAPI EndianMode enum (e.g. ENDIAN_MODE_LITTLE). + */ +EndianMode target_endian_mode(void); + #endif diff --git a/target-info-stub.c b/target-info-stub.c index 2e4407ff04..ca0caa3686 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -18,6 +18,7 @@ static const TargetInfo target_info_stub = { .long_bits = TARGET_LONG_BITS, .cpu_type = CPU_RESOLVING_TYPE, .machine_typename = TYPE_MACHINE, + .endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG : ENDIAN_MODE_LITTLE, }; const TargetInfo *target_info(void) diff --git a/target-info.c b/target-info.c index 8e29553b4e..a756c0714c 100644 --- a/target-info.c +++ b/target-info.c @@ -42,3 +42,8 @@ const char *target_machine_typename(void) { return target_info()->machine_typename; } + +EndianMode target_endian_mode(void) +{ + return target_info()->endianness; +} From 749c21cf6d8ff8eff094137c4ca1298c8f714066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:16 +0200 Subject: [PATCH 43/97] qemu: Convert target_words_bigendian() to TargetInfo API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Richard Henderson Message-Id: <20250708215320.70426-6-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- cpu-target.c | 7 ------- hw/core/cpu-system.c | 2 +- hw/display/vga.c | 2 +- hw/virtio/virtio.c | 2 +- include/exec/tswap.h | 13 +------------ include/qemu/target-info.h | 12 ++++++++++++ system/memory.c | 1 + system/qtest.c | 1 + target-info.c | 5 +++++ 9 files changed, 23 insertions(+), 22 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index 1c90a30759..20db5ff310 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -22,7 +22,6 @@ #include "system/accel-ops.h" #include "system/cpus.h" #include "exec/cpu-common.h" -#include "exec/tswap.h" #include "exec/replay-core.h" #include "exec/log.h" #include "hw/core/cpu.h" @@ -85,9 +84,3 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...) #endif abort(); } - -#undef target_big_endian -bool target_big_endian(void) -{ - return TARGET_BIG_ENDIAN; -} diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 3c84176a0c..a975405d3a 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -24,7 +24,7 @@ #include "exec/cputlb.h" #include "system/memory.h" #include "exec/tb-flush.h" -#include "exec/tswap.h" +#include "qemu/target-info.h" #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "hw/core/sysemu-cpu-ops.h" diff --git a/hw/display/vga.c b/hw/display/vga.c index 20475ebbd3..90b89cf404 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -26,7 +26,7 @@ #include "qemu/units.h" #include "system/reset.h" #include "qapi/error.h" -#include "exec/tswap.h" +#include "qemu/target-info.h" #include "hw/display/vga.h" #include "hw/i386/x86.h" #include "hw/pci/pci.h" diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 82a285a31d..0f4d28033d 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -20,7 +20,7 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" -#include "exec/tswap.h" +#include "qemu/target-info.h" #include "qom/object_interfaces.h" #include "hw/core/cpu.h" #include "hw/virtio/virtio.h" diff --git a/include/exec/tswap.h b/include/exec/tswap.h index 49511f2611..55ffa63359 100644 --- a/include/exec/tswap.h +++ b/include/exec/tswap.h @@ -9,18 +9,7 @@ #define TSWAP_H #include "qemu/bswap.h" - -/** - * target_big_endian: - * Returns true if the (default) endianness of the target is big endian, - * false otherwise. Common code should normally never need to know about the - * endianness of the target, so please do *not* use this function unless you - * know very well what you are doing! - */ -bool target_big_endian(void); -#ifdef COMPILING_PER_TARGET -#define target_big_endian() TARGET_BIG_ENDIAN -#endif +#include "qemu/target-info.h" /* * If we're in target-specific code, we can hard-code the swapping diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index dde0e7d968..abcf25db6f 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -38,4 +38,16 @@ const char *target_machine_typename(void); */ const char *target_cpu_type(void); +/** + * target_big_endian: + * + * Returns: %true if the (default) endianness of the target is big endian, + * %false otherwise. + * + * Common code should normally never need to know about the endianness of + * the target, so please do *not* use this function unless you know very + * well what you are doing! + */ +bool target_big_endian(void); + #endif diff --git a/system/memory.c b/system/memory.c index e8d9b15b28..38da62f505 100644 --- a/system/memory.c +++ b/system/memory.c @@ -22,6 +22,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/qemu-print.h" +#include "qemu/target-info.h" #include "qom/object.h" #include "trace.h" #include "system/ram_addr.h" diff --git a/system/qtest.c b/system/qtest.c index 301b03be2d..fa42c9f921 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/cutils.h" +#include "qemu/target-info.h" #include "qom/object_interfaces.h" #define MAX_IRQ 256 diff --git a/target-info.c b/target-info.c index a756c0714c..3110ab32f7 100644 --- a/target-info.c +++ b/target-info.c @@ -47,3 +47,8 @@ EndianMode target_endian_mode(void) { return target_info()->endianness; } + +bool target_big_endian(void) +{ + return target_endian_mode() == ENDIAN_MODE_BIG; +} From 16c9cb7187ef2414e3ad509048d59a8a4e7d1cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:17 +0200 Subject: [PATCH 44/97] gdbstub/helpers: Replace TARGET_BIG_ENDIAN -> target_big_endian() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check endianness at runtime to remove the target-specific TARGET_BIG_ENDIAN definition. Use cpu_to_[be,le]XX() from "qemu/bswap.h" instead of tswapXX() from "exec/tswap.h". Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-DaudĂ© Message-Id: <20250708215320.70426-7-philmd@linaro.org> Reviewed-by: Manos Pitsidianakis Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/gdbstub/helpers.h | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/include/gdbstub/helpers.h b/include/gdbstub/helpers.h index 6f7cc48adc..b685afac43 100644 --- a/include/gdbstub/helpers.h +++ b/include/gdbstub/helpers.h @@ -16,7 +16,8 @@ #error "gdbstub helpers should only be included by target specific code" #endif -#include "exec/tswap.h" +#include "qemu/bswap.h" +#include "qemu/target-info.h" #include "cpu-param.h" /* @@ -33,40 +34,49 @@ static inline int gdb_get_reg8(GByteArray *buf, uint8_t val) static inline int gdb_get_reg16(GByteArray *buf, uint16_t val) { - uint16_t to_word = tswap16(val); - g_byte_array_append(buf, (uint8_t *) &to_word, 2); + if (target_big_endian()) { + cpu_to_be16s(&val); + } else { + cpu_to_le16s(&val); + } + g_byte_array_append(buf, (uint8_t *) &val, 2); return 2; } static inline int gdb_get_reg32(GByteArray *buf, uint32_t val) { - uint32_t to_long = tswap32(val); - g_byte_array_append(buf, (uint8_t *) &to_long, 4); + if (target_big_endian()) { + cpu_to_be32s(&val); + } else { + cpu_to_le32s(&val); + } + g_byte_array_append(buf, (uint8_t *) &val, 4); return 4; } static inline int gdb_get_reg64(GByteArray *buf, uint64_t val) { - uint64_t to_quad = tswap64(val); - g_byte_array_append(buf, (uint8_t *) &to_quad, 8); + if (target_big_endian()) { + cpu_to_be64s(&val); + } else { + cpu_to_le64s(&val); + } + g_byte_array_append(buf, (uint8_t *) &val, 8); return 8; } static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi, uint64_t val_lo) { - uint64_t to_quad; -#if TARGET_BIG_ENDIAN - to_quad = tswap64(val_hi); - g_byte_array_append(buf, (uint8_t *) &to_quad, 8); - to_quad = tswap64(val_lo); - g_byte_array_append(buf, (uint8_t *) &to_quad, 8); -#else - to_quad = tswap64(val_lo); - g_byte_array_append(buf, (uint8_t *) &to_quad, 8); - to_quad = tswap64(val_hi); - g_byte_array_append(buf, (uint8_t *) &to_quad, 8); -#endif + uint64_t tmp[2]; + if (target_big_endian()) { + tmp[0] = cpu_to_be64(val_hi); + tmp[1] = cpu_to_be64(val_lo); + } else { + tmp[0] = cpu_to_le64(val_lo); + tmp[1] = cpu_to_le64(val_hi); + } + g_byte_array_append(buf, (uint8_t *)&tmp, 16); return 16; } From 0f64fb674360393ae09605d8d53bf81c02c78a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:18 +0200 Subject: [PATCH 45/97] qemu: Declare all load/store helper in 'qemu/bswap.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict "exec/tswap.h" to the tswap*() methods, move the load/store helpers with the other ones declared in "qemu/bswap.h". Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Pierrick Bouvier Message-Id: <20250708215320.70426-8-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/bios-linker-loader.c | 2 - hw/arm/allwinner-r40.c | 1 - hw/arm/boot.c | 2 + hw/arm/npcm7xx.c | 2 +- hw/block/hd-geometry.c | 1 - hw/char/riscv_htif.c | 1 - hw/cxl/cxl-events.c | 2 - hw/display/artist.c | 1 + hw/display/ati.c | 1 + hw/net/can/ctucan_core.c | 1 - hw/net/lan9118.c | 1 + hw/net/rtl8139.c | 1 + hw/net/vmxnet3.c | 1 - hw/pci-host/gt64120.c | 1 + hw/pci-host/pnv_phb3.c | 1 + hw/pci-host/pnv_phb4.c | 1 + hw/pci-host/ppce500.c | 1 - hw/pci-host/sh_pci.c | 1 - hw/s390x/s390-pci-inst.c | 1 + hw/sensor/lsm303dlhc_mag.c | 1 - hw/smbios/smbios.c | 1 + hw/vfio/migration-multifd.c | 1 - hw/virtio/virtio-pci.c | 1 + hw/vmapple/virtio-blk.c | 1 - include/exec/tswap.h | 70 -------------------------- include/qemu/bswap.h | 73 ++++++++++++++++++++++++++++ include/system/memory.h | 1 - include/user/abitypes.h | 1 - target/arm/cpu.c | 1 - target/i386/tcg/system/excp_helper.c | 1 - target/i386/xsave_helper.c | 1 - target/ppc/mmu-hash64.h | 2 - target/riscv/vector_helper.c | 1 - tests/tcg/plugins/mem.c | 1 + 34 files changed, 87 insertions(+), 93 deletions(-) diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c index 108061828b..c9ffe449aa 100644 --- a/hw/acpi/bios-linker-loader.c +++ b/hw/acpi/bios-linker-loader.c @@ -22,8 +22,6 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/nvram/fw_cfg.h" -#include "qemu/bswap.h" - /* * Linker/loader is a paravirtualized interface that passes commands to guest. * The commands can be used to request guest to diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c index 0bf700865c..c8eda39957 100644 --- a/hw/arm/allwinner-r40.c +++ b/hw/arm/allwinner-r40.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qemu/bswap.h" #include "qemu/module.h" #include "qemu/units.h" #include "hw/boards.h" diff --git a/hw/arm/boot.c b/hw/arm/boot.c index becd827af1..d391cd01bb 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -15,6 +15,7 @@ #include "hw/arm/boot.h" #include "hw/arm/linux-boot-if.h" #include "cpu.h" +#include "exec/tswap.h" #include "exec/target_page.h" #include "system/kvm.h" #include "system/tcg.h" @@ -29,6 +30,7 @@ #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/units.h" +#include "qemu/bswap.h" /* Kernel boot protocol is specified in the kernel docs * Documentation/arm/Booting and Documentation/arm64/booting.txt diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 2f30c49df5..ecfae328a9 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -24,7 +24,7 @@ #include "hw/qdev-clock.h" #include "hw/qdev-properties.h" #include "qapi/error.h" -#include "qemu/bswap.h" +#include "exec/tswap.h" #include "qemu/units.h" #include "system/system.h" #include "target/arm/cpu-qom.h" diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c index f3939e73f4..db221901cf 100644 --- a/hw/block/hd-geometry.c +++ b/hw/block/hd-geometry.c @@ -33,7 +33,6 @@ #include "qemu/osdep.h" #include "system/block-backend.h" #include "qapi/qapi-types-block.h" -#include "qemu/bswap.h" #include "hw/block/block.h" #include "trace.h" diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index c884be5d75..a78ea9b01c 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -29,7 +29,6 @@ #include "qemu/timer.h" #include "qemu/error-report.h" #include "system/address-spaces.h" -#include "exec/tswap.h" #include "system/dma.h" #include "system/runstate.h" #include "trace.h" diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c index 12dee2e467..f90470930d 100644 --- a/hw/cxl/cxl-events.c +++ b/hw/cxl/cxl-events.c @@ -8,8 +8,6 @@ */ #include "qemu/osdep.h" - -#include "qemu/bswap.h" #include "qemu/error-report.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" diff --git a/hw/display/artist.c b/hw/display/artist.c index 3fafc8a222..3c884c9243 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -12,6 +12,7 @@ #include "qemu/log.h" #include "qemu/module.h" #include "qemu/units.h" +#include "qemu/bswap.h" #include "qapi/error.h" #include "hw/sysbus.h" #include "hw/loader.h" diff --git a/hw/display/ati.c b/hw/display/ati.c index 7de27732cd..f7c0006a87 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -22,6 +22,7 @@ #include "vga-access.h" #include "hw/qdev-properties.h" #include "vga_regs.h" +#include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/module.h" #include "qemu/error-report.h" diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c index 17131a4e18..6bd99c477b 100644 --- a/hw/net/can/ctucan_core.c +++ b/hw/net/can/ctucan_core.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "qemu/bswap.h" #include "qemu/bitops.h" #include "hw/irq.h" #include "migration/vmstate.h" diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 6dda1e5c94..3017e12971 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -21,6 +21,7 @@ #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qapi/error.h" +#include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/module.h" #include /* for crc32 */ diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 654a087d80..324fb932aa 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -57,6 +57,7 @@ #include "system/dma.h" #include "qemu/module.h" #include "qemu/timer.h" +#include "qemu/bswap.h" #include "net/net.h" #include "net/eth.h" #include "system/system.h" diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 7c0ca56b7c..af73aa8ef2 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -22,7 +22,6 @@ #include "net/tap.h" #include "net/checksum.h" #include "system/system.h" -#include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/pci/msix.h" diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c index b12a25696c..b1d96f62fe 100644 --- a/hw/pci-host/gt64120.c +++ b/hw/pci-host/gt64120.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" +#include "qemu/bswap.h" #include "hw/qdev-properties.h" #include "hw/registerfields.h" #include "hw/pci/pci_device.h" diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index a4335f44f2..5d8383fac3 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/bswap.h" #include "qapi/visitor.h" #include "qapi/error.h" #include "hw/pci-host/pnv_phb3_regs.h" diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 77ea35299d..18992054e8 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/bswap.h" #include "qapi/visitor.h" #include "qapi/error.h" #include "target/ppc/cpu.h" diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 52269b05bb..975d191ccb 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -20,7 +20,6 @@ #include "migration/vmstate.h" #include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" -#include "qemu/bswap.h" #include "hw/pci-host/ppce500.h" #include "qom/object.h" diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index de8f6a84aa..62fb945075 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -28,7 +28,6 @@ #include "hw/irq.h" #include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" -#include "qemu/bswap.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index b5dddb22b8..a3bb5aa221 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -16,6 +16,7 @@ #include "exec/target_page.h" #include "system/memory.h" #include "qemu/error-report.h" +#include "qemu/bswap.h" #include "system/hw_accel.h" #include "hw/boards.h" #include "hw/pci/pci_device.h" diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c index f9e501da84..cd5773ae64 100644 --- a/hw/sensor/lsm303dlhc_mag.c +++ b/hw/sensor/lsm303dlhc_mag.c @@ -28,7 +28,6 @@ #include "qapi/visitor.h" #include "qemu/module.h" #include "qemu/log.h" -#include "qemu/bswap.h" enum LSM303DLHCMagReg { LSM303DLHC_MAG_REG_CRA = 0x00, diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index ad4cd6721e..1ac063cfb4 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/bswap.h" #include "qapi/error.h" #include "qemu/config-file.h" #include "qemu/module.h" diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c index 55635486c8..9dc70fdf16 100644 --- a/hw/vfio/migration-multifd.c +++ b/hw/vfio/migration-multifd.c @@ -13,7 +13,6 @@ #include "hw/vfio/vfio-device.h" #include "migration/misc.h" #include "qapi/error.h" -#include "qemu/bswap.h" #include "qemu/error-report.h" #include "qemu/lockable.h" #include "qemu/main-loop.h" diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index fba2372c93..767216d795 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -30,6 +30,7 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" +#include "qemu/bswap.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/loader.h" diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c index 532b5649ab..9de9aaae0b 100644 --- a/hw/vmapple/virtio-blk.c +++ b/hw/vmapple/virtio-blk.c @@ -19,7 +19,6 @@ #include "hw/vmapple/vmapple.h" #include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-pci.h" -#include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" diff --git a/include/exec/tswap.h b/include/exec/tswap.h index 55ffa63359..72219e2c43 100644 --- a/include/exec/tswap.h +++ b/include/exec/tswap.h @@ -69,74 +69,4 @@ static inline void tswap64s(uint64_t *s) } } -/* Return ld{word}_{le,be}_p following target endianness. */ -#define LOAD_IMPL(word, args...) \ -do { \ - if (target_big_endian()) { \ - return glue(glue(ld, word), _be_p)(args); \ - } else { \ - return glue(glue(ld, word), _le_p)(args); \ - } \ -} while (0) - -static inline int lduw_p(const void *ptr) -{ - LOAD_IMPL(uw, ptr); -} - -static inline int ldsw_p(const void *ptr) -{ - LOAD_IMPL(sw, ptr); -} - -static inline int ldl_p(const void *ptr) -{ - LOAD_IMPL(l, ptr); -} - -static inline uint64_t ldq_p(const void *ptr) -{ - LOAD_IMPL(q, ptr); -} - -static inline uint64_t ldn_p(const void *ptr, int sz) -{ - LOAD_IMPL(n, ptr, sz); -} - -#undef LOAD_IMPL - -/* Call st{word}_{le,be}_p following target endianness. */ -#define STORE_IMPL(word, args...) \ -do { \ - if (target_big_endian()) { \ - glue(glue(st, word), _be_p)(args); \ - } else { \ - glue(glue(st, word), _le_p)(args); \ - } \ -} while (0) - - -static inline void stw_p(void *ptr, uint16_t v) -{ - STORE_IMPL(w, ptr, v); -} - -static inline void stl_p(void *ptr, uint32_t v) -{ - STORE_IMPL(l, ptr, v); -} - -static inline void stq_p(void *ptr, uint64_t v) -{ - STORE_IMPL(q, ptr, v); -} - -static inline void stn_p(void *ptr, int sz, uint64_t v) -{ - STORE_IMPL(n, ptr, sz, v); -} - -#undef STORE_IMPL - #endif /* TSWAP_H */ diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 9a11764536..39ba64046a 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,6 +1,8 @@ #ifndef BSWAP_H #define BSWAP_H +#include "qemu/target-info.h" + #undef bswap16 #define bswap16(_x) __builtin_bswap16(_x) #undef bswap32 @@ -432,4 +434,75 @@ DO_STN_LDN_P(be) #undef le_bswaps #undef be_bswaps + +/* Return ld{word}_{le,be}_p following target endianness. */ +#define LOAD_IMPL(word, args...) \ +do { \ + if (target_big_endian()) { \ + return glue(glue(ld, word), _be_p)(args); \ + } else { \ + return glue(glue(ld, word), _le_p)(args); \ + } \ +} while (0) + +static inline int lduw_p(const void *ptr) +{ + LOAD_IMPL(uw, ptr); +} + +static inline int ldsw_p(const void *ptr) +{ + LOAD_IMPL(sw, ptr); +} + +static inline int ldl_p(const void *ptr) +{ + LOAD_IMPL(l, ptr); +} + +static inline uint64_t ldq_p(const void *ptr) +{ + LOAD_IMPL(q, ptr); +} + +static inline uint64_t ldn_p(const void *ptr, int sz) +{ + LOAD_IMPL(n, ptr, sz); +} + +#undef LOAD_IMPL + +/* Call st{word}_{le,be}_p following target endianness. */ +#define STORE_IMPL(word, args...) \ +do { \ + if (target_big_endian()) { \ + glue(glue(st, word), _be_p)(args); \ + } else { \ + glue(glue(st, word), _le_p)(args); \ + } \ +} while (0) + + +static inline void stw_p(void *ptr, uint16_t v) +{ + STORE_IMPL(w, ptr, v); +} + +static inline void stl_p(void *ptr, uint32_t v) +{ + STORE_IMPL(l, ptr, v); +} + +static inline void stq_p(void *ptr, uint64_t v) +{ + STORE_IMPL(q, ptr, v); +} + +static inline void stn_p(void *ptr, int sz, uint64_t v) +{ + STORE_IMPL(n, ptr, sz, v); +} + +#undef STORE_IMPL + #endif /* BSWAP_H */ diff --git a/include/system/memory.h b/include/system/memory.h index d6d069fd50..e2cd6ed126 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -19,7 +19,6 @@ #include "exec/memattrs.h" #include "exec/memop.h" #include "exec/ramlist.h" -#include "exec/tswap.h" #include "qemu/bswap.h" #include "qemu/queue.h" #include "qemu/int128.h" diff --git a/include/user/abitypes.h b/include/user/abitypes.h index 7528124b62..be7a876523 100644 --- a/include/user/abitypes.h +++ b/include/user/abitypes.h @@ -6,7 +6,6 @@ #endif #include "exec/cpu-defs.h" -#include "exec/tswap.h" #include "user/tswap-target.h" #ifdef TARGET_ABI32 diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 08c43f674a..e2b2337399 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -23,7 +23,6 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "exec/page-vary.h" -#include "exec/tswap.h" #include "target/arm/idau.h" #include "qemu/module.h" #include "qapi/error.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index c162621587..50040f6fca 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -25,7 +25,6 @@ #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" -#include "exec/tswap.h" #include "tcg/helper-tcg.h" typedef struct TranslateParams { diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c index 24ab7be8e9..996e9f3bfe 100644 --- a/target/i386/xsave_helper.c +++ b/target/i386/xsave_helper.c @@ -5,7 +5,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/tswap.h" void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) { diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index b8fb12a970..ae8d4b37ae 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -1,8 +1,6 @@ #ifndef MMU_HASH64_H #define MMU_HASH64_H -#include "exec/tswap.h" - #ifndef CONFIG_USER_ONLY #ifdef TARGET_PPC64 diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index b41c29da0b..7c67d67a13 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -27,7 +27,6 @@ #include "exec/helper-proto.h" #include "exec/tlb-flags.h" #include "exec/target_page.h" -#include "exec/tswap.h" #include "fpu/softfloat.h" #include "tcg/tcg-gvec-desc.h" #include "internals.h" diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c index ca4e8883dd..9649bce99c 100644 --- a/tests/tcg/plugins/mem.c +++ b/tests/tcg/plugins/mem.c @@ -20,6 +20,7 @@ * few things provided by compiler.h. */ #include +#include #include #include From 7f2e88837cb0b03a8ace4a01628d9c26a1196452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Jul 2025 23:53:19 +0200 Subject: [PATCH 46/97] hw/virtio: Build various files once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that various VirtIO files don't use target specific API anymore, we can move them to the system_ss[] source set to build them once. Signed-off-by: Philippe Mathieu-DaudĂ© Reviewed-by: Manos Pitsidianakis Reviewed-by: Pierrick Bouvier Message-Id: <20250708215320.70426-9-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/meson.build | 6 ++++-- hw/virtio/meson.build | 20 +++++++++++--------- hw/virtio/virtio-config-io.c | 1 - 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/hw/block/meson.build b/hw/block/meson.build index 655704471a..43ed296cf4 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -13,7 +13,9 @@ system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c')) system_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c')) -specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c')) -specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) +system_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c')) +system_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('virtio-blk-common.c')) subdir('dataplane') diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 164f6fd995..3ea7b3cec8 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -1,6 +1,7 @@ system_virtio_ss = ss.source_set() system_virtio_ss.add(files('virtio-bus.c')) system_virtio_ss.add(files('iothread-vq-mapping.c')) +system_virtio_ss.add(files('virtio-config-io.c')) system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) @@ -10,11 +11,11 @@ system_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c') specific_virtio_ss = ss.source_set() specific_virtio_ss.add(files('virtio.c')) -specific_virtio_ss.add(files('virtio-config-io.c', 'virtio-qmp.c')) +specific_virtio_ss.add(files('virtio-qmp.c')) if have_vhost system_virtio_ss.add(files('vhost.c')) - specific_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c')) + system_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c')) if have_vhost_user # fixme - this really should be generic specific_virtio_ss.add(files('vhost-user.c')) @@ -43,22 +44,22 @@ if have_vhost endif if have_vhost_vdpa system_virtio_ss.add(files('vhost-vdpa.c')) - specific_virtio_ss.add(files('vhost-shadow-virtqueue.c')) + system_virtio_ss.add(files('vhost-shadow-virtqueue.c')) endif else system_virtio_ss.add(files('vhost-stub.c')) endif +system_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c')) -specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) -specific_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm.c', 'cbor-helpers.c'), libcbor]) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c')) -specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: files('virtio-nsm.c')) +system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('cbor-helpers.c'), libcbor]) +system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) @@ -67,6 +68,7 @@ virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk- virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c')) @@ -85,7 +87,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-md-pci.c')) -specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) +system_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss) system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) diff --git a/hw/virtio/virtio-config-io.c b/hw/virtio/virtio-config-io.c index ad78e0b9bc..f58d90b6e3 100644 --- a/hw/virtio/virtio-config-io.c +++ b/hw/virtio/virtio-config-io.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "hw/virtio/virtio.h" -#include "cpu.h" uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) { From 25e84c02e7aafbcb7a677569e9a4198e97cc38b8 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:45 +0200 Subject: [PATCH 47/97] hw/i386/acpi-build: Make aml_pci_device_dsm() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to export aml_pci_device_dsm() as it is only used in hw/i386/acpi-build.c. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Philippe Mathieu-DaudĂ© Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-2-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 2 +- include/hw/acpi/pci.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 61851cc840..f59026524f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -338,7 +338,7 @@ build_facs(GArray *table_data) g_array_append_vals(table_data, reserved, 40); /* Reserved */ } -Aml *aml_pci_device_dsm(void) +static Aml *aml_pci_device_dsm(void) { Aml *method; diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index 6359d574fd..ab0187a894 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -36,7 +36,6 @@ typedef struct AcpiMcfgInfo { void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, const char *oem_id, const char *oem_table_id); -Aml *aml_pci_device_dsm(void); void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); From c242101c3c92410b7f5196f9d04a2844867be682 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:46 +0200 Subject: [PATCH 48/97] hw/acpi: Rename and move build_x86_acpi_pci_hotplug to pcihp We plan to reuse build_x86_acpi_pci_hotplug() implementation for ARM so let's move the code to generic pcihp. Associated static aml_pci_pdsm() helper is also moved along. build_x86_acpi_pci_hotplug is renamed into build_acpi_pci_hotplug(). No code change intended. Also fix the reference to acpi_pci_hotplug.rst documentation Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-3-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 174 ++++++++++++++++++++++++++++++++++++++- hw/i386/acpi-build.c | 176 +--------------------------------------- hw/i386/acpi-build.h | 4 - include/hw/acpi/pcihp.h | 7 ++ 4 files changed, 182 insertions(+), 179 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 497281ae20..cbe7e01385 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "hw/acpi/pcihp.h" - +#include "hw/acpi/aml-build.h" #include "hw/pci-host/i440fx.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" @@ -513,6 +513,178 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, OBJ_PROP_FLAG_READ); } +void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar) +{ + Aml *UUID, *ifctx1; + uint8_t byte_list[1] = { 0 }; /* nothing supported yet */ + + aml_append(ctx, aml_store(aml_buffer(1, byte_list), retvar)); + /* + * PCI Firmware Specification 3.1 + * 4.6. _DSM Definitions for PCI + */ + UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); + ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID))); + { + /* call is for unsupported UUID, bail out */ + aml_append(ifctx1, aml_return(retvar)); + } + aml_append(ctx, ifctx1); + + ifctx1 = aml_if(aml_lless(aml_arg(1), aml_int(2))); + { + /* call is for unsupported REV, bail out */ + aml_append(ifctx1, aml_return(retvar)); + } + aml_append(ctx, ifctx1); +} + +static Aml *aml_pci_pdsm(void) +{ + Aml *method, *ifctx, *ifctx1; + Aml *ret = aml_local(0); + Aml *caps = aml_local(1); + Aml *acpi_index = aml_local(2); + Aml *zero = aml_int(0); + Aml *one = aml_int(1); + Aml *not_supp = aml_int(0xFFFFFFFF); + Aml *func = aml_arg(2); + Aml *params = aml_arg(4); + Aml *bnum = aml_derefof(aml_index(params, aml_int(0))); + Aml *sunum = aml_derefof(aml_index(params, aml_int(1))); + + method = aml_method("PDSM", 5, AML_SERIALIZED); + + /* get supported functions */ + ifctx = aml_if(aml_equal(func, zero)); + { + build_append_pci_dsm_func0_common(ifctx, ret); + + aml_append(ifctx, aml_store(zero, caps)); + aml_append(ifctx, + aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); + /* + * advertise function 7 if device has acpi-index + * acpi_index values: + * 0: not present (default value) + * FFFFFFFF: not supported (old QEMU without PIDX reg) + * other: device's acpi-index + */ + ifctx1 = aml_if(aml_lnot( + aml_or(aml_equal(acpi_index, zero), + aml_equal(acpi_index, not_supp), NULL) + )); + { + /* have supported functions */ + aml_append(ifctx1, aml_or(caps, one, caps)); + /* support for function 7 */ + aml_append(ifctx1, + aml_or(caps, aml_shiftleft(one, aml_int(7)), caps)); + } + aml_append(ifctx, ifctx1); + + aml_append(ifctx, aml_store(caps, aml_index(ret, zero))); + aml_append(ifctx, aml_return(ret)); + } + aml_append(method, ifctx); + + /* handle specific functions requests */ + /* + * PCI Firmware Specification 3.1 + * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under + * Operating Systems + */ + ifctx = aml_if(aml_equal(func, aml_int(7))); + { + Aml *pkg = aml_package(2); + + aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); + aml_append(ifctx, aml_store(pkg, ret)); + /* + * Windows calls func=7 without checking if it's available, + * as workaround Microsoft has suggested to return invalid for func7 + * Package, so return 2 elements package but only initialize elements + * when acpi_index is supported and leave them uninitialized, which + * leads elements to being Uninitialized ObjectType and should trip + * Windows into discarding result as an unexpected and prevent setting + * bogus 'PCI Label' on the device. + */ + ifctx1 = aml_if(aml_lnot(aml_lor( + aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp) + ))); + { + aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero))); + /* + * optional, if not impl. should return null string + */ + aml_append(ifctx1, aml_store(aml_string("%s", ""), + aml_index(ret, one))); + } + aml_append(ifctx, ifctx1); + + aml_append(ifctx, aml_return(ret)); + } + + aml_append(method, ifctx); + return method; +} + +void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) +{ + Aml *scope; + Aml *field; + Aml *method; + + scope = aml_scope("_SB.PCI0"); + + aml_append(scope, + aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(pcihp_addr), 0x08)); + field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_named_field("PCIU", 32)); + aml_append(field, aml_named_field("PCID", 32)); + aml_append(scope, field); + + aml_append(scope, + aml_operation_region("SEJ", AML_SYSTEM_IO, + aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04)); + field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_named_field("B0EJ", 32)); + aml_append(scope, field); + + aml_append(scope, + aml_operation_region("BNMR", AML_SYSTEM_IO, + aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08)); + field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_named_field("BNUM", 32)); + aml_append(field, aml_named_field("PIDX", 32)); + aml_append(scope, field); + + aml_append(scope, aml_mutex("BLCK", 0)); + + method = aml_method("PCEJ", 2, AML_NOTSERIALIZED); + aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); + aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); + aml_append(method, + aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ"))); + aml_append(method, aml_release(aml_name("BLCK"))); + aml_append(method, aml_return(aml_int(0))); + aml_append(scope, method); + + method = aml_method("AIDX", 2, AML_NOTSERIALIZED); + aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); + aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); + aml_append(method, + aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX"))); + aml_append(method, aml_store(aml_name("PIDX"), aml_local(0))); + aml_append(method, aml_release(aml_name("BLCK"))); + aml_append(method, aml_return(aml_local(0))); + aml_append(scope, method); + + aml_append(scope, aml_pci_pdsm()); + + aml_append(table, scope); +} + const VMStateDescription vmstate_acpi_pcihp_pci_status = { .name = "acpi_pcihp_pci_status", .version_id = 1, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index f59026524f..4f8572eebe 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -361,32 +361,6 @@ static Aml *aml_pci_device_dsm(void) return method; } -static void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar) -{ - Aml *UUID, *ifctx1; - uint8_t byte_list[1] = { 0 }; /* nothing supported yet */ - - aml_append(ctx, aml_store(aml_buffer(1, byte_list), retvar)); - /* - * PCI Firmware Specification 3.1 - * 4.6. _DSM Definitions for PCI - */ - UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); - ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID))); - { - /* call is for unsupported UUID, bail out */ - aml_append(ifctx1, aml_return(retvar)); - } - aml_append(ctx, ifctx1); - - ifctx1 = aml_if(aml_lless(aml_arg(1), aml_int(2))); - { - /* call is for unsupported REV, bail out */ - aml_append(ifctx1, aml_return(retvar)); - } - aml_append(ctx, ifctx1); -} - static Aml *aml_pci_edsm(void) { Aml *method, *ifctx; @@ -647,96 +621,6 @@ static bool build_append_notification_callback(Aml *parent_scope, return !!nr_notifiers; } -static Aml *aml_pci_pdsm(void) -{ - Aml *method, *ifctx, *ifctx1; - Aml *ret = aml_local(0); - Aml *caps = aml_local(1); - Aml *acpi_index = aml_local(2); - Aml *zero = aml_int(0); - Aml *one = aml_int(1); - Aml *not_supp = aml_int(0xFFFFFFFF); - Aml *func = aml_arg(2); - Aml *params = aml_arg(4); - Aml *bnum = aml_derefof(aml_index(params, aml_int(0))); - Aml *sunum = aml_derefof(aml_index(params, aml_int(1))); - - method = aml_method("PDSM", 5, AML_SERIALIZED); - - /* get supported functions */ - ifctx = aml_if(aml_equal(func, zero)); - { - build_append_pci_dsm_func0_common(ifctx, ret); - - aml_append(ifctx, aml_store(zero, caps)); - aml_append(ifctx, - aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); - /* - * advertise function 7 if device has acpi-index - * acpi_index values: - * 0: not present (default value) - * FFFFFFFF: not supported (old QEMU without PIDX reg) - * other: device's acpi-index - */ - ifctx1 = aml_if(aml_lnot( - aml_or(aml_equal(acpi_index, zero), - aml_equal(acpi_index, not_supp), NULL) - )); - { - /* have supported functions */ - aml_append(ifctx1, aml_or(caps, one, caps)); - /* support for function 7 */ - aml_append(ifctx1, - aml_or(caps, aml_shiftleft(one, aml_int(7)), caps)); - } - aml_append(ifctx, ifctx1); - - aml_append(ifctx, aml_store(caps, aml_index(ret, zero))); - aml_append(ifctx, aml_return(ret)); - } - aml_append(method, ifctx); - - /* handle specific functions requests */ - /* - * PCI Firmware Specification 3.1 - * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under - * Operating Systems - */ - ifctx = aml_if(aml_equal(func, aml_int(7))); - { - Aml *pkg = aml_package(2); - - aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); - aml_append(ifctx, aml_store(pkg, ret)); - /* - * Windows calls func=7 without checking if it's available, - * as workaround Microsoft has suggested to return invalid for func7 - * Package, so return 2 elements package but only initialize elements - * when acpi_index is supported and leave them uninitialized, which - * leads elements to being Uninitialized ObjectType and should trip - * Windows into discarding result as an unexpected and prevent setting - * bogus 'PCI Label' on the device. - */ - ifctx1 = aml_if(aml_lnot(aml_lor( - aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp) - ))); - { - aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero))); - /* - * optional, if not impl. should return null string - */ - aml_append(ifctx1, aml_store(aml_string("%s", ""), - aml_index(ret, one))); - } - aml_append(ifctx, ifctx1); - - aml_append(ifctx, aml_return(ret)); - } - - aml_append(method, ifctx); - return method; -} - /* * build_prt - Define interrupt routing rules * @@ -1227,62 +1111,6 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg) return dev; } -static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) -{ - Aml *scope; - Aml *field; - Aml *method; - - scope = aml_scope("_SB.PCI0"); - - aml_append(scope, - aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(pcihp_addr), 0x08)); - field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_named_field("PCIU", 32)); - aml_append(field, aml_named_field("PCID", 32)); - aml_append(scope, field); - - aml_append(scope, - aml_operation_region("SEJ", AML_SYSTEM_IO, - aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04)); - field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_named_field("B0EJ", 32)); - aml_append(scope, field); - - aml_append(scope, - aml_operation_region("BNMR", AML_SYSTEM_IO, - aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08)); - field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_named_field("BNUM", 32)); - aml_append(field, aml_named_field("PIDX", 32)); - aml_append(scope, field); - - aml_append(scope, aml_mutex("BLCK", 0)); - - method = aml_method("PCEJ", 2, AML_NOTSERIALIZED); - aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); - aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); - aml_append(method, - aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ"))); - aml_append(method, aml_release(aml_name("BLCK"))); - aml_append(method, aml_return(aml_int(0))); - aml_append(scope, method); - - method = aml_method("AIDX", 2, AML_NOTSERIALIZED); - aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); - aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); - aml_append(method, - aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX"))); - aml_append(method, aml_store(aml_name("PIDX"), aml_local(0))); - aml_append(method, aml_release(aml_name("BLCK"))); - aml_append(method, aml_return(aml_local(0))); - aml_append(scope, method); - - aml_append(scope, aml_pci_pdsm()); - - aml_append(table, scope); -} - static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug) { Aml *if_ctx; @@ -1394,7 +1222,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { - build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); + build_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); } build_piix4_pci0_int(dsdt); } else if (q35) { @@ -1438,7 +1266,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en) { - build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); + build_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); } build_q35_pci0_int(dsdt); } diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h index 275ec058a1..8ba3c33e48 100644 --- a/hw/i386/acpi-build.h +++ b/hw/i386/acpi-build.h @@ -5,10 +5,6 @@ extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio; -/* PCI Hot-plug registers' base. See docs/specs/acpi_pci_hotplug.rst */ -#define ACPI_PCIHP_SEJ_BASE 0x8 -#define ACPI_PCIHP_BNMR_BASE 0x10 - void acpi_setup(void); Object *acpi_get_i386_pci_host(void); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index cdc0cb8e43..971451e8ea 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -33,6 +33,10 @@ #define ACPI_PCIHP_IO_BASE_PROP "acpi-pcihp-io-base" #define ACPI_PCIHP_IO_LEN_PROP "acpi-pcihp-io-len" +/* PCI Hot-plug registers bases. See docs/specs/acpi_pci_hotplug.rst */ +#define ACPI_PCIHP_SEJ_BASE 0x8 +#define ACPI_PCIHP_BNMR_BASE 0x10 + typedef struct AcpiPciHpPciStatus { uint32_t up; uint32_t down; @@ -69,6 +73,9 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp); +void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr); +void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar); + /* Called on reset */ void acpi_pcihp_reset(AcpiPciHpState *s); From eb3feb8747754d2e41654368133c2d61cc8dd72c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:47 +0200 Subject: [PATCH 49/97] hw/pci-host/gpex-acpi: Add native_pci_hotplug arg to acpi_dsdt_add_pci_osc Add a new argument to acpi_dsdt_add_pci_osc to be able to disable native pci hotplug. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-4-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-host/gpex-acpi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 0aba47c71c..f34b7cf25e 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -50,7 +50,7 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq, } } -static void acpi_dsdt_add_pci_osc(Aml *dev) +static void acpi_dsdt_add_pci_osc(Aml *dev, bool enable_native_pcie_hotplug) { Aml *method, *UUID, *ifctx, *ifctx1, *elsectx, *buf; @@ -77,11 +77,12 @@ static void acpi_dsdt_add_pci_osc(Aml *dev) aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); /* - * Allow OS control for all 5 features: - * PCIeHotplug SHPCHotplug PME AER PCIeCapability. + * Allow OS control for SHPCHotplug, PME, AER, PCIeCapability, + * and PCIeHotplug depending on enable_native_pcie_hotplug */ - aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F), - aml_name("CTRL"))); + aml_append(ifctx, aml_and(aml_name("CTRL"), + aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), + aml_name("CTRL"))); ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), @@ -192,7 +193,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) if (is_cxl) { build_cxl_osc_method(dev); } else { - acpi_dsdt_add_pci_osc(dev); + acpi_dsdt_add_pci_osc(dev, true); } aml_append(scope, dev); @@ -267,7 +268,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) } aml_append(dev, aml_name_decl("_CRS", rbuf)); - acpi_dsdt_add_pci_osc(dev); + acpi_dsdt_add_pci_osc(dev, true); Aml *dev_res0 = aml_device("%s", "RES0"); aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); From 9748673735d93da3b1da12041f2525e0fbca5dc6 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Mon, 14 Jul 2025 10:04:48 +0200 Subject: [PATCH 50/97] tests/qtest/bios-tables-test: Prepare for changes in the DSDT table This commit adds DSDT blobs to the whilelist in the prospect to allow changes in the GPEX _OSC method. Signed-off-by: Gustavo Romero Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Acked-by: Igor Mammedov Message-Id: <20250714080639.2525563-5-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..8d9673cb5d 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,12 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/aarch64/virt/DSDT", +"tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt", +"tests/data/acpi/aarch64/virt/DSDT.memhp", +"tests/data/acpi/aarch64/virt/DSDT.pxb", +"tests/data/acpi/aarch64/virt/DSDT.topology", +"tests/data/acpi/loongarch64/virt/DSDT.memhp", +"tests/data/acpi/loongarch64/virt/DSDT.topology", +"tests/data/acpi/loongarch64/virt/DSDT.numamem", +"tests/data/acpi/loongarch64/virt/DSDT", +"tests/data/acpi/x86/microvm/DSDT.pcie", +"tests/data/acpi/riscv64/virt/DSDT", From ec9af8919826d57126d9b83fa1715d1333b74a18 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:49 +0200 Subject: [PATCH 51/97] hw/pci-host/gpex-acpi: Split host bridge OSC and DSM generation acpi_dsdt_add_pci_osc() name is confusing as it gives the impression it appends the _OSC method but in fact it also appends the _DSM method for the host bridge. Let's split the function into two separate ones and let them return the method Aml pointer instead. This matches the way it is done on x86 (build_q35_osc_method). In a subsequent patch we will replace the gpex method by the q35 implementation that will become shared between ARM and x86. acpi_dsdt_add_host_bridge_methods is a new top helper that generates both the _OSC and _DSM methods. We take the opportunity to move SUPP and CTRL in the _osc method that use them. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-6-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-host/gpex-acpi.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index f34b7cf25e..80fc2bf032 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -50,14 +50,12 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq, } } -static void acpi_dsdt_add_pci_osc(Aml *dev, bool enable_native_pcie_hotplug) +static Aml *build_host_bridge_osc(bool enable_native_pcie_hotplug) { - Aml *method, *UUID, *ifctx, *ifctx1, *elsectx, *buf; - - /* Declare an _OSC (OS Control Handoff) method */ - aml_append(dev, aml_name_decl("SUPP", aml_int(0))); - aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + Aml *method, *UUID, *ifctx, *ifctx1, *elsectx; method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + aml_append(method, aml_name_decl("SUPP", aml_int(0))); + aml_append(method, aml_name_decl("CTRL", aml_int(0))); aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); @@ -103,9 +101,13 @@ static void acpi_dsdt_add_pci_osc(Aml *dev, bool enable_native_pcie_hotplug) aml_name("CDW1"))); aml_append(elsectx, aml_return(aml_arg(3))); aml_append(method, elsectx); - aml_append(dev, method); + return method; +} - method = aml_method("_DSM", 4, AML_NOTSERIALIZED); +static Aml *build_host_bridge_dsm(void) +{ + Aml *method = aml_method("_DSM", 4, AML_NOTSERIALIZED); + Aml *UUID, *ifctx, *ifctx1, *buf; /* PCI Firmware Specification 3.0 * 4.6.1. _DSM for PCI Express Slot Information @@ -124,7 +126,15 @@ static void acpi_dsdt_add_pci_osc(Aml *dev, bool enable_native_pcie_hotplug) byte_list[0] = 0; buf = aml_buffer(1, byte_list); aml_append(method, aml_return(buf)); - aml_append(dev, method); + return method; +} + +static void acpi_dsdt_add_host_bridge_methods(Aml *dev, + bool enable_native_pcie_hotplug) +{ + /* Declare an _OSC (OS Control Handoff) method */ + aml_append(dev, build_host_bridge_osc(enable_native_pcie_hotplug)); + aml_append(dev, build_host_bridge_dsm()); } void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) @@ -193,7 +203,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) if (is_cxl) { build_cxl_osc_method(dev); } else { - acpi_dsdt_add_pci_osc(dev, true); + acpi_dsdt_add_host_bridge_methods(dev, true); } aml_append(scope, dev); @@ -268,7 +278,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) } aml_append(dev, aml_name_decl("_CRS", rbuf)); - acpi_dsdt_add_pci_osc(dev, true); + acpi_dsdt_add_host_bridge_methods(dev, true); Aml *dev_res0 = aml_device("%s", "RES0"); aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); From c4ad7513565979ae4c3910bd37c453f5737343a1 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:50 +0200 Subject: [PATCH 52/97] hw/acpi/ged: Add a acpi-pci-hotplug-with-bridge-support property A new boolean property is introduced. This will be used to turn ACPI PCI hotplug support. By default it is unset. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-7-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 2 ++ include/hw/acpi/generic_event_device.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 7a62f8d5bc..7831db412b 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -318,6 +318,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) static const Property acpi_ged_properties[] = { DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0), + DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, AcpiGedState, + pcihp_state.use_acpi_hotplug_bridge, 0), }; static const VMStateDescription vmstate_memhp_state = { diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d2dac87b4a..f5ffa67a39 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -63,6 +63,7 @@ #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/ghes.h" #include "hw/acpi/cpu.h" +#include "hw/acpi/pcihp.h" #include "qom/object.h" #define ACPI_POWER_BUTTON_DEVICE "PWRB" @@ -114,6 +115,7 @@ struct AcpiGedState { MemoryRegion container_memhp; CPUHotplugState cpuhp_state; MemoryRegion container_cpuhp; + AcpiPciHpState pcihp_state; GEDState ged_state; uint32_t ged_event_bitmap; qemu_irq irq; From 1136309df5e3de7d031a137221318f48784cca5d Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:51 +0200 Subject: [PATCH 53/97] hw/pci-host/gpex-acpi: Use GED acpi pcihp property Retrieve the acpi pcihp property value from the ged. In case this latter is not set, PCI native hotplug is used on pci0. For expander bridges we keep pci native hotplug, as done on x86 q35. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-8-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt-acpi-build.c | 9 +++++++++ hw/pci-host/gpex-acpi.c | 3 ++- include/hw/pci-host/gpex.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 782b17b966..f3bad69aa7 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -144,12 +144,21 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int ecam_id = VIRT_ECAM_ID(vms->highmem_ecam); bool cxl_present = false; PCIBus *bus = vms->bus; + bool acpi_pcihp = false; + + if (vms->acpi_dev) { + acpi_pcihp = object_property_get_bool(OBJECT(vms->acpi_dev), + ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, + NULL); + } + struct GPEXConfig cfg = { .mmio32 = memmap[VIRT_PCIE_MMIO], .pio = memmap[VIRT_PCIE_PIO], .ecam = memmap[ecam_id], .irq = irq, .bus = vms->bus, + .pci_native_hotplug = !acpi_pcihp, }; if (vms->highmem_mmio) { diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 80fc2bf032..44737a8d81 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -203,6 +203,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) if (is_cxl) { build_cxl_osc_method(dev); } else { + /* pxb bridges do not have ACPI PCI Hot-plug enabled */ acpi_dsdt_add_host_bridge_methods(dev, true); } @@ -278,7 +279,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) } aml_append(dev, aml_name_decl("_CRS", rbuf)); - acpi_dsdt_add_host_bridge_methods(dev, true); + acpi_dsdt_add_host_bridge_methods(dev, cfg->pci_native_hotplug); Aml *dev_res0 = aml_device("%s", "RES0"); aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h index 84471533af..feaf827474 100644 --- a/include/hw/pci-host/gpex.h +++ b/include/hw/pci-host/gpex.h @@ -45,6 +45,7 @@ struct GPEXConfig { MemMapEntry pio; int irq; PCIBus *bus; + bool pci_native_hotplug; }; typedef struct GPEXIrq GPEXIrq; From dc925e4b1d19dcce93107d1d20f7232244f48924 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:52 +0200 Subject: [PATCH 54/97] hw/i386/acpi-build: Turn build_q35_osc_method into a generic method GPEX acpi_dsdt_add_pci_osc() does basically the same as build_q35_osc_method(). Rename build_q35_osc_method() into build_pci_host_bridge_osc_method() and move it into hw/acpi/pci.c. In a subsequent patch we will use this later in place of acpi_dsdt_add_pci_osc(). Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-9-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pci.c | 50 +++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 54 ++----------------------------------------- include/hw/acpi/pci.h | 2 ++ 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c index d511a85029..2228f1245e 100644 --- a/hw/acpi/pci.c +++ b/hw/acpi/pci.c @@ -301,3 +301,53 @@ void build_srat_generic_affinity_structures(GArray *table_data) object_child_foreach_recursive(object_get_root(), build_acpi_generic_port, table_data); } + +Aml *build_pci_host_bridge_osc_method(bool enable_native_pcie_hotplug) +{ + Aml *if_ctx; + Aml *if_ctx2; + Aml *else_ctx; + Aml *method; + Aml *a_cwd1 = aml_name("CDW1"); + Aml *a_ctrl = aml_local(0); + + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); + + if_ctx = aml_if(aml_equal( + aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); + aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); + aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + + aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); + + /* + * Always allow native PME, AER (no dependencies) + * Allow SHPC (PCI bridges can have SHPC controller) + * Disable PCIe Native Hot-plug if ACPI PCI Hot-plug is enabled. + */ + aml_append(if_ctx, aml_and(a_ctrl, + aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), a_ctrl)); + + if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); + /* Unknown revision */ + aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); + aml_append(if_ctx, if_ctx2); + + if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); + /* Capabilities bits were masked */ + aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); + aml_append(if_ctx, if_ctx2); + + /* Update DWORD3 in the buffer */ + aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); + aml_append(method, if_ctx); + + else_ctx = aml_else(); + /* Unrecognized UUID */ + aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); + aml_append(method, else_ctx); + + aml_append(method, aml_return(aml_arg(3))); + return method; +} diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4f8572eebe..91945f716c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1111,56 +1111,6 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg) return dev; } -static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug) -{ - Aml *if_ctx; - Aml *if_ctx2; - Aml *else_ctx; - Aml *method; - Aml *a_cwd1 = aml_name("CDW1"); - Aml *a_ctrl = aml_local(0); - - method = aml_method("_OSC", 4, AML_NOTSERIALIZED); - aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); - - if_ctx = aml_if(aml_equal( - aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); - - aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); - - /* - * Always allow native PME, AER (no dependencies) - * Allow SHPC (PCI bridges can have SHPC controller) - * Disable PCIe Native Hot-plug if ACPI PCI Hot-plug is enabled. - */ - aml_append(if_ctx, aml_and(a_ctrl, - aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), a_ctrl)); - - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); - /* Unknown revision */ - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); - aml_append(if_ctx, if_ctx2); - - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); - /* Capabilities bits were masked */ - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); - aml_append(if_ctx, if_ctx2); - - /* Update DWORD3 in the buffer */ - aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); - aml_append(method, if_ctx); - - else_ctx = aml_else(); - /* Unrecognized UUID */ - aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); - aml_append(method, else_ctx); - - aml_append(method, aml_return(aml_arg(3))); - return method; -} - static void build_acpi0017(Aml *table) { Aml *dev, *scope, *method; @@ -1231,7 +1181,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); - aml_append(dev, build_q35_osc_method(!pm->pcihp_bridge_en)); + aml_append(dev, build_pci_host_bridge_osc_method(!pm->pcihp_bridge_en)); aml_append(dev, aml_pci_edsm()); aml_append(sb_scope, dev); if (mcfg_valid) { @@ -1353,7 +1303,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); /* Expander bridges do not have ACPI PCI Hot-plug enabled */ - aml_append(dev, build_q35_osc_method(true)); + aml_append(dev, build_pci_host_bridge_osc_method(true)); } else { aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); } diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index ab0187a894..8a328b580c 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -42,4 +42,6 @@ void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); void build_srat_generic_affinity_structures(GArray *table_data); +Aml *build_pci_host_bridge_osc_method(bool enable_native_pcie_hotplug); + #endif From af151d50eac24604be19d0fc3bd6492979b0f399 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:53 +0200 Subject: [PATCH 55/97] hw/pci-host/gpex-acpi: Use build_pci_host_bridge_osc_method gpex build_host_bridge_osc() and x86 originated build_pci_host_bridge_osc_method() are mostly identical. In GPEX, SUPP is set to CDW2 but is not further used. CTRL is same as Local0. So let gpex code reuse build_pci_host_bridge_osc_method() and remove build_host_bridge_osc(). Also add an imply ACPI_PCI clause along with PCI_EXPRESS_GENERIC_BRIDGE to compile hw/acpi/pci.c when its dependency is resolved (ie. CONFIG_ACPI_PCI). This is requested to link qemu-system-mips64el. The disassembled DSDT difference is given below: * Original Table Header: * Signature "DSDT" - * Length 0x00001A4F (6735) + * Length 0x00001A35 (6709) * Revision 0x02 - * Checksum 0xBF + * Checksum 0xDD * OEM ID "BOCHS " * OEM Table ID "BXPC " * OEM Revision 0x00000001 (1) @@ -1849,27 +1849,26 @@ DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) { CreateDWordField (Arg3, 0x04, CDW2) CreateDWordField (Arg3, 0x08, CDW3) - SUPP = CDW2 /* \_SB_.PCI0._OSC.CDW2 */ - CTRL = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ - CTRL &= 0x1F + Local0 = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ + Local0 &= 0x1F If ((Arg1 != One)) { CDW1 |= 0x08 } - If ((CDW3 != CTRL)) + If ((CDW3 != Local0)) { CDW1 |= 0x10 } - CDW3 = CTRL /* \_SB_.PCI0.CTRL */ - Return (Arg3) + CDW3 = Local0 } Else { CDW1 |= 0x04 - Return (Arg3) } + + Return (Arg3) } Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method Signed-off-by: Eric Auger Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-10-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-host/Kconfig | 1 + hw/pci-host/gpex-acpi.c | 62 ++++------------------------------------- 2 files changed, 6 insertions(+), 57 deletions(-) diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 35c0415242..9824fa188d 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -54,6 +54,7 @@ config PCI_EXPRESS_Q35 config PCI_EXPRESS_GENERIC_BRIDGE bool select PCI_EXPRESS + imply ACPI_PCI config PCI_EXPRESS_XILINX bool diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 44737a8d81..952a0ace19 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "hw/acpi/aml-build.h" +#include "hw/acpi/pci.h" #include "hw/pci-host/gpex.h" #include "hw/arm/virt.h" #include "hw/pci/pci_bus.h" @@ -50,61 +51,7 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq, } } -static Aml *build_host_bridge_osc(bool enable_native_pcie_hotplug) -{ - Aml *method, *UUID, *ifctx, *ifctx1, *elsectx; - method = aml_method("_OSC", 4, AML_NOTSERIALIZED); - aml_append(method, aml_name_decl("SUPP", aml_int(0))); - aml_append(method, aml_name_decl("CTRL", aml_int(0))); - aml_append(method, - aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); - - /* PCI Firmware Specification 3.0 - * 4.5.1. _OSC Interface for PCI Host Bridge Devices - * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is - * identified by the Universal Unique IDentifier (UUID) - * 33DB4D5B-1FF7-401C-9657-7441C03DD766 - */ - UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); - ifctx = aml_if(aml_equal(aml_arg(0), UUID)); - aml_append(ifctx, - aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); - aml_append(ifctx, - aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); - aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); - aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); - - /* - * Allow OS control for SHPCHotplug, PME, AER, PCIeCapability, - * and PCIeHotplug depending on enable_native_pcie_hotplug - */ - aml_append(ifctx, aml_and(aml_name("CTRL"), - aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), - aml_name("CTRL"))); - - ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); - aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), - aml_name("CDW1"))); - aml_append(ifctx, ifctx1); - - ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); - aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10), - aml_name("CDW1"))); - aml_append(ifctx, ifctx1); - - aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); - aml_append(ifctx, aml_return(aml_arg(3))); - aml_append(method, ifctx); - - elsectx = aml_else(); - aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4), - aml_name("CDW1"))); - aml_append(elsectx, aml_return(aml_arg(3))); - aml_append(method, elsectx); - return method; -} - -static Aml *build_host_bridge_dsm(void) +static Aml *build_pci_host_bridge_dsm_method(void) { Aml *method = aml_method("_DSM", 4, AML_NOTSERIALIZED); Aml *UUID, *ifctx, *ifctx1, *buf; @@ -133,8 +80,9 @@ static void acpi_dsdt_add_host_bridge_methods(Aml *dev, bool enable_native_pcie_hotplug) { /* Declare an _OSC (OS Control Handoff) method */ - aml_append(dev, build_host_bridge_osc(enable_native_pcie_hotplug)); - aml_append(dev, build_host_bridge_dsm()); + aml_append(dev, + build_pci_host_bridge_osc_method(enable_native_pcie_hotplug)); + aml_append(dev, build_pci_host_bridge_dsm_method()); } void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) From f47d6e6a8f69c8890207d3f771e079700418f7a6 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 14 Jul 2025 17:49:03 -0400 Subject: [PATCH 56/97] tests/qtest/bios-tables-test: Update DSDT blobs after GPEX _OSC change Update the reference DSDT blobs after GPEX _OSC change. The _OSC change affects the aarch64 'virt' and the x86 'microvm' machines. DSDT diff is the same for all the machines/tests: * Original Table Header: * Signature "DSDT" - * Length 0x00001A4F (6735) + * Length 0x00001A35 (6709) * Revision 0x02 - * Checksum 0xBF + * Checksum 0xDD * OEM ID "BOCHS " * OEM Table ID "BXPC " * OEM Revision 0x00000001 (1) @@ -1849,27 +1849,26 @@ DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) { CreateDWordField (Arg3, 0x04, CDW2) CreateDWordField (Arg3, 0x08, CDW3) - SUPP = CDW2 /* \_SB_.PCI0._OSC.CDW2 */ - CTRL = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ - CTRL &= 0x1F + Local0 = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ + Local0 &= 0x1F If ((Arg1 != One)) { CDW1 |= 0x08 } - If ((CDW3 != CTRL)) + If ((CDW3 != Local0)) { CDW1 |= 0x10 } - CDW3 = CTRL /* \_SB_.PCI0.CTRL */ - Return (Arg3) + CDW3 = Local0 } Else { CDW1 |= 0x04 - Return (Arg3) } + + Return (Arg3) } Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method Signed-off-by: Eric Auger Signed-off-by: Gustavo Romero Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-11-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT | Bin 5196 -> 5158 bytes .../data/acpi/aarch64/virt/DSDT.acpihmatvirt | Bin 5282 -> 5244 bytes tests/data/acpi/aarch64/virt/DSDT.memhp | Bin 6557 -> 6519 bytes tests/data/acpi/aarch64/virt/DSDT.pxb | Bin 7679 -> 7603 bytes tests/data/acpi/aarch64/virt/DSDT.topology | Bin 5398 -> 5360 bytes tests/data/acpi/loongarch64/virt/DSDT | Bin 4641 -> 4603 bytes tests/data/acpi/loongarch64/virt/DSDT.memhp | Bin 5862 -> 5824 bytes tests/data/acpi/loongarch64/virt/DSDT.numamem | Bin 4647 -> 4609 bytes .../data/acpi/loongarch64/virt/DSDT.topology | Bin 4943 -> 4905 bytes tests/data/acpi/riscv64/virt/DSDT | Bin 3576 -> 3538 bytes tests/data/acpi/x86/microvm/DSDT.pcie | Bin 3023 -> 2985 bytes tests/qtest/bios-tables-test-allowed-diff.h | 11 ----------- 12 files changed, 11 deletions(-) diff --git a/tests/data/acpi/aarch64/virt/DSDT b/tests/data/acpi/aarch64/virt/DSDT index 36d3e5d5a5e47359b6dcb3706f98b4f225677591..acab6e65febbc210158d4c39be0680bbb90250f5 100644 GIT binary patch delta 114 zcmX@3u}p)@CDC8kfX{JVpjp}Y(OkR^V=X2?C2#NTx$NL96vvg%MIJ<-! zF7RWWyjw`i#5kckflEGNfxx86nT)j{87>YGxj=Z*WM`Lf;{=G907$GL0VJ}JXS1=e GBqIPCb06IR delta 152 zcmZ3caYlp7CDL29`;K;#0k bNt0pfAi@G5;R29ikoc19g?yWNg(VpQ5Tq&5 diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt b/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt index e6154d0355f84fdcc51387b4db8f9ee63acae4e9..54c27e7d95b4956ed1b5dee0d299ccb08dc2a73e 100644 GIT binary patch delta 114 zcmZ3a`A37xCDYGxj=Z*WM`Lf;{=G907$GL0VJ}JXLF~p GBqIP%EFggZ delta 152 zcmeyPu}G84CDNm0%wtEG)?g0OQ*$bpQYW diff --git a/tests/data/acpi/aarch64/virt/DSDT.memhp b/tests/data/acpi/aarch64/virt/DSDT.memhp index 33f011d6b635035a04c0b39ce9b4e219f7ae74b7..4330bc97cba0950191c45ac833533db7a190db81 100644 GIT binary patch delta 114 zcmbPh{N0GlCDFq==X{M&B8`a&on7k%!&gatO5EAiWkM|FDX6ediaCQkd zT;Rt#dAE?3iE%=80+)Qk0)a`BGZ||^GF%)Wa)I!q$<8j}#t9HH0gzZh0!U;b&t_xc GEH(gwhaoor delta 152 zcmexvG}oBRCDi~V&gatOkmCpr4G3W1a1IIbVGwcS zjQ0v^qQ^l^!#6*Zkz@n_W$r!H delta 282 zcmdmN{ok6)CDYGxj=Z*WM`Lf;{=G907$GL0VJ}JXY*fS GNk#xh{2=83 delta 152 zcmeyMIZcbpCDha)H34$(f9`Ahlc^Aaa4& bq{%RK5Mcq3Z~;g$NPJ25LcYz{g(VpQyBaCk diff --git a/tests/data/acpi/loongarch64/virt/DSDT b/tests/data/acpi/loongarch64/virt/DSDT index f32e732b11a557ae01c7f383625d3b6f459ac9f7..b31841aec6ed296f10ea1695a67ead38f45424d5 100644 GIT binary patch delta 108 zcmZ3e@>`k9CDH>8AMDK1 zmCfMn5^lJ_gMBg=kCvYiNJ)XSOSmyeRW*pCO53&bW(hN*)H W3xI?RK#D=)OR^X8ZO-6{-~s?5GAexl diff --git a/tests/data/acpi/loongarch64/virt/DSDT.numamem b/tests/data/acpi/loongarch64/virt/DSDT.numamem index 9b462869cd4911714e7c2a22025c465afa2a7d52..07923ac39584c5a5e73c9556d251814ce10de6cc 100644 GIT binary patch delta 108 zcmZ3k(x}4a66_MfD8#_P_+lg19cCt<37cOq3vdXD_^`+O2RpNLWivRtgc~mKW1TF< zqh(^8P@TXfm#{!!(&S9WT96DE2Z&rCJZZACOSo|YL`(oAR*(P^S;(`wk7p(;0BWip A_y7O^ delta 146 zcmZovS+2t666_M9F2umVXt$B;4l|R}Bf!L(UFm(`N V0g!M3NHIu!N%lg%%^5s1Spg~IDC__L diff --git a/tests/data/acpi/loongarch64/virt/DSDT.topology b/tests/data/acpi/loongarch64/virt/DSDT.topology index 65111aa822663a907b83487cb496be38a4bdff05..6dfbb495f88b74b87849b58473e46717bc588a56 100644 GIT binary patch delta 108 zcmX@Fwo;ADCDMXEN4;WVkp$N< FT>x#oA)x>O delta 151 zcmca4{X?3|CDNm0%wvzEYgaCD#&HG5Ji`+{YxqAtd6%9`7IQ%+i(3;Or7^ zxWJEf@*XZN6XS&H1TMLR1p<>MXEN4;WVkp$pn4BhW?qd?*kmCpr4G3W1a1IIbVGwcS zjQ0|Z0pAkq&fwN1vF-TQ4h~Sb3kqZPSP0nPj1*zrY0FevC bCQXK^g9r Date: Mon, 14 Jul 2025 10:04:55 +0200 Subject: [PATCH 57/97] hw/i386/acpi-build: Introduce build_append_pcihp_resources() helper Extract the code that reserves resources for ACPI PCI hotplug into a new helper named build_append_pcihp_resources() and move it to pcihp.c. We will reuse it on ARM. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-12-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 18 ++++++++++++++++++ hw/i386/acpi-build.c | 15 ++------------- include/hw/acpi/pcihp.h | 2 ++ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index cbe7e01385..5ca36c8619 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -685,6 +685,24 @@ void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) aml_append(table, scope); } +/* Reserve PCIHP resources */ +void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */, + uint64_t io_addr, uint64_t io_len) +{ + Aml *dev, *crs; + + dev = aml_device("PHPR"); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); + aml_append(dev, + aml_name_decl("_UID", aml_string("PCI Hotplug resources"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, io_addr, io_addr, 1, io_len)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + const VMStateDescription vmstate_acpi_pcihp_pci_status = { .name = "acpi_pcihp_pci_status", .version_id = 1, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 91945f716c..52cef834ed 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1432,19 +1432,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* reserve PCIHP resources */ if (pm->pcihp_io_len && (pm->pcihp_bridge_en || pm->pcihp_root_en)) { - dev = aml_device("PHPR"); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); - aml_append(dev, - aml_name_decl("_UID", aml_string("PCI Hotplug resources"))); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1, - pm->pcihp_io_len) - ); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); + build_append_pcihp_resources(scope, + pm->pcihp_io_base, pm->pcihp_io_len); } aml_append(dsdt, scope); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 971451e8ea..8a46a414cc 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -75,6 +75,8 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr); void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar); +void build_append_pcihp_resources(Aml *table, + uint64_t io_addr, uint64_t io_len); /* Called on reset */ void acpi_pcihp_reset(AcpiPciHpState *s); From b412e0557c03b9aac946133a443a76aa86c3f8b4 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:56 +0200 Subject: [PATCH 58/97] hw/acpi/pcihp: Add an AmlRegionSpace arg to build_acpi_pci_hotplug On ARM we will put the operation regions in AML_SYSTEM_MEMORY. So let's allow this configuration. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-13-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 8 ++++---- hw/i386/acpi-build.c | 4 ++-- include/hw/acpi/pcihp.h | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 5ca36c8619..afa3ec5f4d 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -629,7 +629,7 @@ static Aml *aml_pci_pdsm(void) return method; } -void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) +void build_acpi_pci_hotplug(Aml *table, AmlRegionSpace rs, uint64_t pcihp_addr) { Aml *scope; Aml *field; @@ -638,21 +638,21 @@ void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) scope = aml_scope("_SB.PCI0"); aml_append(scope, - aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(pcihp_addr), 0x08)); + aml_operation_region("PCST", rs, aml_int(pcihp_addr), 0x08)); field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("PCIU", 32)); aml_append(field, aml_named_field("PCID", 32)); aml_append(scope, field); aml_append(scope, - aml_operation_region("SEJ", AML_SYSTEM_IO, + aml_operation_region("SEJ", rs, aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04)); field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("B0EJ", 32)); aml_append(scope, field); aml_append(scope, - aml_operation_region("BNMR", AML_SYSTEM_IO, + aml_operation_region("BNMR", rs, aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08)); field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_named_field("BNUM", 32)); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 52cef834ed..6ca2b34ef8 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1172,7 +1172,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { - build_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); + build_acpi_pci_hotplug(dsdt, AML_SYSTEM_IO, pm->pcihp_io_base); } build_piix4_pci0_int(dsdt); } else if (q35) { @@ -1216,7 +1216,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en) { - build_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); + build_acpi_pci_hotplug(dsdt, AML_SYSTEM_IO, pm->pcihp_io_base); } build_q35_pci0_int(dsdt); } diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 8a46a414cc..253ac6e483 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -28,6 +28,7 @@ #define HW_ACPI_PCIHP_H #include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" #include "hw/hotplug.h" #define ACPI_PCIHP_IO_BASE_PROP "acpi-pcihp-io-base" @@ -73,7 +74,7 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp); -void build_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr); +void build_acpi_pci_hotplug(Aml *table, AmlRegionSpace rs, uint64_t pcihp_addr); void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar); void build_append_pcihp_resources(Aml *table, uint64_t io_addr, uint64_t io_len); From d962f199c7e8625c91e8d1cc54a0323180e6f3e1 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:57 +0200 Subject: [PATCH 59/97] hw/i386/acpi-build: Move build_append_notification_callback to pcihp We plan to reuse build_append_notification_callback() on ARM so let's move it to pcihp.c. No functional change intended. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-14-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 58 +++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 58 ----------------------------------------- include/hw/acpi/pcihp.h | 1 + 3 files changed, 59 insertions(+), 58 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index afa3ec5f4d..b64d06afc9 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -39,6 +39,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qom/qom-qobject.h" +#include "qobject/qnum.h" #include "trace.h" #define ACPI_PCIHP_SIZE 0x0018 @@ -703,6 +704,63 @@ void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */, aml_append(scope, dev); } +bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus) +{ + Aml *method; + PCIBus *sec; + QObject *bsel; + int nr_notifiers = 0; + GQueue *pcnt_bus_list = g_queue_new(); + + QLIST_FOREACH(sec, &bus->child, sibling) { + Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); + if (pci_bus_is_root(sec)) { + continue; + } + nr_notifiers = nr_notifiers + + build_append_notification_callback(br_scope, sec); + /* + * add new child scope to parent + * and keep track of bus that have PCNT, + * bus list is used later to call children PCNTs from this level PCNT + */ + if (nr_notifiers) { + g_queue_push_tail(pcnt_bus_list, sec); + aml_append(parent_scope, br_scope); + } + } + + /* + * Append PCNT method to notify about events on local and child buses. + * ps: hostbridge might not have hotplug (bsel) enabled but might have + * child bridges that do have bsel. + */ + method = aml_method("PCNT", 0, AML_NOTSERIALIZED); + + /* If bus supports hotplug select it and notify about local events */ + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); + if (bsel) { + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + + aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); + aml_append(method, aml_call2("DVNT", aml_name("PCIU"), + aml_int(1))); /* Device Check */ + aml_append(method, aml_call2("DVNT", aml_name("PCID"), + aml_int(3))); /* Eject Request */ + nr_notifiers++; + } + + /* Notify about child bus events in any case */ + while ((sec = g_queue_pop_head(pcnt_bus_list))) { + aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn)); + } + + aml_append(parent_scope, method); + qobject_unref(bsel); + g_queue_free(pcnt_bus_list); + return !!nr_notifiers; +} + const VMStateDescription vmstate_acpi_pcihp_pci_status = { .name = "acpi_pcihp_pci_status", .version_id = 1, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6ca2b34ef8..3275675e60 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -563,64 +563,6 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) } } -static bool build_append_notification_callback(Aml *parent_scope, - const PCIBus *bus) -{ - Aml *method; - PCIBus *sec; - QObject *bsel; - int nr_notifiers = 0; - GQueue *pcnt_bus_list = g_queue_new(); - - QLIST_FOREACH(sec, &bus->child, sibling) { - Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); - if (pci_bus_is_root(sec)) { - continue; - } - nr_notifiers = nr_notifiers + - build_append_notification_callback(br_scope, sec); - /* - * add new child scope to parent - * and keep track of bus that have PCNT, - * bus list is used later to call children PCNTs from this level PCNT - */ - if (nr_notifiers) { - g_queue_push_tail(pcnt_bus_list, sec); - aml_append(parent_scope, br_scope); - } - } - - /* - * Append PCNT method to notify about events on local and child buses. - * ps: hostbridge might not have hotplug (bsel) enabled but might have - * child bridges that do have bsel. - */ - method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - - /* If bus supports hotplug select it and notify about local events */ - bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - - aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); - aml_append(method, aml_call2("DVNT", aml_name("PCIU"), - aml_int(1))); /* Device Check */ - aml_append(method, aml_call2("DVNT", aml_name("PCID"), - aml_int(3))); /* Eject Request */ - nr_notifiers++; - } - - /* Notify about child bus events in any case */ - while ((sec = g_queue_pop_head(pcnt_bus_list))) { - aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn)); - } - - aml_append(parent_scope, method); - qobject_unref(bsel); - g_queue_free(pcnt_bus_list); - return !!nr_notifiers; -} - /* * build_prt - Define interrupt routing rules * diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 253ac6e483..f4fd44cb32 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -78,6 +78,7 @@ void build_acpi_pci_hotplug(Aml *table, AmlRegionSpace rs, uint64_t pcihp_addr); void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar); void build_append_pcihp_resources(Aml *table, uint64_t io_addr, uint64_t io_len); +bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus); /* Called on reset */ void acpi_pcihp_reset(AcpiPciHpState *s); From e87ab64e8f614ae8702209dd801ac08ca5897ff1 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:58 +0200 Subject: [PATCH 60/97] hw/i386/acpi-build: Move build_append_pci_bus_devices/pcihp_slots to pcihp We intend to reuse build_append_pci_bus_devices and build_append_pcihp_slots on ARM. So let's move them to hw/acpi/pcihp.c as well as all static helpers they use. No functional change intended. Signed-off-by: Eric Auger Reviewed-by: Gustavo Romero Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-15-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 173 ++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 172 --------------------------------------- include/hw/acpi/pci.h | 1 - include/hw/acpi/pcihp.h | 2 + 4 files changed, 175 insertions(+), 173 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index b64d06afc9..2c76edeb15 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "hw/acpi/pcihp.h" #include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/pci-host/i440fx.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" @@ -761,6 +762,178 @@ bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus) return !!nr_notifiers; } +static Aml *aml_pci_device_dsm(void) +{ + Aml *method; + + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + Aml *params = aml_local(0); + Aml *pkg = aml_package(2); + aml_append(pkg, aml_int(0)); + aml_append(pkg, aml_int(0)); + aml_append(method, aml_store(pkg, params)); + aml_append(method, + aml_store(aml_name("BSEL"), aml_index(params, aml_int(0)))); + aml_append(method, + aml_store(aml_name("ASUN"), aml_index(params, aml_int(1)))); + aml_append(method, + aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1), + aml_arg(2), aml_arg(3), params)) + ); + } + return method; +} + +static Aml *aml_pci_static_endpoint_dsm(PCIDevice *pdev) +{ + Aml *method; + + g_assert(pdev->acpi_index != 0); + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + Aml *params = aml_local(0); + Aml *pkg = aml_package(1); + aml_append(pkg, aml_int(pdev->acpi_index)); + aml_append(method, aml_store(pkg, params)); + aml_append(method, + aml_return(aml_call5("EDSM", aml_arg(0), aml_arg(1), + aml_arg(2), aml_arg(3), params)) + ); + } + return method; +} + +static void build_append_pcihp_notify_entry(Aml *method, int slot) +{ + Aml *if_ctx; + int32_t devfn = PCI_DEVFN(slot, 0); + + if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL)); + aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1))); + aml_append(method, if_ctx); +} + +static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) +{ + const PCIDevice *pdev = bus->devices[devfn]; + + if (PCI_FUNC(devfn)) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { + return true; + } + } + } + return false; +} + +static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) +{ + PCIDevice *pdev = bus->devices[devfn]; + if (pdev) { + return is_devfn_ignored_generic(devfn, bus) || + !DEVICE_GET_CLASS(pdev)->hotpluggable || + /* Cold plugged bridges aren't themselves hot-pluggable */ + (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); + } else { /* non populated slots */ + /* + * hotplug is supported only for non-multifunction device + * so generate device description only for function 0 + */ + if (PCI_FUNC(devfn) || + (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { + return true; + } + } + return false; +} + +void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus) +{ + int devfn; + Aml *dev, *notify_method = NULL, *method; + QObject *bsel = object_property_get_qobject(OBJECT(bus), + ACPI_PCIHP_PROP_BSEL, NULL); + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + qobject_unref(bsel); + + aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); + notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + int slot = PCI_SLOT(devfn); + int adr = slot << 16 | PCI_FUNC(devfn); + + if (is_devfn_ignored_hotplug(devfn, bus)) { + continue; + } + + if (bus->devices[devfn]) { + dev = aml_scope("S%.02X", devfn); + } else { + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + } + + /* + * Can't declare _SUN here for every device as it changes 'slot' + * enumeration order in linux kernel, so use another variable for it + */ + aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); + aml_append(dev, aml_pci_device_dsm()); + + aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); + /* add _EJ0 to make slot hotpluggable */ + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) + ); + aml_append(dev, method); + + build_append_pcihp_notify_entry(notify_method, slot); + + /* device descriptor has been composed, add it into parent context */ + aml_append(parent_scope, dev); + } + aml_append(parent_scope, notify_method); +} + +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) +{ + int devfn; + Aml *dev; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ + int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); + PCIDevice *pdev = bus->devices[devfn]; + + if (!pdev || is_devfn_ignored_generic(devfn, bus)) { + continue; + } + + /* start to compose PCI device descriptor */ + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + + call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); + /* add _DSM if device has acpi-index set */ + if (pdev->acpi_index && + !object_property_get_bool(OBJECT(pdev), "hotpluggable", + &error_abort)) { + aml_append(dev, aml_pci_static_endpoint_dsm(pdev)); + } + + /* device descriptor has been composed, add it into parent context */ + aml_append(parent_scope, dev); + } +} + const VMStateDescription vmstate_acpi_pcihp_pci_status = { .name = "acpi_pcihp_pci_status", .version_id = 1, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 3275675e60..fe8bc62c03 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -338,29 +338,6 @@ build_facs(GArray *table_data) g_array_append_vals(table_data, reserved, 40); /* Reserved */ } -static Aml *aml_pci_device_dsm(void) -{ - Aml *method; - - method = aml_method("_DSM", 4, AML_SERIALIZED); - { - Aml *params = aml_local(0); - Aml *pkg = aml_package(2); - aml_append(pkg, aml_int(0)); - aml_append(pkg, aml_int(0)); - aml_append(method, aml_store(pkg, params)); - aml_append(method, - aml_store(aml_name("BSEL"), aml_index(params, aml_int(0)))); - aml_append(method, - aml_store(aml_name("ASUN"), aml_index(params, aml_int(1)))); - aml_append(method, - aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1), - aml_arg(2), aml_arg(3), params)) - ); - } - return method; -} - static Aml *aml_pci_edsm(void) { Aml *method, *ifctx; @@ -414,155 +391,6 @@ static Aml *aml_pci_edsm(void) return method; } -static Aml *aml_pci_static_endpoint_dsm(PCIDevice *pdev) -{ - Aml *method; - - g_assert(pdev->acpi_index != 0); - method = aml_method("_DSM", 4, AML_SERIALIZED); - { - Aml *params = aml_local(0); - Aml *pkg = aml_package(1); - aml_append(pkg, aml_int(pdev->acpi_index)); - aml_append(method, aml_store(pkg, params)); - aml_append(method, - aml_return(aml_call5("EDSM", aml_arg(0), aml_arg(1), - aml_arg(2), aml_arg(3), params)) - ); - } - return method; -} - -static void build_append_pcihp_notify_entry(Aml *method, int slot) -{ - Aml *if_ctx; - int32_t devfn = PCI_DEVFN(slot, 0); - - if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL)); - aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1))); - aml_append(method, if_ctx); -} - -static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) -{ - const PCIDevice *pdev = bus->devices[devfn]; - - if (PCI_FUNC(devfn)) { - if (IS_PCI_BRIDGE(pdev)) { - /* - * Ignore only hotplugged PCI bridges on !0 functions, but - * allow describing cold plugged bridges on all functions - */ - if (DEVICE(pdev)->hotplugged) { - return true; - } - } - } - return false; -} - -static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) -{ - PCIDevice *pdev = bus->devices[devfn]; - if (pdev) { - return is_devfn_ignored_generic(devfn, bus) || - !DEVICE_GET_CLASS(pdev)->hotpluggable || - /* Cold plugged bridges aren't themselves hot-pluggable */ - (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); - } else { /* non populated slots */ - /* - * hotplug is supported only for non-multifunction device - * so generate device description only for function 0 - */ - if (PCI_FUNC(devfn) || - (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { - return true; - } - } - return false; -} - -void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus) -{ - int devfn; - Aml *dev, *notify_method = NULL, *method; - QObject *bsel = object_property_get_qobject(OBJECT(bus), - ACPI_PCIHP_PROP_BSEL, NULL); - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - qobject_unref(bsel); - - aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); - notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); - - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - int slot = PCI_SLOT(devfn); - int adr = slot << 16 | PCI_FUNC(devfn); - - if (is_devfn_ignored_hotplug(devfn, bus)) { - continue; - } - - if (bus->devices[devfn]) { - dev = aml_scope("S%.02X", devfn); - } else { - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); - } - - /* - * Can't declare _SUN here for every device as it changes 'slot' - * enumeration order in linux kernel, so use another variable for it - */ - aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); - aml_append(dev, aml_pci_device_dsm()); - - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - /* add _EJ0 to make slot hotpluggable */ - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); - - build_append_pcihp_notify_entry(notify_method, slot); - - /* device descriptor has been composed, add it into parent context */ - aml_append(parent_scope, dev); - } - aml_append(parent_scope, notify_method); -} - -void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) -{ - int devfn; - Aml *dev; - - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ - int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); - PCIDevice *pdev = bus->devices[devfn]; - - if (!pdev || is_devfn_ignored_generic(devfn, bus)) { - continue; - } - - /* start to compose PCI device descriptor */ - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); - - call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); - /* add _DSM if device has acpi-index set */ - if (pdev->acpi_index && - !object_property_get_bool(OBJECT(pdev), "hotpluggable", - &error_abort)) { - aml_append(dev, aml_pci_static_endpoint_dsm(pdev)); - } - - /* device descriptor has been composed, add it into parent context */ - aml_append(parent_scope, dev); - } -} - /* * build_prt - Define interrupt routing rules * diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index 8a328b580c..69bae95eac 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -37,7 +37,6 @@ typedef struct AcpiMcfgInfo { void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, const char *oem_id, const char *oem_table_id); -void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); void build_srat_generic_affinity_structures(GArray *table_data); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index f4fd44cb32..5506a58862 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -80,6 +80,8 @@ void build_append_pcihp_resources(Aml *table, uint64_t io_addr, uint64_t io_len); bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus); +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); + /* Called on reset */ void acpi_pcihp_reset(AcpiPciHpState *s); From b9dc4e04c807ad3860a9ba8773b3b0e7057c31aa Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:04:59 +0200 Subject: [PATCH 61/97] hw/i386/acpi-build: Use AcpiPciHpState::root in acpi_set_pci_info pcihp acpi_set_pci_info() generic code currently uses acpi_get_i386_pci_host() to retrieve the pci host bridge. To make it work also on ARM we get rid of that call and directly use AcpiPciHpState::root. Signed-off-by: Eric Auger Suggested-by: Igor Mammedov Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-16-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 2c76edeb15..2db2f16940 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -99,10 +99,10 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque) return info; } -static void acpi_set_pci_info(bool has_bridge_hotplug) +static void acpi_set_pci_info(AcpiPciHpState *s) { static bool bsel_is_set; - Object *host = acpi_get_i386_pci_host(); + bool has_bridge_hotplug = s->use_acpi_hotplug_bridge; PCIBus *bus; BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT, .has_bridge_hotplug = has_bridge_hotplug }; @@ -112,11 +112,8 @@ static void acpi_set_pci_info(bool has_bridge_hotplug) } bsel_is_set = true; - if (!host) { - return; - } - bus = PCI_HOST_BRIDGE(host)->bus; + bus = s->root; if (bus) { /* Scan all PCI buses. Set property to enable acpi based hotplug. */ pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info); @@ -266,7 +263,7 @@ static void acpi_pcihp_update(AcpiPciHpState *s) void acpi_pcihp_reset(AcpiPciHpState *s) { - acpi_set_pci_info(s->use_acpi_hotplug_bridge); + acpi_set_pci_info(s); acpi_pcihp_update(s); } From bc8f29df27e68b0476360526634097608171e783 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:00 +0200 Subject: [PATCH 62/97] hw/i386/acpi-build: Move aml_pci_edsm to a generic place Move aml_pci_edsm to pci-bridge.c since we want to reuse that for ARM and acpi-index support. Also rename it into build_pci_bridge_edsm. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-17-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pci-bridge.c | 54 ++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 57 ++----------------------------------------- include/hw/acpi/pci.h | 1 + 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c index 7baa7034a1..394a919479 100644 --- a/hw/acpi/pci-bridge.c +++ b/hw/acpi/pci-bridge.c @@ -35,3 +35,57 @@ void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope) } } } + +Aml *build_pci_bridge_edsm(void) +{ + Aml *method, *ifctx; + Aml *zero = aml_int(0); + Aml *func = aml_arg(2); + Aml *ret = aml_local(0); + Aml *aidx = aml_local(1); + Aml *params = aml_arg(4); + + method = aml_method("EDSM", 5, AML_SERIALIZED); + + /* get supported functions */ + ifctx = aml_if(aml_equal(func, zero)); + { + /* 1: have supported functions */ + /* 7: support for function 7 */ + const uint8_t caps = 1 | BIT(7); + build_append_pci_dsm_func0_common(ifctx, ret); + aml_append(ifctx, aml_store(aml_int(caps), aml_index(ret, zero))); + aml_append(ifctx, aml_return(ret)); + } + aml_append(method, ifctx); + + /* handle specific functions requests */ + /* + * PCI Firmware Specification 3.1 + * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under + * Operating Systems + */ + ifctx = aml_if(aml_equal(func, aml_int(7))); + { + Aml *pkg = aml_package(2); + aml_append(pkg, zero); + /* optional, if not impl. should return null string */ + aml_append(pkg, aml_string("%s", "")); + aml_append(ifctx, aml_store(pkg, ret)); + + /* + * IASL is fine when initializing Package with computational data, + * however it makes guest unhappy /it fails to process such AML/. + * So use runtime assignment to set acpi-index after initializer + * to make OSPM happy. + */ + aml_append(ifctx, + aml_store(aml_derefof(aml_index(params, aml_int(0))), aidx)); + aml_append(ifctx, aml_store(aidx, aml_index(ret, zero))); + aml_append(ifctx, aml_return(ret)); + } + aml_append(method, ifctx); + + return method; +} + diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index fe8bc62c03..423c4959fe 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -338,59 +338,6 @@ build_facs(GArray *table_data) g_array_append_vals(table_data, reserved, 40); /* Reserved */ } -static Aml *aml_pci_edsm(void) -{ - Aml *method, *ifctx; - Aml *zero = aml_int(0); - Aml *func = aml_arg(2); - Aml *ret = aml_local(0); - Aml *aidx = aml_local(1); - Aml *params = aml_arg(4); - - method = aml_method("EDSM", 5, AML_SERIALIZED); - - /* get supported functions */ - ifctx = aml_if(aml_equal(func, zero)); - { - /* 1: have supported functions */ - /* 7: support for function 7 */ - const uint8_t caps = 1 | BIT(7); - build_append_pci_dsm_func0_common(ifctx, ret); - aml_append(ifctx, aml_store(aml_int(caps), aml_index(ret, zero))); - aml_append(ifctx, aml_return(ret)); - } - aml_append(method, ifctx); - - /* handle specific functions requests */ - /* - * PCI Firmware Specification 3.1 - * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under - * Operating Systems - */ - ifctx = aml_if(aml_equal(func, aml_int(7))); - { - Aml *pkg = aml_package(2); - aml_append(pkg, zero); - /* optional, if not impl. should return null string */ - aml_append(pkg, aml_string("%s", "")); - aml_append(ifctx, aml_store(pkg, ret)); - - /* - * IASL is fine when initializing Package with computational data, - * however it makes guest unhappy /it fails to process such AML/. - * So use runtime assignment to set acpi-index after initializer - * to make OSPM happy. - */ - aml_append(ifctx, - aml_store(aml_derefof(aml_index(params, aml_int(0))), aidx)); - aml_append(ifctx, aml_store(aidx, aml_index(ret, zero))); - aml_append(ifctx, aml_return(ret)); - } - aml_append(method, ifctx); - - return method; -} - /* * build_prt - Define interrupt routing rules * @@ -937,7 +884,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, dev = aml_device("PCI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); - aml_append(dev, aml_pci_edsm()); + aml_append(dev, build_pci_bridge_edsm()); aml_append(sb_scope, dev); aml_append(dsdt, sb_scope); @@ -952,7 +899,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); aml_append(dev, build_pci_host_bridge_osc_method(!pm->pcihp_bridge_en)); - aml_append(dev, aml_pci_edsm()); + aml_append(dev, build_pci_bridge_edsm()); aml_append(sb_scope, dev); if (mcfg_valid) { aml_append(sb_scope, build_q35_dram_controller(&mcfg)); diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index 69bae95eac..20b672575f 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -42,5 +42,6 @@ void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); void build_srat_generic_affinity_structures(GArray *table_data); Aml *build_pci_host_bridge_osc_method(bool enable_native_pcie_hotplug); +Aml *build_pci_bridge_edsm(void); #endif From c82a9d740758644493bbb32711237c41070babb8 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:01 +0200 Subject: [PATCH 63/97] qtest/bios-tables-test: Prepare for fixing the aarch64 viot test The test misses a variant and this puts the mess on subsequent rebuild-expected-aml.sh where a first DSDT reference blob is overriden by another one. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-18-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT.viot | 0 tests/qtest/bios-tables-test-allowed-diff.h | 1 + 2 files changed, 1 insertion(+) create mode 100644 tests/data/acpi/aarch64/virt/DSDT.viot diff --git a/tests/data/acpi/aarch64/virt/DSDT.viot b/tests/data/acpi/aarch64/virt/DSDT.viot new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..7a74beab3d 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,2 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/aarch64/virt/DSDT.viot", From 070c0892d528d66651cb2f3cc6a63eaa13c01ddf Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:02 +0200 Subject: [PATCH 64/97] qtest/bios-tables-test: Add a variant to the aarch64 viot test Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-19-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e988deac02..4701975c05 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -2275,6 +2275,7 @@ static void test_acpi_aarch64_virt_viot(void) test_data data = { .machine = "virt", .arch = "aarch64", + .variant = ".viot", .tcg_only = true, .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", From c34115091fab11342370c7af51589ba24d5cece9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:03 +0200 Subject: [PATCH 65/97] qtest/bios-tables-test: Generate DSDT.viot Use a specific DSDT.viot reference blob instead of relying on the default DSDT blob. The content is unchanged. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-20-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT.viot | Bin 0 -> 5158 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/aarch64/virt/DSDT.viot b/tests/data/acpi/aarch64/virt/DSDT.viot index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..acab6e65febbc210158d4c39be0680bbb90250f5 100644 GIT binary patch literal 5158 zcmZ<>b_r1vVPIf7fyp59qWFRMl z00ToO8v`SwA_D_MB|~(Rg zAXgY+GlGi=*#j_VuppUXglvW}Rx_BfnZbr+hB2}kCRoj2!Da>rk{Kq*W|(3%gB6<@ zTu5e^BAa1`)eJUlX7C`HVTNpmIaV{+v6;b#WQIAi85UU0;J{{v0FoIN$Yxk#HG>nI z8A3>ASR$EW2+bU*NsNmNn;9ZVW>_Jcfi;<;W)fH$6GJk?8rcl&>68bXJ0y_Iut7Eh zdphOCW`-1!8Meq~U{9xf*vybYGQ$qp4D9KYADbC+NM_h0n}I!@3Scus0m%#pWHYd* zQ$cKIC?T2Qh-?P-bSi|+3>73ZoRH1Ho=%0anW2VchBJ~GM%dG-2sSe`kj!vFHUoP) z6~$(T7LpmR$Yx+qr()R5&_Oc84cQFr=~Nt>8G1-&xFef^J)KHmGs6JM3=d>8u%}Z= zY-SiCnc<0S2KIC+h0P2TBs08_&A^^crLmb|hGd2}vKiRZsSGwVERf9bK{f+>I+ev{ zh82<-zDQ;mV^61Y*vzm&GQ$tq4D9Jt9-A3j~nVKECLhA?YVfU_qw)<9-C8dxxJ#5;Ss@IrXTpf;bY zI|E0&lan7j9D_rG1m(G80vMbbJQ-3M6c`K`6c}6>QW?q^G8vK?QW+RPhJc%C0YM?c zKE+%OLfkCe|Nk?9;)VgjX7n*IFk}$o0f}=l`GDG&P!6+?fq^lD5HAbQ|No2(AU%d~ z9!QrFgAgA?4y?}@!3F6wfU0Ez>okJ%KssScnHa!24WK%i7`Q+>VYV=Xb;4Z0%mC5} zQ_2j{X$aNH4ABX*g$1k=<^mS5PMA^_h)$T}Ss*%Lwy=VA!d$=#)(KO}3egF3JS#*e z%oaAVPM8bWz&c?{*&sS$j%S1DgxSIl)(LX~J6I=7DLX_b%<=3HoiJNCz&c?r-~j7{ zDdm9ZggKrAq7!BdCs-%U1)N}=Fr}OjoiN99LUh7x;R5S~xqu6-6Q-04q7&wLE{IN; zE!<$8Fc)xxb;6W#Lv+F%&kfNDvxNt&6XpUQuuhm#9*9nu<9Q%DVYcvsb;4Z03)Tr! z$_vp6b389ZC(IT;uuhl@_`o`0O8Fo5S=i`3qo|lY!L$MgtRm@UF!oiG;&gLT4`3PW_l94`#f3A056tP|z}5wK2}QW1zwnBzqtI$^em zf_1`NAPUwAQz{D433I$CL?_G^F|baU3&g-WVM@gyI$@3%gXo0WA`aFGbAdQmCrqh0 zL?_Jg;t-uMTO`0bVJ?sW>x3zlfarudUIL;MW{V_PC(H$sV4X0fk`SFR$4f$V!fcTO z>x8*L3ak^RR0^UK=6ETHPM9syV4W}*NP~64luAQ%!W=IR(FwCf2CNh20vWJQm{J*t zPMG6mAUa{T$bxmkTp$b92~#Qy(Ft?BEJP>F7CEp^m|36T-jDdmSzh1jI10xSJNEn3wgO&fcV_;xp=+Z{g1CnHD0O|Pu zAEF2>0wF-+l?)<2?D77=&MaNo49+g$h70^yCuax>a|uNI-ZuU&FXJ#Ryu|Th0gy~V0!U;b z4@3xLl;M(W5#4x~U|*I6iV!<5n4f$aY+B_zQT&y!GrzUmg_75I=)S0T2lq5p!aX(F2XSxx2c=L&hE; z18#<(MpCG!3$MGY3#i=#Z)7qvYJyu}(G9LauI>yx3=ABcTrAOz+#s&AYp|=2f{1Lq rYgh{ZKwxrp0vD)l(iRXN Date: Mon, 14 Jul 2025 10:05:04 +0200 Subject: [PATCH 66/97] tests/qtest/bios-tables-test: Prepare for changes in the arm virt DSDT table This commit adds DSDT blobs to the whilelist in the prospect to allow changes in the arm virt DSDT method. Signed-off-by: Gustavo Romero Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-21-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..023fbc6059 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,7 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/aarch64/virt/DSDT", +"tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt", +"tests/data/acpi/aarch64/virt/DSDT.memhp", +"tests/data/acpi/aarch64/virt/DSDT.pxb", +"tests/data/acpi/aarch64/virt/DSDT.topology", +"tests/data/acpi/aarch64/virt/DSDT.viot", From ff692ee7bcb506d318c7a279abf570b1f220a3da Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:05 +0200 Subject: [PATCH 67/97] hw/arm/virt-acpi-build: Let non hotplug ports support static acpi-index hw/arm/virt-acpi-build: Let non hotplug ports support static acpi-index Add the requested ACPI bits requested to support static acpi-index for non hotplug ports. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-22-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/Kconfig | 2 ++ hw/arm/virt-acpi-build.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 1634e26fcc..2aa4b5d778 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -34,6 +34,8 @@ config ARM_VIRT select ACPI_HW_REDUCED select ACPI_APEI select ACPI_VIOT + select ACPI_PCIHP + select ACPI_PCI_BRIDGE select VIRTIO_MEM_SUPPORTED select ACPI_CXL select ACPI_HMAT diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f3bad69aa7..3dc1cfcd67 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -34,6 +34,7 @@ #include "hw/core/cpu.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/pcihp.h" #include "hw/nvram/fw_cfg_acpi.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/aml-build.h" @@ -906,6 +907,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) const int *irqmap = vms->irqmap; AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; + Aml *pci0_scope; acpi_table_begin(&table, table_data); dsdt = init_aml_allocator(); @@ -959,6 +961,16 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) aml_append(dsdt, scope); + pci0_scope = aml_scope("\\_SB.PCI0"); + + aml_append(pci0_scope, build_pci_bridge_edsm()); + build_append_pci_bus_devices(pci0_scope, vms->bus); + if (object_property_find(OBJECT(vms->bus), ACPI_PCIHP_PROP_BSEL)) { + build_append_pcihp_slots(pci0_scope, vms->bus); + } + + aml_append(dsdt, pci0_scope); + /* copy AML table into ACPI tables blob */ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); From 4dfb1418278a43f3acbf177dfcafe955da8ffaf6 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:06 +0200 Subject: [PATCH 68/97] tests/qtest/bios-tables-test: Update ARM DSDT reference blobs Changes relate to the introduction of pieces related to acpi-index static support along with root ports with no hotplug. + + Scope (\_SB.PCI0) + { + Method (EDSM, 5, Serialized) + { + If ((Arg2 == Zero)) + { + Local0 = Buffer (One) + { + 0x00 // . + } + If ((Arg0 != ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) + { + Return (Local0) + } + + If ((Arg1 < 0x02)) + { + Return (Local0) + } + + Local0 [Zero] = 0x81 + Return (Local0) + } + + If ((Arg2 == 0x07)) + { + Local0 = Package (0x02) + { + Zero, + "" + } + Local1 = DerefOf (Arg4 [Zero]) + Local0 [Zero] = Local1 + Return (Local0) + } + } + + Device (S00) + { + Name (_ADR, Zero) // _ADR: Address + } + + Device (S08) + { + Name (_ADR, 0x00010000) // _ADR: Address + } + + Device (S10) + { + Name (_ADR, 0x00020000) // _ADR: Address + } + } } Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-23-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT | Bin 5158 -> 5293 bytes .../data/acpi/aarch64/virt/DSDT.acpihmatvirt | Bin 5244 -> 5379 bytes tests/data/acpi/aarch64/virt/DSDT.memhp | Bin 6519 -> 6654 bytes tests/data/acpi/aarch64/virt/DSDT.pxb | Bin 7603 -> 7768 bytes tests/data/acpi/aarch64/virt/DSDT.topology | Bin 5360 -> 5495 bytes tests/data/acpi/aarch64/virt/DSDT.viot | Bin 5158 -> 5310 bytes tests/qtest/bios-tables-test-allowed-diff.h | 6 ------ 7 files changed, 6 deletions(-) diff --git a/tests/data/acpi/aarch64/virt/DSDT b/tests/data/acpi/aarch64/virt/DSDT index acab6e65febbc210158d4c39be0680bbb90250f5..18d97e8f22979411a528705c0e314acb424bbfa5 100644 GIT binary patch delta 156 zcmZ3cu~w7ICDM6Gl delta 19 acmZ3hxlDu0CDC8qh84&E4EZYD8 delta 19 acmexo{N0GlCDFq|YTuA^&WCm0K diff --git a/tests/data/acpi/aarch64/virt/DSDT.pxb b/tests/data/acpi/aarch64/virt/DSDT.pxb index 7fdbc03e2bf9fb7d35704779253de36e362f0bf9..c2779882494e16920787b8ab7b4cb3c3b70f224b 100644 GIT binary patch delta 168 zcmdmNeZz*!CD2+L6)WZd delta 19 acmca%v)P)HJ2nXCn0iZX7Xs@xe~<0nVNVBHpa7F2TOM3(O{GF%$?g zGcqJBkeW0(Lr|DY;DY(dr@^LGz7xe?`AQyk_Fa;&fPHEv7t@l20M6GC8qh84& Date: Mon, 14 Jul 2025 10:05:07 +0200 Subject: [PATCH 69/97] hw/arm/virt-acpi-build: Modify the DSDT ACPI table to enable ACPI PCI hotplug Modify the DSDT ACPI table to enable ACPI PCI hotplug. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-24-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 1 - hw/arm/virt-acpi-build.c | 17 +++++++++++++++++ hw/arm/virt.c | 2 ++ include/hw/acpi/pcihp.h | 2 ++ include/hw/arm/virt.h | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 2db2f16940..f1594e664a 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -43,7 +43,6 @@ #include "qobject/qnum.h" #include "trace.h" -#define ACPI_PCIHP_SIZE 0x0018 #define PCI_UP_BASE 0x0000 #define PCI_DOWN_BASE 0x0004 #define PCI_EJ_BASE 0x0008 diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3dc1cfcd67..b01fc4f8ef 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -969,6 +969,23 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_pcihp_slots(pci0_scope, vms->bus); } + if (vms->acpi_dev) { + bool acpi_pcihp; + + acpi_pcihp = object_property_get_bool(OBJECT(vms->acpi_dev), + ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, + NULL); + + if (acpi_pcihp) { + build_acpi_pci_hotplug(dsdt, AML_SYSTEM_MEMORY, + memmap[VIRT_ACPI_PCIHP].base); + build_append_pcihp_resources(pci0_scope, + memmap[VIRT_ACPI_PCIHP].base, + memmap[VIRT_ACPI_PCIHP].size); + + build_append_notification_callback(pci0_scope, vms->bus); + } + } aml_append(dsdt, pci0_scope); /* copy AML table into ACPI tables blob */ diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8070ff7b11..817adedb31 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -76,6 +76,7 @@ #include "standard-headers/linux/input.h" #include "hw/arm/smmuv3.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/pcihp.h" #include "target/arm/cpu-qom.h" #include "target/arm/internals.h" #include "target/arm/multiprocessing.h" @@ -186,6 +187,7 @@ static const MemMapEntry base_memmap[] = { [VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN}, [VIRT_PVTIME] = { 0x090a0000, 0x00010000 }, [VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 }, + [VIRT_ACPI_PCIHP] = { 0x090c0000, ACPI_PCIHP_SIZE }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 5506a58862..9ff548650b 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -38,6 +38,8 @@ #define ACPI_PCIHP_SEJ_BASE 0x8 #define ACPI_PCIHP_BNMR_BASE 0x10 +#define ACPI_PCIHP_SIZE 0x0018 + typedef struct AcpiPciHpPciStatus { uint32_t up; uint32_t down; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 4375819ea0..365a28b082 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -80,6 +80,7 @@ enum { VIRT_ACPI_GED, VIRT_NVDIMM_ACPI, VIRT_PVTIME, + VIRT_ACPI_PCIHP, VIRT_LOWMEMMAP_LAST, }; From 7b3e231f0902c6aec5fd0ed38b84eb33fb7271e0 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:08 +0200 Subject: [PATCH 70/97] hw/acpi/ged: Add a bus link property This property will be set by the machine code on the object creation. It will be used by acpi pcihp hotplug code. Signed-off-by: Eric Auger Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-25-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 7831db412b..ef1c1ec51f 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -13,6 +13,7 @@ #include "qapi/error.h" #include "hw/acpi/acpi.h" #include "hw/acpi/generic_event_device.h" +#include "hw/pci/pci.h" #include "hw/irq.h" #include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" @@ -320,6 +321,8 @@ static const Property acpi_ged_properties[] = { DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0), DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, AcpiGedState, pcihp_state.use_acpi_hotplug_bridge, 0), + DEFINE_PROP_LINK("bus", AcpiGedState, pcihp_state.root, + TYPE_PCI_BUS, PCIBus *), }; static const VMStateDescription vmstate_memhp_state = { From 1913b8e68670223cfe8101c332a3b903031fc4d2 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:09 +0200 Subject: [PATCH 71/97] hw/arm/virt: Pass the bus on the ged creation The bus will be needed on ged realize for acpi pci hp setup. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-26-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 817adedb31..41b5086b55 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -701,6 +701,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); + object_property_set_link(OBJECT(dev), "bus", OBJECT(vms->bus), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); From 8c58dc0531d868ea706a68114c22601cdf4c4e67 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:10 +0200 Subject: [PATCH 72/97] hw/acpi/ged: Call pcihp plug callbacks in hotplug handler implementation Add PCI device related code in the TYPE_HOTPLUG_HANDLER implementation. For a PCI device hotplug/hotunplug event, the code routes to acpi_pcihp_device callbacks (pre_plug_cb, plug_cb, unplug_request_cb, unplug_cb). Signed-off-by: Eric Auger Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Message-Id: <20250714080639.2525563-27-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index ef1c1ec51f..92b931758f 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -17,6 +17,7 @@ #include "hw/irq.h" #include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/error-report.h" @@ -228,6 +229,14 @@ static const MemoryRegionOps ged_regs_ops = { }, }; +static void acpi_ged_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp); + } +} + static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -241,6 +250,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, } } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_plug_cb(hotplug_dev, &s->pcihp_state, dev, errp); } else { error_setg(errp, "virt: device plug request for unsupported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -257,6 +268,9 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->pcihp_state, + dev, errp); } else { error_setg(errp, "acpi: device unplug request for unsupported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -272,6 +286,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, acpi_memory_unplug_cb(&s->memhp_state, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + acpi_pcihp_device_unplug_cb(hotplug_dev, &s->pcihp_state, dev, errp); } else { error_setg(errp, "acpi: device unplug for unsupported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -485,6 +501,7 @@ static void acpi_ged_class_init(ObjectClass *class, const void *data) dc->vmsd = &vmstate_acpi_ged; dc->realize = acpi_ged_realize; + hc->pre_plug = acpi_ged_device_pre_plug_cb; hc->plug = acpi_ged_device_plug_cb; hc->unplug_request = acpi_ged_unplug_request_cb; hc->unplug = acpi_ged_unplug_cb; From b8c7ebbb70a316c8ea4a2a31eb071456bcc350b5 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:11 +0200 Subject: [PATCH 73/97] hw/acpi/pcihp: Remove root arg in acpi_pcihp_init Let pass the root bus to ich9 and piix4 through a property link instead of through an argument passed to acpi_pcihp_init(). Also make sure the root bus is set at the entry of acpi_pcihp_init(). The rationale of that change is to be consistent with the forecoming ARM implementation where the machine passes the root bus (steming from GPEX) to the GED device through a link property. Signed-off-by: Eric Auger Suggested-by: Igor Mammedov Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-28-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/acpi-pci-hotplug-stub.c | 2 +- hw/acpi/ich9.c | 7 ++++++- hw/acpi/pcihp.c | 4 ++-- hw/acpi/piix4.c | 5 ++++- include/hw/acpi/pcihp.h | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/hw/acpi/acpi-pci-hotplug-stub.c b/hw/acpi/acpi-pci-hotplug-stub.c index b7bc6e40a1..d58ea726a8 100644 --- a/hw/acpi/acpi-pci-hotplug-stub.c +++ b/hw/acpi/acpi-pci-hotplug-stub.c @@ -4,7 +4,7 @@ const VMStateDescription vmstate_acpi_pcihp_pci_status; -void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, +void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, MemoryRegion *address_space_io, uint16_t io_base) { } diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 967b67485e..2b3b493c01 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -322,9 +322,10 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq) } if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) { + object_property_set_link(OBJECT(lpc_pci), "bus", + OBJECT(pci_get_bus(lpc_pci)), &error_abort); acpi_pcihp_init(OBJECT(lpc_pci), &pm->acpi_pci_hotplug, - pci_get_bus(lpc_pci), pci_address_space_io(lpc_pci), ACPI_PCIHP_ADDR_ICH9); @@ -428,6 +429,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, &pm->pm_io_base, OBJ_PROP_FLAG_READ); + object_property_add_link(obj, "bus", TYPE_PCI_BUS, + (Object **)&pm->acpi_pci_hotplug.root, + object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", ich9_pm_get_gpe0_blk, NULL, NULL, pm); diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index f1594e664a..4922bbc778 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -493,13 +493,13 @@ static const MemoryRegionOps acpi_pcihp_io_ops = { }, }; -void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, +void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, MemoryRegion *io, uint16_t io_base) { s->io_len = ACPI_PCIHP_SIZE; s->io_base = io_base; - s->root = root_bus; + assert(s->root); memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s, "acpi-pci-hotplug", s->io_len); diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index d98b80df6d..7a18f18dda 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -567,7 +567,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge || s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) { - acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, + object_property_set_link(OBJECT(s), "bus", OBJECT(bus), &error_abort); + acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, parent, ACPI_PCIHP_ADDR_PIIX4); qbus_set_hotplug_handler(BUS(pci_get_bus(PCI_DEVICE(s))), OBJECT(s)); } @@ -611,6 +612,8 @@ static const Property piix4_pm_properties[] = { acpi_pci_hotplug.use_acpi_hotplug_bridge, true), DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCI_ROOTHP, PIIX4PMState, acpi_pci_hotplug.use_acpi_root_pci_hotplug, true), + DEFINE_PROP_LINK("bus", PIIX4PMState, acpi_pci_hotplug.root, + TYPE_PCI_BUS, PCIBus *), DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, acpi_memory_hotplug.is_enabled, true), DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false), diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index 9ff548650b..ca6a258825 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -62,7 +62,7 @@ typedef struct AcpiPciHpState { bool use_acpi_root_pci_hotplug; } AcpiPciHpState; -void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root, +void acpi_pcihp_init(Object *owner, AcpiPciHpState *, MemoryRegion *io, uint16_t io_base); bool acpi_pcihp_is_hotpluggable_bus(AcpiPciHpState *s, BusState *bus); From 1816a337a126281de43aabb4b55689f69ee876bc Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:12 +0200 Subject: [PATCH 74/97] hw/acpi/ged: Prepare the device to react to PCI hotplug events QEMU will notify the OS about PCI hotplug/hotunplug events through GED interrupts. Let the GED device handle a new PCI hotplug event. On its occurrence it calls the \\_SB.PCI0.PCNT method with the BLCK mutex held. The GED device uses a dedicated MMIO region that will be mapped by the machine code. At this point the GED still does not support PCI device hotplug in its TYPE_HOTPLUG_HANDLER implementation. This will come in a subsequent patch. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-29-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 35 ++++++++++++++++++++++++++ include/hw/acpi/generic_event_device.h | 14 ++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 92b931758f..7535d07737 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/pcihp.h" #include "hw/acpi/generic_event_device.h" #include "hw/pci/pci.h" #include "hw/irq.h" @@ -28,6 +29,7 @@ static const uint32_t ged_supported_events[] = { ACPI_GED_PWR_DOWN_EVT, ACPI_GED_NVDIMM_HOTPLUG_EVT, ACPI_GED_CPU_HOTPLUG_EVT, + ACPI_GED_PCI_HOTPLUG_EVT, }; /* @@ -123,6 +125,12 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, aml_notify(aml_name("\\_SB.NVDR"), aml_int(0x80))); break; + case ACPI_GED_PCI_HOTPLUG_EVT: + aml_append(if_ctx, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(if_ctx, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(if_ctx, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + break; default: /* * Please make sure all the events in ged_supported_events[] @@ -316,6 +324,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) sel = ACPI_GED_NVDIMM_HOTPLUG_EVT; } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { sel = ACPI_GED_CPU_HOTPLUG_EVT; + } else if (ev & ACPI_PCI_HOTPLUG_STATUS) { + sel = ACPI_GED_PCI_HOTPLUG_EVT; } else { /* Unknown event. Return without generating interrupt. */ warn_report("GED: Unsupported event %d. No irq injected", ev); @@ -427,9 +437,13 @@ static void acpi_ged_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AcpiGedState *s = ACPI_GED(dev); + AcpiPciHpState *pcihp_state = &s->pcihp_state; uint32_t ged_events; int i; + if (pcihp_state->use_acpi_hotplug_bridge) { + s->ged_event_bitmap |= ACPI_GED_PCI_HOTPLUG_EVT; + } ged_events = ctpop32(s->ged_event_bitmap); for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) { @@ -449,6 +463,13 @@ static void acpi_ged_realize(DeviceState *dev, Error **errp) cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), &s->cpuhp_state, 0); break; + case ACPI_GED_PCI_HOTPLUG_EVT: + memory_region_init(&s->container_pcihp, OBJECT(dev), + ACPI_PCIHP_REGION_NAME, ACPI_PCIHP_SIZE); + sysbus_init_mmio(sbd, &s->container_pcihp); + acpi_pcihp_init(OBJECT(s), &s->pcihp_state, + &s->container_pcihp, 0); + qbus_set_hotplug_handler(BUS(s->pcihp_state.root), OBJECT(dev)); } ged_events--; } @@ -490,11 +511,22 @@ static void acpi_ged_initfn(Object *obj) sysbus_init_mmio(sbd, &ged_st->regs); } +static void ged_reset_hold(Object *obj, ResetType type) +{ + AcpiGedState *s = ACPI_GED(obj); + + if (s->pcihp_state.use_acpi_hotplug_bridge) { + acpi_pcihp_reset(&s->pcihp_state); + } +} + static void acpi_ged_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); + ResettableClass *rc = RESETTABLE_CLASS(class); + AcpiGedClass *gedc = ACPI_GED_CLASS(class); dc->desc = "ACPI Generic Event Device"; device_class_set_props(dc, acpi_ged_properties); @@ -505,6 +537,8 @@ static void acpi_ged_class_init(ObjectClass *class, const void *data) hc->plug = acpi_ged_device_plug_cb; hc->unplug_request = acpi_ged_unplug_request_cb; hc->unplug = acpi_ged_unplug_cb; + resettable_class_set_parent_phases(rc, NULL, ged_reset_hold, NULL, + &gedc->parent_phases); adevc->ospm_status = acpi_ged_ospm_status; adevc->send_event = acpi_ged_send_event; @@ -516,6 +550,7 @@ static const TypeInfo acpi_ged_info = { .instance_size = sizeof(AcpiGedState), .instance_init = acpi_ged_initfn, .class_init = acpi_ged_class_init, + .class_size = sizeof(AcpiGedClass), .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index f5ffa67a39..d56adaa626 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -69,7 +69,7 @@ #define ACPI_POWER_BUTTON_DEVICE "PWRB" #define TYPE_ACPI_GED "acpi-ged" -OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) +OBJECT_DECLARE_TYPE(AcpiGedState, AcpiGedClass, ACPI_GED) #define ACPI_GED_EVT_SEL_OFFSET 0x0 #define ACPI_GED_EVT_SEL_LEN 0x4 @@ -102,6 +102,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) #define ACPI_GED_PWR_DOWN_EVT 0x2 #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 #define ACPI_GED_CPU_HOTPLUG_EVT 0x8 +#define ACPI_GED_PCI_HOTPLUG_EVT 0x10 typedef struct GEDState { MemoryRegion evt; @@ -109,6 +110,8 @@ typedef struct GEDState { uint32_t sel; } GEDState; +#define ACPI_PCIHP_REGION_NAME "pcihp container" + struct AcpiGedState { SysBusDevice parent_obj; MemHotplugState memhp_state; @@ -116,12 +119,21 @@ struct AcpiGedState { CPUHotplugState cpuhp_state; MemoryRegion container_cpuhp; AcpiPciHpState pcihp_state; + MemoryRegion container_pcihp; GEDState ged_state; uint32_t ged_event_bitmap; qemu_irq irq; AcpiGhesState ghes_state; }; +typedef struct AcpiGedClass { + /* */ + SysBusDeviceClass parent_class; + + /*< public >*/ + ResettablePhases parent_phases; +} AcpiGedClass; + void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base); void acpi_dsdt_add_power_button(Aml *scope); From 745315784db4315644421f5def482ff1324503bd Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:13 +0200 Subject: [PATCH 75/97] hw/acpi/ged: Support migration of AcpiPciHpState Add a subsection to migrate the AcpiPciHpState state. Signed-off-by: Eric Auger Reviewed-by: Igor Mammedov Reviewed-by: Jonathan Cameron Reviewed-by: Prasad Pandit Message-Id: <20250714080639.2525563-30-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 7535d07737..95682b79a2 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -417,6 +417,25 @@ static const VMStateDescription vmstate_ghes_state = { } }; +static bool pcihp_needed(void *opaque) +{ + AcpiGedState *s = opaque; + return s->pcihp_state.use_acpi_hotplug_bridge; +} + +static const VMStateDescription vmstate_pcihp_state = { + .name = "acpi-ged/pcihp", + .version_id = 1, + .minimum_version_id = 1, + .needed = pcihp_needed, + .fields = (const VMStateField[]) { + VMSTATE_PCI_HOTPLUG(pcihp_state, + AcpiGedState, + NULL, NULL), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_acpi_ged = { .name = "acpi-ged", .version_id = 1, @@ -429,6 +448,7 @@ static const VMStateDescription vmstate_acpi_ged = { &vmstate_memhp_state, &vmstate_cpuhp_state, &vmstate_ghes_state, + &vmstate_pcihp_state, NULL } }; From 1a102856652268cf2ec4cbd2cb9b229ef920c31d Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:14 +0200 Subject: [PATCH 76/97] hw/core/sysbus: Introduce sysbus_mmio_map_name() helper Some sysbus devices have conditional mmio regions. This happens for instance with the hw/acpi/ged device. In that case it becomes difficult to predict which index a specific MMIO region corresponds to when one needs to mmio map the region. Introduce a new helper that takes the name of the region instead of its index. If the region is not found this returns -1. Otherwise it maps the corresponding index and returns this latter. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-31-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/sysbus.c | 11 +++++++++++ include/hw/sysbus.h | 1 + 2 files changed, 12 insertions(+) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index e71367adfb..ec69e877a2 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -151,6 +151,17 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) sysbus_mmio_map_common(dev, n, addr, false, 0); } +int sysbus_mmio_map_name(SysBusDevice *dev, const char *name, hwaddr addr) +{ + for (int i = 0; i < dev->num_mmio; i++) { + if (!strcmp(dev->mmio[i].memory->name, name)) { + sysbus_mmio_map(dev, i, addr); + return i; + } + } + return -1; +} + void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, int priority) { diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 7dc88aaa27..18fde8a7b4 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -82,6 +82,7 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq); bool sysbus_is_irq_connected(SysBusDevice *dev, int n); qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n); void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr); +int sysbus_mmio_map_name(SysBusDevice *dev, const char*name, hwaddr addr); void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, int priority); From cfd4ace6e5faf3064defa559e1b5fd674109186f Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:15 +0200 Subject: [PATCH 77/97] hw/arm/virt: Minor code reshuffling in create_acpi_ged Use a local SysBusDevice handle. Also use the newly introduced sysbus_mmio_map_name which brings better readability about the region being mapped. GED device has regions which exist depending on some external properties and it becomes difficult to guess the index of a region. Better refer to a region by its name. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-32-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 11 +++++++---- include/hw/acpi/generic_event_device.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 41b5086b55..f127a668ef 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -688,6 +688,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) { DeviceState *dev; MachineState *ms = MACHINE(vms); + SysBusDevice *sbdev; int irq = vms->irqmap[VIRT_ACPI_GED]; uint32_t event = ACPI_GED_PWR_DOWN_EVT; @@ -702,11 +703,13 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); object_property_set_link(OBJECT(dev), "bus", OBJECT(vms->bus), &error_abort); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sbdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbdev, &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); + sysbus_mmio_map_name(sbdev, TYPE_ACPI_GED, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map_name(sbdev, ACPI_MEMHP_REGION_NAME, + vms->memmap[VIRT_PCDIMM_ACPI].base); + sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(vms->gic, irq)); return dev; } diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d56adaa626..2c5b055327 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -111,6 +111,7 @@ typedef struct GEDState { } GEDState; #define ACPI_PCIHP_REGION_NAME "pcihp container" +#define ACPI_MEMHP_REGION_NAME "memhp container" struct AcpiGedState { SysBusDevice parent_obj; From 6af97d127eb40bd8a3b25db86d3644b25287be51 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:16 +0200 Subject: [PATCH 78/97] hw/arm/virt: Let virt support pci hotplug/unplug GED event Set up the IO registers used to communicate between QEMU and ACPI. Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-33-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index f127a668ef..ef6be3660f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -691,6 +691,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) SysBusDevice *sbdev; int irq = vms->irqmap[VIRT_ACPI_GED]; uint32_t event = ACPI_GED_PWR_DOWN_EVT; + bool acpi_pcihp; if (ms->ram_slots) { event |= ACPI_GED_MEM_HOTPLUG_EVT; @@ -709,6 +710,18 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) sysbus_mmio_map_name(sbdev, TYPE_ACPI_GED, vms->memmap[VIRT_ACPI_GED].base); sysbus_mmio_map_name(sbdev, ACPI_MEMHP_REGION_NAME, vms->memmap[VIRT_PCDIMM_ACPI].base); + + acpi_pcihp = object_property_get_bool(OBJECT(dev), + ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, NULL); + + if (acpi_pcihp) { + int pcihp_region_index; + + pcihp_region_index = sysbus_mmio_map_name(sbdev, ACPI_PCIHP_REGION_NAME, + vms->memmap[VIRT_ACPI_PCIHP].base); + assert(pcihp_region_index >= 0); + } + sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(vms->gic, irq)); return dev; From 099ea5daeae0b1acb386b9e3c99838798cb0f690 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Mon, 14 Jul 2025 10:05:17 +0200 Subject: [PATCH 79/97] tests/qtest/bios-tables-test: Prepare for addition of acpi pci hp tests Soon we will introduce new tests related to ACPI PCI hotplug and acpi-index that will use a new reference blob: tests/data/acpi/aarch64/virt/DSDT.acpipcihp tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex Signed-off-by: Gustavo Romero Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-34-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT.acpipcihp | 0 tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex | 0 tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 tests/data/acpi/aarch64/virt/DSDT.acpipcihp create mode 100644 tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpipcihp b/tests/data/acpi/aarch64/virt/DSDT.acpipcihp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex b/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..02f4f0b29f 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/aarch64/virt/DSDT.acpipcihp", +"tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex", From 72140ff2a14545f3c7835c8531cb51255b652d2e Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Mon, 14 Jul 2025 10:05:18 +0200 Subject: [PATCH 80/97] tests/qtest/bios-tables-test: Add aarch64 ACPI PCI hotplug test Add 2 new tests: - test_acpi_aarch64_virt_acpi_pci_hotplug tests the acpi pci hotplug using -global acpi-ged.acpi-pci-hotplug-with-bridge-support=on - test_acpi_aarch64_virt_pcie_root_port_hpoff tests static-acpi index on a root port with disabled hotplug Signed-off-by: Gustavo Romero Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-35-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 4701975c05..6aec68decc 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1643,6 +1643,54 @@ static void test_acpi_aarch64_virt_tcg_memhp(void) } +static void test_acpi_aarch64_virt_acpi_pci_hotplug(void) +{ + test_data data = { + .machine = "virt", + .arch = "aarch64", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 256ULL * MiB, + .variant = ".acpipcihp", + }; + + /* Use ACPI PCI Hotplug */ + test_acpi_one(" -global acpi-ged.acpi-pci-hotplug-with-bridge-support=on" + " -cpu cortex-a57" + " -device pcie-root-port,id=pcie.1,bus=pcie.0,chassis=0,slot=1,addr=7.0" + " -device pci-testdev,bus=pcie.1", + &data); + + free_test_data(&data); +} + +static void test_acpi_aarch64_virt_pcie_root_port_hpoff(void) +{ + test_data data = { + .machine = "virt", + .arch = "aarch64", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 256ULL * MiB, + .variant = ".hpoffacpiindex", + }; + + /* turn hotplug off on the pcie-root-port and use static acpi-index*/ + test_acpi_one(" -device pcie-root-port,id=pcie.1,chassis=0," + "slot=1,hotplug=off,addr=7.0" + " -device pci-testdev,bus=pcie.1,acpi-index=12" + " -cpu cortex-a57", + &data); + + free_test_data(&data); +} + static void test_acpi_microvm_prepare(test_data *data) { data->machine = "microvm"; @@ -2708,6 +2756,10 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/virt/numamem", test_acpi_aarch64_virt_tcg_numamem); qtest_add_func("acpi/virt/memhp", test_acpi_aarch64_virt_tcg_memhp); + qtest_add_func("acpi/virt/acpipcihp", + test_acpi_aarch64_virt_acpi_pci_hotplug); + qtest_add_func("acpi/virt/hpoffacpiindex", + test_acpi_aarch64_virt_pcie_root_port_hpoff); qtest_add_func("acpi/virt/pxb", test_acpi_aarch64_virt_tcg_pxb); qtest_add_func("acpi/virt/oem-fields", test_acpi_aarch64_virt_oem_fields); From 84dfc6c07495052c16886f3bf279342fc30e99b0 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:19 +0200 Subject: [PATCH 81/97] qtest/bios-tables-test: Generate reference blob for DSDT.hpoffacpiindex The disassembled DSDT table is given below * Original Table Header: * Signature "DSDT" * Length 0x000014E3 (5347) * Revision 0x02 * Checksum 0x92 * OEM ID "BOCHS " * OEM Table ID "BXPC " * OEM Revision 0x00000001 (1) * Compiler ID "BXPC" * Compiler Version 0x00000001 (1) */ DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) { Scope (\_SB) { Device (C000) { Name (_HID, "ACPI0007" /* Processor Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID } Device (COM0) { Name (_HID, "ARMH0011") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x09000000, // Address Base 0x00001000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000021, } }) } Device (FWCF) { Name (_HID, "QEMU0002") // _HID: Hardware ID Name (_STA, 0x0B) // _STA: Status Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x09020000, // Address Base 0x00000018, // Address Length ) }) } Device (VR00) { Name (_HID, "LNRO0005") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x0A000000, // Address Base 0x00000200, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000030, } }) } ../.. Device (L000) { Name (_HID, "PNP0C0F" /* PCI Interrupt Link Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_PRS, ResourceTemplate () // _PRS: Possible Resource Settings { Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000023, } }) Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000023, } }) Method (_SRS, 1, NotSerialized) // _SRS: Set Resource Settings { } } ../.. Device (PCI0) { Name (_HID, "PNP0A08" /* PCI Express Bus */) // _HID: Hardware ID Name (_CID, "PNP0A03" /* PCI Bus */) // _CID: Compatible ID Name (_SEG, Zero) // _SEG: PCI Segment Name (_BBN, Zero) // _BBN: BIOS Bus Number Name (_UID, Zero) // _UID: Unique ID Name (_STR, Unicode ("PCIe 0 Device")) // _STR: Description String Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_PRT, Package (0x80) // _PRT: PCI Routing Table { Package (0x04) { 0xFFFF, Zero, L000, Zero }, ../.. }) Method (_CBA, 0, NotSerialized) // _CBA: Configuration Base Address { Return (0x0000004010000000) } Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, 0x0000, // Granularity 0x0000, // Range Minimum 0x00FF, // Range Maximum 0x0000, // Translation Offset 0x0100, // Length ,, ) DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x00000000, // Granularity 0x10000000, // Range Minimum 0x3EFEFFFF, // Range Maximum 0x00000000, // Translation Offset 0x2EFF0000, // Length ,, , AddressRangeMemory, TypeStatic) DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, 0x00000000, // Granularity 0x00000000, // Range Minimum 0x0000FFFF, // Range Maximum 0x3EFF0000, // Translation Offset 0x00010000, // Length ,, , TypeStatic, DenseTranslation) QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x0000000000000000, // Granularity 0x0000008000000000, // Range Minimum 0x000000FFFFFFFFFF, // Range Maximum 0x0000000000000000, // Translation Offset 0x0000008000000000, // Length ,, , AddressRangeMemory, TypeStatic) }) Method (_OSC, 4, NotSerialized) // _OSC: Operating System Capabilities { CreateDWordField (Arg3, Zero, CDW1) If ((Arg0 == ToUUID ("33db4d5b-1ff7-401c-9657-7441c03dd766") /* PCI Host Bridge Device */)) { CreateDWordField (Arg3, 0x04, CDW2) CreateDWordField (Arg3, 0x08, CDW3) Local0 = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ Local0 &= 0x1F If ((Arg1 != One)) { CDW1 |= 0x08 } If ((CDW3 != Local0)) { CDW1 |= 0x10 } CDW3 = Local0 } Else { CDW1 |= 0x04 } Return (Arg3) } Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method { If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) { If ((Arg2 == Zero)) { Return (Buffer (One) { 0x01 // . }) } } Return (Buffer (One) { 0x00 // . }) } Device (RES0) { Name (_HID, "PNP0C02" /* PNP Motherboard Resources */) // _HID: Hardware ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x0000000000000000, // Granularity 0x0000004010000000, // Range Minimum 0x000000401FFFFFFF, // Range Maximum 0x0000000000000000, // Translation Offset 0x0000000010000000, // Length ,, , AddressRangeMemory, TypeStatic) }) } } Device (\_SB.GED) { Name (_HID, "ACPI0013" /* Generic Event Device */) // _HID: Hardware ID Name (_UID, "GED") // _UID: Unique ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) { 0x00000029, } }) OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) Field (EREG, DWordAcc, NoLock, WriteAsZeros) { ESEL, 32 } Method (_EVT, 1, Serialized) // _EVT: Event { Local0 = ESEL /* \_SB_.GED_.ESEL */ If (((Local0 & 0x02) == 0x02)) { Notify (PWRB, 0x80) // Status Change } } } Device (PWRB) { Name (_HID, "PNP0C0C" /* Power Button Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID } } Scope (\_SB.PCI0) { Method (EDSM, 5, Serialized) { If ((Arg2 == Zero)) { Local0 = Buffer (One) { 0x00 // . } If ((Arg0 != ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) { Return (Local0) } If ((Arg1 < 0x02)) { Return (Local0) } Local0 [Zero] = 0x81 Return (Local0) } If ((Arg2 == 0x07)) { Local0 = Package (0x02) { Zero, "" } Local1 = DerefOf (Arg4 [Zero]) Local0 [Zero] = Local1 Return (Local0) } } Device (S00) { Name (_ADR, Zero) // _ADR: Address } Device (S08) { Name (_ADR, 0x00010000) // _ADR: Address } Device (S38) { Name (_ADR, 0x00070000) // _ADR: Address Device (S00) { Name (_ADR, Zero) // _ADR: Address Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method { Local0 = Package (0x01) { 0x0C } Return (EDSM (Arg0, Arg1, Arg2, Arg3, Local0)) } } } } } Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-36-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex | Bin 0 -> 5347 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex b/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..970d43f68bca060361105f70dbb00b3a25646db4 100644 GIT binary patch literal 5347 zcmZ<>b_sbb!oa{Z$;sc@BUr&HBEVTeK|z6$fq?@*Ho-Pd0O;*nSzA(8UUk?KVLqn(>N4#@Tu%Hx|cpE1J$Usg8 z0S1OnHU>sUMFs|jN`~kr3%77*H;B1`uD+oL1_nk99Pz;+j$GUv@y^bUj1VIPx%ePP zFmXyibvm+y1;L!;;}_&_U|?X1uokWpVL2BA6V!48WFrhAwxb#WvKGS#CI*BNhEOA% zK&~*tW&{@#vIk(!U_mm&2-yr{tY$D{GlLDu3}a+7Ot6~4g3SyLBr{Bq%`nAk1}io* zxRA^+MK;3>s~K$A%-}&X!wlIBbF5~tV>5#f$qaL3Gc2&0!GX;T0VFdlkj=2fY6d4Z zGlY=LutYM$5SlqqlNc8lHZw$!%&18Xux%_OiiCWd5&HL@Al(gDNJ%79SiG%oyDSHVWz-6r&h9;*pI~!D19d3~rPc$W_qXgJKk@ zF@kKCDi*UKVyI?8a}lap%&6{C!(tXh3}M!!0B28VtbxpOG_YXchf>C@{D%q%xE-WHKZ(q%tso3;{RO0)j$> zeTumngt%F_|NmzI#SH_5&FEubV8|fE0}|(A@&UCkp&Vu(0|R3QAzl`q|Nj{oKza<} zJdiFU1|dF(99W+*f(z1V09DHb)@cOifpo%@GBJR48bEb2F>rx&!fas%>x8+0nE|8| zrj!|?(-5kY8KM(r3kz5$%mpl9oiL>=5S=i`vp{shY+(iKgt>qftP`e`6`~X7cvgr` zm@RBzoiG=$fpx-^vO#ph9M1;P3A2SAtP|z}cCb#EQg(<=nB&x3!ghUkPjo*SYQW(yBkC(H#rV4X0fJP@5Q$MZmR!ffFM>x8+07pxPe zloz5C=6GI+PM9rxV4W}*@PT#0l=4Az!W_>B(FwDKAFLDR0)DVgm{NX-PMG8QAv$5U z2!M6MTp$3}2~#Qn(Ft?B07NIu7D2F1m7li19*&+ni33GuESSL)W z5JV@;@j?)tFk6JdI$Hvqc`P z6XpVWuuhm#d5BJ!rw8J6%dFfa&!`Ztgkiw8SbNe3?j6AuFj{09+? z?cxj!JfOiG5KrL$|9_xv83O~uf4z2b21XuckT3}U2P^+?$H2hI(4~!}2PDbR0MhaQ zKSU8&1VVtsD;Y$5*yH_!omslF8Ju0h4Hx*aPR0wmUdCZsc!}cy+v{mv z*<38nF5yO9*<2jXF5$)nAR?hUflEGNfxx86nT)j{?O-{>1;UdigQX#20w9@!1dzx= z9*7XgD8nV$BD(P|!M-dD6d`tAFhBV;*tE)bqWCLc$-~aR3pgidF)R^eW@H2r4AD)# zEJ3cpNR1n3@DLVg;LDiH0K@0t(Eb1azdR_EA$|sv0w5AJBId*%qX!yub9Z%#hm1Wy z2HXrmjigXd7hZQ)7f`zg-pFKT)C9M{q8nU;T-_OX7#KJ>xmcnbxj|fK*I-v41rgbJ z*RT-I0uU!*fxzVI1TIk9q%9yk$cd{Vx=9kmfLI1=8TU;~4Aj(A6xAcp8B{$K+O2!{uhexjR9f{hUZ>$6r00#{qJpcdz literal 0 HcmV?d00001 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 02f4f0b29f..dc3ab24d05 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,3 +1,2 @@ /* List of comma-separated changed AML files to ignore */ "tests/data/acpi/aarch64/virt/DSDT.acpipcihp", -"tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex", From 14e37f46b1762224f215df884d2f1547ff7198ae Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 14 Jul 2025 10:05:20 +0200 Subject: [PATCH 82/97] qtest/bios-tables-test: Generate reference blob for DSDT.acpipcihp The disassembled DSDT table is given below. /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20210604 (64-bit version) * Copyright (c) 2000 - 2021 Intel Corporation * * Disassembling to symbolic ASL+ operators * * Disassembly of ../tests/data/acpi/aarch64/virt/DSDT.acpipcihp, Thu Jul 3 05:16:27 2025 * * Original Table Header: * Signature "DSDT" * Length 0x0000183A (6202) * Revision 0x02 * Checksum 0x98 * OEM ID "BOCHS " * OEM Table ID "BXPC " * OEM Revision 0x00000001 (1) * Compiler ID "BXPC" * Compiler Version 0x00000001 (1) */ DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) { Scope (\_SB) { Device (C000) { Name (_HID, "ACPI0007" /* Processor Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID } Device (COM0) { Name (_HID, "ARMH0011") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x09000000, // Address Base 0x00001000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000021, } }) } Device (FWCF) { Name (_HID, "QEMU0002") // _HID: Hardware ID Name (_STA, 0x0B) // _STA: Status Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x09020000, // Address Base 0x00000018, // Address Length ) }) } Device (VR00) { Name (_HID, "LNRO0005") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x0A000000, // Address Base 0x00000200, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000030, } }) } ../.. Device (L000) { Name (_HID, "PNP0C0F" /* PCI Interrupt Link Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_PRS, ResourceTemplate () // _PRS: Possible Resource Settings { Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000023, } }) Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000023, } }) Method (_SRS, 1, NotSerialized) // _SRS: Set Resource Settings { } } ../.. Device (PCI0) { Name (_HID, "PNP0A08" /* PCI Express Bus */) // _HID: Hardware ID Name (_CID, "PNP0A03" /* PCI Bus */) // _CID: Compatible ID Name (_SEG, Zero) // _SEG: PCI Segment Name (_BBN, Zero) // _BBN: BIOS Bus Number Name (_UID, Zero) // _UID: Unique ID Name (_STR, Unicode ("PCIe 0 Device")) // _STR: Description String Name (_CCA, One) // _CCA: Cache Coherency Attribute Name (_PRT, Package (0x80) // _PRT: PCI Routing Table { Package (0x04) { 0xFFFF, Zero, L000, Zero }, ../.. }) Method (_CBA, 0, NotSerialized) // _CBA: Configuration Base Address { Return (0x0000004010000000) } Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, 0x0000, // Granularity 0x0000, // Range Minimum 0x00FF, // Range Maximum 0x0000, // Translation Offset 0x0100, // Length ,, ) DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x00000000, // Granularity 0x10000000, // Range Minimum 0x3EFEFFFF, // Range Maximum 0x00000000, // Translation Offset 0x2EFF0000, // Length ,, , AddressRangeMemory, TypeStatic) DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, 0x00000000, // Granularity 0x00000000, // Range Minimum 0x0000FFFF, // Range Maximum 0x3EFF0000, // Translation Offset 0x00010000, // Length ,, , TypeStatic, DenseTranslation) QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x0000000000000000, // Granularity 0x0000008000000000, // Range Minimum 0x000000FFFFFFFFFF, // Range Maximum 0x0000000000000000, // Translation Offset 0x0000008000000000, // Length ,, , AddressRangeMemory, TypeStatic) }) Method (_OSC, 4, NotSerialized) // _OSC: Operating System Capabilities { CreateDWordField (Arg3, Zero, CDW1) If ((Arg0 == ToUUID ("33db4d5b-1ff7-401c-9657-7441c03dd766") /* PCI Host Bridge Device */)) { CreateDWordField (Arg3, 0x04, CDW2) CreateDWordField (Arg3, 0x08, CDW3) Local0 = CDW3 /* \_SB_.PCI0._OSC.CDW3 */ Local0 &= 0x1E If ((Arg1 != One)) { CDW1 |= 0x08 } If ((CDW3 != Local0)) { CDW1 |= 0x10 } CDW3 = Local0 } Else { CDW1 |= 0x04 } Return (Arg3) } Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method { If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) { If ((Arg2 == Zero)) { Return (Buffer (One) { 0x01 // . }) } } Return (Buffer (One) { 0x00 // . }) } Device (RES0) { Name (_HID, "PNP0C02" /* PNP Motherboard Resources */) // _HID: Hardware ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, 0x0000000000000000, // Granularity 0x0000004010000000, // Range Minimum 0x000000401FFFFFFF, // Range Maximum 0x0000000000000000, // Translation Offset 0x0000000010000000, // Length ,, , AddressRangeMemory, TypeStatic) }) } } Device (\_SB.GED) { Name (_HID, "ACPI0013" /* Generic Event Device */) // _HID: Hardware ID Name (_UID, "GED") // _UID: Unique ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) { 0x00000029, } }) OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) Field (EREG, DWordAcc, NoLock, WriteAsZeros) { ESEL, 32 } Method (_EVT, 1, Serialized) // _EVT: Event { Local0 = ESEL /* \_SB_.GED_.ESEL */ If (((Local0 & 0x02) == 0x02)) { Notify (PWRB, 0x80) // Status Change } If (((Local0 & 0x10) == 0x10)) { Acquire (\_SB.PCI0.BLCK, 0xFFFF) \_SB.PCI0.PCNT () Release (\_SB.PCI0.BLCK) } } } Device (PWRB) { Name (_HID, "PNP0C0C" /* Power Button Device */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID } } Scope (_SB.PCI0) { OperationRegion (PCST, SystemMemory, 0x090C0000, 0x08) Field (PCST, DWordAcc, NoLock, WriteAsZeros) { PCIU, 32, PCID, 32 } OperationRegion (SEJ, SystemMemory, 0x090C0008, 0x04) Field (SEJ, DWordAcc, NoLock, WriteAsZeros) { B0EJ, 32 } OperationRegion (BNMR, SystemMemory, 0x090C0010, 0x08) Field (BNMR, DWordAcc, NoLock, WriteAsZeros) { BNUM, 32, PIDX, 32 } Mutex (BLCK, 0x00) Method (PCEJ, 2, NotSerialized) { Acquire (BLCK, 0xFFFF) BNUM = Arg0 B0EJ = (One << Arg1) Release (BLCK) Return (Zero) } Method (AIDX, 2, NotSerialized) { Acquire (BLCK, 0xFFFF) BNUM = Arg0 PIDX = (One << Arg1) Local0 = PIDX /* \_SB_.PCI0.PIDX */ Release (BLCK) Return (Local0) } Method (PDSM, 5, Serialized) { If ((Arg2 == Zero)) { Local0 = Buffer (One) { 0x00 // . } If ((Arg0 != ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) { Return (Local0) } If ((Arg1 < 0x02)) { Return (Local0) } Local1 = Zero Local2 = AIDX (DerefOf (Arg4 [Zero]), DerefOf (Arg4 [One] )) If (!((Local2 == Zero) | (Local2 == 0xFFFFFFFF))) { Local1 |= One Local1 |= (One << 0x07) } Local0 [Zero] = Local1 Return (Local0) } If ((Arg2 == 0x07)) { Local2 = AIDX (DerefOf (Arg4 [Zero]), DerefOf (Arg4 [One] )) Local0 = Package (0x02) {} If (!((Local2 == Zero) || (Local2 == 0xFFFFFFFF))) { Local0 [Zero] = Local2 Local0 [One] = "" } Return (Local0) } } } Scope (\_SB.PCI0) { Method (EDSM, 5, Serialized) { If ((Arg2 == Zero)) { Local0 = Buffer (One) { 0x00 // . } If ((Arg0 != ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) { Return (Local0) } If ((Arg1 < 0x02)) { Return (Local0) } Local0 [Zero] = 0x81 Return (Local0) } If ((Arg2 == 0x07)) { Local0 = Package (0x02) { Zero, "" } Local1 = DerefOf (Arg4 [Zero]) Local0 [Zero] = Local1 Return (Local0) } } Device (S00) { Name (_ADR, Zero) // _ADR: Address } Device (S08) { Name (_ADR, 0x00010000) // _ADR: Address } Device (S38) { Name (_ADR, 0x00070000) // _ADR: Address Device (S00) { Name (_ADR, Zero) // _ADR: Address } Name (BSEL, One) Scope (S00) { Name (ASUN, Zero) Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method { Local0 = Package (0x02) { Zero, Zero } Local0 [Zero] = BSEL /* \_SB_.PCI0.S38_.BSEL */ Local0 [One] = ASUN /* \_SB_.PCI0.S38_.S00_.ASUN */ Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) } Name (_SUN, Zero) // _SUN: Slot User Number Method (_EJ0, 1, NotSerialized) // _EJx: Eject Device, x=0-9 { PCEJ (BSEL, _SUN) } } Method (DVNT, 2, NotSerialized) { If ((Arg0 & One)) { Notify (S00, Arg1) } } } Name (BSEL, Zero) Scope (S00) { Name (ASUN, Zero) Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method { Local0 = Package (0x02) { Zero, Zero } Local0 [Zero] = BSEL /* \_SB_.PCI0.BSEL */ Local0 [One] = ASUN /* \_SB_.PCI0.S00_.ASUN */ Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) } Name (_SUN, Zero) // _SUN: Slot User Number Method (_EJ0, 1, NotSerialized) // _EJx: Eject Device, x=0-9 { PCEJ (BSEL, _SUN) } } Scope (S08) { Name (ASUN, One) Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method { Local0 = Package (0x02) { Zero, Zero } Local0 [Zero] = BSEL /* \_SB_.PCI0.BSEL */ Local0 [One] = ASUN /* \_SB_.PCI0.S08_.ASUN */ Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) } Name (_SUN, One) // _SUN: Slot User Number Method (_EJ0, 1, NotSerialized) // _EJx: Eject Device, x=0-9 { PCEJ (BSEL, _SUN) } } Method (DVNT, 2, NotSerialized) { If ((Arg0 & One)) { Notify (S00, Arg1) } If ((Arg0 & 0x02)) { Notify (S08, Arg1) } } Device (PHPR) { Name (_HID, "PNP0A06" /* Generic Container Device */) // _HID: Hardware ID Name (_UID, "PCI Hotplug resources") // _UID: Unique ID Name (_STA, 0x0B) // _STA: Status Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { IO (Decode16, 0x0000, // Range Minimum 0x0000, // Range Maximum 0x01, // Alignment 0x18, // Length ) }) } Scope (S38) { Method (PCNT, 0, NotSerialized) { BNUM = One DVNT (PCIU, One) DVNT (PCID, 0x03) } } Method (PCNT, 0, NotSerialized) { BNUM = Zero DVNT (PCIU, One) DVNT (PCID, 0x03) ^S38.PCNT () } } } Signed-off-by: Eric Auger Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-Id: <20250714080639.2525563-37-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/DSDT.acpipcihp | Bin 0 -> 6202 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpipcihp b/tests/data/acpi/aarch64/virt/DSDT.acpipcihp index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8d55a877a40cb4c4dffdc70378204e12d2261a75 100644 GIT binary patch literal 6202 zcmZ<>b_ubPU|?XH;pFe^5v<@85#X$#prF9Wz`y`vgJ^+%XU3TLV5j)#CMjnF0|SnD z4^J0fN9O=f0|Ntd29EepPZx&hCM#!uUzl8wuZMwwp&?X`Bi=bESWt>fyp59qWFRMl z00ToO8v`SwA_D_MB|~(Rg zAXgY+GlGi=*#j_VuppUXglvW}Rx_BfnZbr+hB2}kCRoj2!Da>rk{Kq*W|(3%gB6<@ zTu5e^BAa1`)eJUlX7C`HVTNpmIaV{+v6;b#WQIAi85UU0;J{{v0FoIN$Yxk#HG>nI z8A3>ASR$EW2+bU*NsNmNn;9ZVW>_Jcfi;<;W)fH$6GJk?8rcl&>68bXJ0y_Iut7Eh zdphOCW`-1!8Meq~U{9xf*vybYGQ$qp4D9KYADbC+NM_h0n}I!@3Scus0m%#pWHYd* zQ$cKIC?T2Qh-?P-bSi|+3>73ZoRH1Ho=%0anW2VchBJ~GM%dG-2sSe`kj!vFHUoP) z6~$(T7LpmR$Yx+qr()R5&_Oc84cQFr=~Nt>8G1-&xFef^J)KHmGs6JM3=d>8u%}Z= zY-SiCnc<0S2KIC+h0P2TBs08_&A^^crLmb|hGd2}vKiRZsSGwVERf9bK{f+>I+ev{ zh82<-zDQ;mV^61Y*vzm&GQ$tq4D9Jt9-A3j~nVKECLhA?YVfU_qw)<9-C8dxxJ#5;Ss@IrXTpf;bY zI|E0&lan7j9D_rG1m(G80vMbbJQ-3M6c`K`6c}6>QW?q^G8vK?QW+RPhJc%C0YM?c zKE+%OLfkCe|Nk?9;)VgjX7n*IFk}$o0f}=l`GDG&P!6+?fq^lD5HAbQ|No2(AU%d~ z9!QrFgAgA?4y?}@!3F6wfU0Ez>okJ%KssScnHa!24WK%i7`Q+>VYV=Xb;4Z0%mC5} zQ_2j{X$aNH4ABX*g$1k=<^mS5PMA^_h)$T}Ss*%Lwy=VA!d$=#)(KO}3egF3JS#*e z%oaAVPM8bWz&c?{*&sS$j%S1DgxSIl)(LX~J6I=7DLX_b%<=3HoiJNCz&c?r-~j7{ zDdm9ZggKrAq7!BdCs-%U1)N}=Fr}OjoiN99LUh7x;R5S~xqu6-6Q-04q7&wLE{IN; zE!<$8Fc)xxb;6W#Lv+F%&kfNDvxNt&6XpUQuuhm#9*9nu<9Q%DVYcvsb;4Z03)Tr! z$_vp6b389ZC(IT;uuhl@_`o`0O8Fo5S=i`3qo|lY!L$MgtRm@UF!oiG;&gLT4`3PW_l94`#f3A056tP|z}5wK2}QW1zwnBzqtI$^em zf_1`NAPUwAQz{D433I$CL?_G^F|baU3&g-WVM@gyI$@3%gXo0WA`aFGbAdQmCrqh0 zL?_Jg;t-uMTO`0bVJ?sW>x3zlfarudUIL;MW{V_PC(H$sV4X0fk`SFR$4f$V!fcTO z>x8*L3ak^RR0^UK=6ETHPM9syV4W}*NP~64luAQ%!W=IR(FwCf2CNh20vWJQm{J*t zPMG6mAUa{T$bxmkTp$b92~#Qy(Ft?BEJP>F7CEp^m|36T-jDdmSzh1jI10xSJNEn3wgO&fcV_;xp=+Z{g1CnHD0O|Pu zAEF2>0wF-+l?)<2?D77=&MaNo49+g$h70^yCuax>a|uNI-ZuU&FXJ#Ryu|Th0gy~V0!U;b z4@3xLl;M(W5#4x~U|*I6iV!<5n4f$aY+B_zQT&y!GrzUmg_75I=)S0T2lq5p&><(F2XSxx2c=L&hE; z18#<(MpCG!3$MGY3#i=#Z)7qvYJyu}(G9LauI>yx3=ABcTrAOz+#s&AYp|=2f`~V3 zylYqpX90+pus~pPbpjWtancqL9^}N;u)qc+Ai%&S5Um`e&kV91)LwJ)arXZIA4wp< z*)Jqo9Z3MBBDzTuWD3Nopyr&jfituTC*UFm_6o?b=!O92;1H1OcsRK@q8kN3T;~91 z&rpQ`XHOS}=!RfduXqL?4h9~G>p@&+Cj(b6h3Ez+Ki?n*9s!UPNGpiz?Bo~fs}SJn z5}^>y2yzF5h-!eds~1zWGKly8e?bOFML{KFCIiTnXmybA5(W`%M^BdsY^p$J6@Z8Y zsM-V(7p?%8U|-$^E^L#t7zzZL85t55NKL|?E|w%LV4s@F#k3@$fFZE}WJz;J4g*7T zM-C%H(gLYTwUd(=CMWTL(|m0rV`6P$B_kI*Lt;TNe<>}1R1#`VSx~p z1z-=r9T?rj9c*9_&k^tF62uVQ#2;*60paj~vUqfp8%MA)LWG?GMLma8u&WQFfIkb^ z2*==1KL!y^P(I@+5Mp6sU`QwcDFC^m03-?a8Yt{DGPAN1IO4(Th2mYk3>ZO?3{ndc z6A^L=^9x~Gz+Iie$j}BdIumRW1GOyzn`aTv0dgB7i4JEJ!Qyav42Lh^sm|bH0{Oxs zJ~O(>izUD#APAAG91YAMxr#Ty*;BzIzoa0iG+m)6wK%`DC^@wl)PaHyng<07@^W#x xgNtZJiAn|mRZzT$$b)h(LjfZwSAZ-BWj#hH!-b1kL=z& Date: Mon, 14 Jul 2025 18:31:43 +0100 Subject: [PATCH 83/97] tests: virt: Allow changes to PPTT test table Allow changes to PPTT test table, preparing for adding identical implementation flags support and for adding a root node for all the system. This is related to both loongarch64 and aarch64. Signed-off-by: Yicong Yang Reviewed-by: Jonathan Cameron Reviewed-by: Zhao Liu Signed-off-by: Alireza Sanaee Message-Id: <20250714173146.511-2-alireza.sanaee@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..5c3ff47748 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/aarch64/virt/PPTT", +"tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt", +"tests/data/acpi/aarch64/virt/PPTT.topology", +"tests/data/acpi/loongarch64/virt/PPTT", +"tests/data/acpi/loongarch64/virt/PPTT.topology", From ec57e4778e3c64d17d57e629a0c37209ff36900b Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 14 Jul 2025 18:31:44 +0100 Subject: [PATCH 84/97] hw/acpi/aml-build: Set identical implementation flag for PPTT processor nodes Per ACPI 6.5 Table 5.158: Processor Structure Flags, the identical implementation flag indicates whether all the children processors of this node share the same identical implementation revision. Currently Linux support parsing this field [1] and maybe used to identify the heterogeneous platform. Since qemu only support homogeneous emulation, set this flag for all the processor node to indicates the facts when building the PPTT table. Node leaf is an exception since spec says this flag should be ignored on leaf nodes by OSPM. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/acpi/pptt.c?h=v6.11-rc1#n810 Signed-off-by: Yicong Yang Reviewed-by: Jonathan Cameron Signed-off-by: Alireza Sanaee Message-Id: <20250714173146.511-3-alireza.sanaee@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index cb817a0f31..9b9be4ea0f 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2172,7 +2172,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, core_id = -1; socket_offset = table_data->len - pptt_start; build_processor_hierarchy_node(table_data, - (1 << 0), /* Physical package */ + (1 << 0) | /* Physical package */ + (1 << 4), /* Identical Implementation */ 0, socket_id, NULL, 0); } @@ -2183,7 +2184,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, core_id = -1; cluster_offset = table_data->len - pptt_start; build_processor_hierarchy_node(table_data, - (0 << 0), /* Not a physical package */ + (0 << 0) | /* Not a physical package */ + (1 << 4), /* Identical Implementation */ socket_offset, cluster_id, NULL, 0); } } else { @@ -2201,7 +2203,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, core_id = cpus->cpus[n].props.core_id; core_offset = table_data->len - pptt_start; build_processor_hierarchy_node(table_data, - (0 << 0), /* Not a physical package */ + (0 << 0) | /* Not a physical package */ + (1 << 4), /* Identical Implementation */ cluster_offset, core_id, NULL, 0); } From 9bf96fc2df494053bcd8697b5c5ad8954bf3510f Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 14 Jul 2025 18:31:45 +0100 Subject: [PATCH 85/97] hw/acpi/aml-build: Build a root node in the PPTT table Currently we build the PPTT starting from the socket node and each socket will be a separate tree. For a multi-socket system it'll be hard for the OS to know the whole system is homogeneous or not (actually we're in the current implementation) since no parent node to telling the identical implementation informentation. Add a root node for indicating this. Signed-off-by: Yicong Yang Reviewed-by: Jonathan Cameron Signed-off-by: Alireza Sanaee Message-Id: <20250714173146.511-4-alireza.sanaee@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 9b9be4ea0f..1e685f982f 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2152,12 +2152,25 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, int64_t socket_id = -1, cluster_id = -1, core_id = -1; uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0; uint32_t pptt_start = table_data->len; + uint32_t root_offset; int n; AcpiTable table = { .sig = "PPTT", .rev = 2, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(&table, table_data); + /* + * Build a root node for all the processor nodes. Otherwise when + * building a multi-socket system each socket tree is separated + * and will be hard for the OS like Linux to know whether the + * system is homogeneous. + */ + root_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (1 << 0) | /* Physical package */ + (1 << 4), /* Identical Implementation */ + 0, 0, NULL, 0); + /* * This works with the assumption that cpus[n].props.*_id has been * sorted from top to down levels in mc->possible_cpu_arch_ids(). @@ -2174,7 +2187,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, build_processor_hierarchy_node(table_data, (1 << 0) | /* Physical package */ (1 << 4), /* Identical Implementation */ - 0, socket_id, NULL, 0); + root_offset, socket_id, NULL, 0); } if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) { From 98f030e7c9b4ac42e886b140899f7ae12ab4f028 Mon Sep 17 00:00:00 2001 From: Alireza Sanaee Date: Mon, 14 Jul 2025 18:31:46 +0100 Subject: [PATCH 86/97] tests: virt: Update expected ACPI tables for virt test Update the ACPI tables according to the acpi aml_build change, also empty bios-tables-test-allowed-diff.h. The disassembled differences between actual and expected PPTT shows below. Only about the root node adding and identification flag set as expected. Diff regarding Loongarch64: /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20230628 (64-bit version) * Copyright (c) 2000 - 2023 Intel Corporation * - * Disassembly of tests/data/acpi/loongarch64/virt/PPTT, Mon Jul 14 16:15:12 2025 + * Disassembly of /tmp/aml-4A0092, Mon Jul 14 16:15:12 2025 * * ACPI Data Table [PPTT] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex) */ [000h 0000 004h] Signature : "PPTT" [Processor Properties Topology Table] -[004h 0004 004h] Table Length : 0000004C +[004h 0004 004h] Table Length : 00000060 [008h 0008 001h] Revision : 02 -[009h 0009 001h] Checksum : A8 +[009h 0009 001h] Checksum : 27 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h] Oem Table ID : "BXPC " [018h 0024 004h] Oem Revision : 00000001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 00000001 [024h 0036 001h] Subtable Type : 00 [Processor Hierarchy Node] [025h 0037 001h] Length : 14 [026h 0038 002h] Reserved : 0000 -[028h 0040 004h] Flags (decoded below) : 00000001 +[028h 0040 004h] Flags (decoded below) : 00000011 Physical package : 1 ACPI Processor ID valid : 0 Processor is a thread : 0 Node is a leaf : 0 - Identical Implementation : 0 + Identical Implementation : 1 [02Ch 0044 004h] Parent : 00000000 [030h 0048 004h] ACPI Processor ID : 00000000 [034h 0052 004h] Private Resource Number : 00000000 [038h 0056 001h] Subtable Type : 00 [Processor Hierarchy Node] [039h 0057 001h] Length : 14 [03Ah 0058 002h] Reserved : 0000 -[03Ch 0060 004h] Flags (decoded below) : 0000000A +[03Ch 0060 004h] Flags (decoded below) : 00000011 + Physical package : 1 + ACPI Processor ID valid : 0 + Processor is a thread : 0 + Node is a leaf : 0 + Identical Implementation : 1 +[040h 0064 004h] Parent : 00000024 +[044h 0068 004h] ACPI Processor ID : 00000000 +[048h 0072 004h] Private Resource Number : 00000000 + +[04Ch 0076 001h] Subtable Type : 00 [Processor Hierarchy Node] +[04Dh 0077 001h] Length : 14 +[04Eh 0078 002h] Reserved : 0000 +[050h 0080 004h] Flags (decoded below) : 0000000A Physical package : 0 ACPI Processor ID valid : 1 Processor is a thread : 0 Node is a leaf : 1 Identical Implementation : 0 -[040h 0064 004h] Parent : 00000024 -[044h 0068 004h] ACPI Processor ID : 00000000 -[048h 0072 004h] Private Resource Number : 00000000 +[054h 0084 004h] Parent : 00000038 +[058h 0088 004h] ACPI Processor ID : 00000000 +[05Ch 0092 004h] Private Resource Number : 00000000 -Raw Table Data: Length 76 (0x4C) +Raw Table Data: Length 96 (0x60) - 0000: 50 50 54 54 4C 00 00 00 02 A8 42 4F 43 48 53 20 // PPTTL.....BOCHS + 0000: 50 50 54 54 60 00 00 00 02 27 42 4F 43 48 53 20 // PPTT`....'BOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC - 0020: 01 00 00 00 00 14 00 00 01 00 00 00 00 00 00 00 // ................ - 0030: 00 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................ - 0040: 24 00 00 00 00 00 00 00 00 00 00 00 // $........... + 0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................ + 0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................ + 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $............... + 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8........... Diff regarding ARM64: /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20200925 (64-bit version) * Copyright (c) 2000 - 2020 Intel Corporation * - * Disassembly of tests/data/acpi/aarch64/virt/PPTT, Thu Apr 24 11:02:39 2025 + * Disassembly of /tmp/aml-E0RF52, Thu Apr 24 11:02:39 2025 * * ACPI Data Table [PPTT] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue */ [000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table] -[004h 0004 4] Table Length : 0000004C +[004h 0004 4] Table Length : 00000060 [008h 0008 1] Revision : 02 -[009h 0009 1] Checksum : A8 +[009h 0009 1] Checksum : 27 [00Ah 0010 6] Oem ID : "BOCHS " [010h 0016 8] Oem Table ID : "BXPC " [018h 0024 4] Oem Revision : 00000001 [01Ch 0028 4] Asl Compiler ID : "BXPC" [020h 0032 4] Asl Compiler Revision : 00000001 [024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node] [025h 0037 1] Length : 14 [026h 0038 2] Reserved : 0000 -[028h 0040 4] Flags (decoded below) : 00000001 +[028h 0040 4] Flags (decoded below) : 00000011 Physical package : 1 ACPI Processor ID valid : 0 Processor is a thread : 0 Node is a leaf : 0 - Identical Implementation : 0 + Identical Implementation : 1 [02Ch 0044 4] Parent : 00000000 [030h 0048 4] ACPI Processor ID : 00000000 [034h 0052 4] Private Resource Number : 00000000 [038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node] [039h 0057 1] Length : 14 [03Ah 0058 2] Reserved : 0000 -[03Ch 0060 4] Flags (decoded below) : 0000000A +[03Ch 0060 4] Flags (decoded below) : 00000011 + Physical package : 1 + ACPI Processor ID valid : 0 + Processor is a thread : 0 + Node is a leaf : 0 + Identical Implementation : 1 +[040h 0064 4] Parent : 00000024 +[044h 0068 4] ACPI Processor ID : 00000000 +[048h 0072 4] Private Resource Number : 00000000 + +[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node] +[04Dh 0077 1] Length : 14 +[04Eh 0078 2] Reserved : 0000 +[050h 0080 4] Flags (decoded below) : 0000000A Physical package : 0 ACPI Processor ID valid : 1 Processor is a thread : 0 Node is a leaf : 1 Identical Implementation : 0 -[040h 0064 4] Parent : 00000024 -[044h 0068 4] ACPI Processor ID : 00000000 -[048h 0072 4] Private Resource Number : 00000000 +[054h 0084 4] Parent : 00000038 +[058h 0088 4] ACPI Processor ID : 00000000 +[05Ch 0092 4] Private Resource Number : 00000000 -Raw Table Data: Length 76 (0x4C) +Raw Table Data: Length 96 (0x60) - 0000: 50 50 54 54 4C 00 00 00 02 A8 42 4F 43 48 53 20 // PPTTL.....BOCHS + 0000: 50 50 54 54 60 00 00 00 02 27 42 4F 43 48 53 20 // PPTT`....'BOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC - 0020: 01 00 00 00 00 14 00 00 01 00 00 00 00 00 00 00 // ................ - 0030: 00 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................ - 0040: 24 00 00 00 00 00 00 00 00 00 00 00 // $........... + 0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................ + 0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................ + 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $............... + 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8........... Signed-off-by: Alireza Sanaee Message-Id: <20250714173146.511-5-alireza.sanaee@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/aarch64/virt/PPTT | Bin 76 -> 96 bytes tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt | Bin 156 -> 176 bytes tests/data/acpi/aarch64/virt/PPTT.topology | Bin 336 -> 356 bytes tests/data/acpi/loongarch64/virt/PPTT | Bin 76 -> 96 bytes tests/data/acpi/loongarch64/virt/PPTT.topology | Bin 176 -> 196 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 ----- 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/aarch64/virt/PPTT b/tests/data/acpi/aarch64/virt/PPTT index 7a1258ecf123555b24462c98ccbb76b4ac1d0c2b..15598a9b8a3cc0cdd50bc1f77c73ae0ba728a272 100644 GIT binary patch literal 96 zcmWFt2nk7GU|?WUck*}k2v%^42yj+VP*7lGU|;~TK{SI11A`y~8i0zaAPb8yFmN$2 JFjydo0RR)W2LS*8 delta 38 lcmYfB;R*-{3GrcIU|?D?kxP!1k%57MVWOijj|zwZ#Q=h<1jzsZ diff --git a/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt b/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt index 4eef303a5b6168c6bc3795c2e2c53f65b4c4cfd4..7b613ddaf4b8cfa13821aa2e835d290077221897 100644 GIT binary patch literal 176 zcmWFt2npH1z`(%7>*Vk35v<@85#X$#prF9Wz`y`vgJ=d31_nU}GyoM-K^7KaVBlh4 jV6ea;1~v;Mhol!-45YUN4%yJ5@Uvn0RUu82>}2A diff --git a/tests/data/acpi/aarch64/virt/PPTT.topology b/tests/data/acpi/aarch64/virt/PPTT.topology index 3fbcae5ff08aaf16fedf4da45e941661d79c1174..6b864f035c9f48845e9a3beb482c5171074864a5 100644 GIT binary patch literal 356 zcmWFt2nk7HWME*L?&R<65v<@85#X$#prF9Wz`y`vgJ=d31_nU}GyoM-K^7KaU=Uzn zV6ea<=7T22$H2glfI|#yCrA!z9!M{;7)b9N1_lNukQxvcVPJrXF@yLZ4Al#A3$k92 o`)+{bVHm3S4FdxM3l=d}Br%v?Wb;7wYA`Y|upy~~iLpb)00?&w0RR91 literal 336 zcmWFt2nh*bWME*baq@Te2v%^42yj+VP*7lGU|;~TK{SI10|S_5KmsBVwhDxTkWeuT z2oFMvFfi~jFfjN)cn}gv3~nxxUSu(l-VO!^1}2D329R4|V$4WlASTEy$a+CyM?eG& rL+!o6z`($QMT`|m48#QKMK%v)uLvUp0~<&ZgrVkv#MnW61_lNI0DKMs diff --git a/tests/data/acpi/loongarch64/virt/PPTT b/tests/data/acpi/loongarch64/virt/PPTT index 7a1258ecf123555b24462c98ccbb76b4ac1d0c2b..15598a9b8a3cc0cdd50bc1f77c73ae0ba728a272 100644 GIT binary patch literal 96 zcmWFt2nk7GU|?WUck*}k2v%^42yj+VP*7lGU|;~TK{SI11A`y~8i0zaAPb8yFmN$2 JFjydo0RR)W2LS*8 delta 38 lcmYfB;R*-{3GrcIU|?D?kxP!1k%57MVWOijj|zwZ#Q=h<1jzsZ diff --git a/tests/data/acpi/loongarch64/virt/PPTT.topology b/tests/data/acpi/loongarch64/virt/PPTT.topology index d91e55b2399d9949dbb8e4c8cf634af1a0e56df4..7fc92984694d2cac7bf867c7fea696e135f8c758 100644 GIT binary patch literal 196 zcmWFt2njjDz`($y<>c?|5v<@85#X$#prF9Wz`y`vgJ=d31_nU}GyoM-K^7KaU=Uzn rV6Z?F<6~f8@WCMlHXkI1q!(EXq_+d)K9Cv^7GYq3i7|ut3=9kan=lFi literal 176 zcmWFt2npH1z`($y@8s|75v<@85#X$#prF9Wz`y`vgJ=d31_m(AfCNM!Y!wIvAw?J% k_!t-%EFe4xi6jO$14%Ek7)Wmk$Sn|^3?O@9V$4u60J3}u0RR91 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 5c3ff47748..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,6 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/aarch64/virt/PPTT", -"tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt", -"tests/data/acpi/aarch64/virt/PPTT.topology", -"tests/data/acpi/loongarch64/virt/PPTT", -"tests/data/acpi/loongarch64/virt/PPTT.topology", From fe63feb7e8f2d62621008fdf7c884f3573de249b Mon Sep 17 00:00:00 2001 From: Fan Ni Date: Mon, 14 Jul 2025 18:44:57 +0100 Subject: [PATCH 87/97] hw/cxl: fix DC extent capacity tracking Per cxl r3.2 Section 9.13.3.3, extent capacity tracking should include extents in different states including added, pending, etc. Before the change, for the in-device extent number tracking purpose, we only have "total_extent_count" defined, which only tracks the number of extents accepted. However, we need to track number of extents in other states also, for now it is extents pending-to-add. To fix that, we introduce a new counter for dynamic capacity "nr_extents_accepted" which explicitly tracks number of the extents accepted by the hosts, and fix "total_extent_count" to include both accepted and pending extents counting. Signed-off-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 26 ++++++++++++++++++-------- hw/mem/cxl_type3.c | 1 + include/hw/cxl/cxl_device.h | 3 ++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 299f232f26..0b615ea37a 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -2750,7 +2750,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd, uint16_t out_pl_len, size; CXLDCExtent *ent; - if (start_extent_id > ct3d->dc.total_extent_count) { + if (start_extent_id > ct3d->dc.nr_extents_accepted) { return CXL_MBOX_INVALID_INPUT; } @@ -2761,7 +2761,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd, out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); stl_le_p(&out->count, record_count); - stl_le_p(&out->total_extents, ct3d->dc.total_extent_count); + stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted); stl_le_p(&out->generation_num, ct3d->dc.ext_list_gen_seq); if (record_count > 0) { @@ -2883,16 +2883,20 @@ void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list, QTAILQ_INSERT_TAIL(list, group, node); } -void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list) +uint32_t cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list) { CXLDCExtent *ent, *ent_next; CXLDCExtentGroup *group = QTAILQ_FIRST(list); + uint32_t extents_deleted = 0; QTAILQ_REMOVE(list, group, node); QTAILQ_FOREACH_SAFE(ent, &group->list, node, ent_next) { cxl_remove_extent_from_extent_list(&group->list, ent); + extents_deleted++; } g_free(group); + + return extents_deleted; } /* @@ -3011,7 +3015,7 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd, CXLUpdateDCExtentListInPl *in = (void *)payload_in; CXLType3Dev *ct3d = CXL_TYPE3(cci->d); CXLDCExtentList *extent_list = &ct3d->dc.extents; - uint32_t i; + uint32_t i, num; uint64_t dpa, len; CXLRetCode ret; @@ -3020,7 +3024,8 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd, } if (in->num_entries_updated == 0) { - cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + ct3d->dc.total_extent_count -= num; return CXL_MBOX_SUCCESS; } @@ -3051,10 +3056,12 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd, cxl_insert_extent_to_extent_list(extent_list, dpa, len, NULL, 0); ct3d->dc.total_extent_count += 1; + ct3d->dc.nr_extents_accepted += 1; ct3_set_region_block_backed(ct3d, dpa, len); } /* Remove the first extent group in the pending list */ - cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + ct3d->dc.total_extent_count -= num; return CXL_MBOX_SUCCESS; } @@ -3160,7 +3167,7 @@ free_and_exit: } *updated_list_size = 0; } else { - *updated_list_size = ct3d->dc.total_extent_count + cnt_delta; + *updated_list_size = ct3d->dc.nr_extents_accepted + cnt_delta; } return ret; @@ -3222,7 +3229,10 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd, ct3_set_region_block_backed(ct3d, ent->start_dpa, ent->len); cxl_remove_extent_from_extent_list(&updated_list, ent); } - ct3d->dc.total_extent_count = updated_list_size; + ct3d->dc.total_extent_count += (updated_list_size - + ct3d->dc.nr_extents_accepted); + + ct3d->dc.nr_extents_accepted = updated_list_size; return CXL_MBOX_SUCCESS; } diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 94e7274912..f283178d88 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -2076,6 +2076,7 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path, } if (group) { cxl_extent_group_list_insert_tail(&dcd->dc.extents_pending, group); + dcd->dc.total_extent_count += num_extents; } /* diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index ed6cd50c67..a151e19da8 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -618,6 +618,7 @@ struct CXLType3Dev { CXLDCExtentList extents; CXLDCExtentGroupList extents_pending; uint32_t total_extent_count; + uint32_t nr_extents_accepted; uint32_t ext_list_gen_seq; uint8_t num_regions; /* 0-8 regions */ @@ -696,7 +697,7 @@ CXLDCExtentGroup *cxl_insert_extent_to_extent_group(CXLDCExtentGroup *group, uint16_t shared_seq); void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list, CXLDCExtentGroup *group); -void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list); +uint32_t cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list); void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, uint64_t len); void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, From 9fde6eb39d8f2354c8f8da91ee6854c60929270f Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:44:58 +0100 Subject: [PATCH 88/97] hw/cxl: mailbox-utils: 0x5600 - FMAPI Get DCD Info FM DCD Management command 0x5600 implemented per CXL 3.2 Spec Section 7.6.7.6.1. Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 59 +++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 4 +++ include/hw/cxl/cxl_device.h | 1 + 3 files changed, 64 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 0b615ea37a..3304048922 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -23,6 +23,7 @@ #include "qemu/uuid.h" #include "system/hostmem.h" #include "qemu/range.h" +#include "qapi/qapi-types-cxl.h" #define CXL_CAPACITY_MULTIPLIER (256 * MiB) #define CXL_DC_EVENT_LOG_SIZE 8 @@ -117,6 +118,8 @@ enum { #define GET_PHYSICAL_PORT_STATE 0x1 TUNNEL = 0x53, #define MANAGEMENT_COMMAND 0x0 + FMAPI_DCD_MGMT = 0x56, + #define GET_DCD_INFO 0x0 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3237,6 +3240,52 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* CXL r3.2 section 7.6.7.6.1: Get DCD Info (Opcode 5600h) */ +static CXLRetCode cmd_fm_get_dcd_info(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t num_hosts; + uint8_t num_regions_supported; + uint8_t rsvd1[2]; + uint16_t supported_add_sel_policy_bitmask; + uint8_t rsvd2[2]; + uint16_t supported_removal_policy_bitmask; + uint8_t sanitize_on_release_bitmask; + uint8_t rsvd3; + uint64_t total_dynamic_capacity; + uint64_t region_blk_size_bitmasks[8]; + } QEMU_PACKED *out = (void *)payload_out; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLDCRegion *region; + int i; + + out->num_hosts = 1; + out->num_regions_supported = ct3d->dc.num_regions; + stw_le_p(&out->supported_add_sel_policy_bitmask, + BIT(CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE)); + stw_le_p(&out->supported_removal_policy_bitmask, + BIT(CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE)); + out->sanitize_on_release_bitmask = 0; + + stq_le_p(&out->total_dynamic_capacity, + ct3d->dc.total_capacity / CXL_CAPACITY_MULTIPLIER); + + for (i = 0; i < ct3d->dc.num_regions; i++) { + region = &ct3d->dc.regions[i]; + memcpy(&out->region_blk_size_bitmasks[i], + ®ion->supported_blk_size_bitmask, + sizeof(out->region_blk_size_bitmasks[i])); + } + + *len_out = sizeof(*out); + return CXL_MBOX_SUCCESS; +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3350,6 +3399,11 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = { cmd_tunnel_management_cmd, ~0, 0 }, }; +static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { + [FMAPI_DCD_MGMT][GET_DCD_INFO] = { "GET_DCD_INFO", + cmd_fm_get_dcd_info, 0, 0 }, +}; + /* * While the command is executing in the background, the device should * update the percentage complete in the Background Command Status Register @@ -3624,7 +3678,12 @@ void cxl_initialize_t3_fm_owned_ld_mctpcci(CXLCCI *cci, DeviceState *d, DeviceState *intf, size_t payload_max) { + CXLType3Dev *ct3d = CXL_TYPE3(d); + cxl_copy_cci_commands(cci, cxl_cmd_set_t3_fm_owned_ld_mctp); + if (ct3d->dc.num_regions) { + cxl_copy_cci_commands(cci, cxl_cmd_set_fm_dcd); + } cci->d = d; cci->intf = intf; cxl_init_cci(cci, payload_max); diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index f283178d88..d898cfd617 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -8,6 +8,7 @@ * * SPDX-License-Identifier: GPL-v2-only */ +#include #include "qemu/osdep.h" #include "qemu/units.h" @@ -634,6 +635,8 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp) uint64_t region_len; uint64_t decode_len; uint64_t blk_size = 2 * MiB; + /* Only 1 block size is supported for now. */ + uint64_t supported_blk_size_bitmask = blk_size; CXLDCRegion *region; MemoryRegion *mr; uint64_t dc_size; @@ -679,6 +682,7 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp) .block_size = blk_size, /* dsmad_handle set when creating CDAT table entries */ .flags = 0, + .supported_blk_size_bitmask = supported_blk_size_bitmask, }; ct3d->dc.total_capacity += region->len; region->blk_bitmap = bitmap_new(region->len / region->block_size); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index a151e19da8..7eade9cf8a 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -530,6 +530,7 @@ typedef struct CXLDCRegion { uint32_t dsmadhandle; uint8_t flags; unsigned long *blk_bitmap; + uint64_t supported_blk_size_bitmask; } CXLDCRegion; typedef struct CXLSetFeatureInfo { From 3d1607cc299f40d0f0749ce808e9776196f7ef85 Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:44:59 +0100 Subject: [PATCH 89/97] hw/mem: cxl_type3: Add dsmas_flags to CXLDCRegion struct Add booleans to DC Region struct to represent dsmas flags (defined in CDAT) in preparation for the next command, which returns the flags in the next mailbox command 0x5601. Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 8 +++++++- include/hw/cxl/cxl_device.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index d898cfd617..6b0889c9ae 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -226,10 +226,16 @@ static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv) * future. */ for (i = 0; i < ct3d->dc.num_regions; i++) { + ct3d->dc.regions[i].nonvolatile = false; + ct3d->dc.regions[i].sharable = false; + ct3d->dc.regions[i].hw_managed_coherency = false; + ct3d->dc.regions[i].ic_specific_dc_management = false; + ct3d->dc.regions[i].rdonly = false; ct3_build_cdat_entries_for_mr(&(table[cur_ent]), dsmad_handle++, ct3d->dc.regions[i].len, - false, true, region_base); + ct3d->dc.regions[i].nonvolatile, + true, region_base); ct3d->dc.regions[i].dsmadhandle = dsmad_handle - 1; cur_ent += CT3_CDAT_NUM_ENTRIES; diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 7eade9cf8a..7e0a66906f 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -133,6 +133,15 @@ typedef enum { CXL_MBOX_MAX = 0x20 } CXLRetCode; +/* r3.2 Section 7.6.7.6.2: Table 7-66: DSMAS Flags Bits */ +typedef enum { + CXL_DSMAS_FLAGS_NONVOLATILE = 2, + CXL_DSMAS_FLAGS_SHARABLE = 3, + CXL_DSMAS_FLAGS_HW_MANAGED_COHERENCY = 4, + CXL_DSMAS_FLAGS_IC_SPECIFIC_DC_MANAGEMENT = 5, + CXL_DSMAS_FLAGS_RDONLY = 6, +} CXLDSMASFlags; + typedef struct CXLCCI CXLCCI; typedef struct cxl_device_state CXLDeviceState; struct cxl_cmd; @@ -531,6 +540,12 @@ typedef struct CXLDCRegion { uint8_t flags; unsigned long *blk_bitmap; uint64_t supported_blk_size_bitmask; + /* Following bools make up dsmas flags, as defined in the CDAT */ + bool nonvolatile; + bool sharable; + bool hw_managed_coherency; + bool ic_specific_dc_management; + bool rdonly; } CXLDCRegion; typedef struct CXLSetFeatureInfo { From a8f1cbbbcad6e1b2211a201ad95d68c451a990e3 Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:00 +0100 Subject: [PATCH 90/97] hw/cxl: mailbox-utils: 0x5601 - FMAPI Get Host Region Config FM DCD Management command 0x5601 implemented per CXL r3.2 Spec Section 7.6.7.6.2 Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 106 +++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 3304048922..bf1710b251 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -120,6 +120,7 @@ enum { #define MANAGEMENT_COMMAND 0x0 FMAPI_DCD_MGMT = 0x56, #define GET_DCD_INFO 0x0 + #define GET_HOST_DC_REGION_CONFIG 0x1 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3286,6 +3287,109 @@ static CXLRetCode cmd_fm_get_dcd_info(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +static void build_dsmas_flags(uint8_t *flags, CXLDCRegion *region) +{ + *flags = 0; + + if (region->nonvolatile) { + *flags |= BIT(CXL_DSMAS_FLAGS_NONVOLATILE); + } + if (region->sharable) { + *flags |= BIT(CXL_DSMAS_FLAGS_SHARABLE); + } + if (region->hw_managed_coherency) { + *flags |= BIT(CXL_DSMAS_FLAGS_HW_MANAGED_COHERENCY); + } + if (region->ic_specific_dc_management) { + *flags |= BIT(CXL_DSMAS_FLAGS_IC_SPECIFIC_DC_MANAGEMENT); + } + if (region->rdonly) { + *flags |= BIT(CXL_DSMAS_FLAGS_RDONLY); + } +} + +/* + * CXL r3.2 section 7.6.7.6.2: + * Get Host DC Region Configuration (Opcode 5601h) + */ +static CXLRetCode cmd_fm_get_host_dc_region_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t region_cnt; + uint8_t start_rid; + } QEMU_PACKED *in = (void *)payload_in; + struct { + uint16_t host_id; + uint8_t num_regions; + uint8_t regions_returned; + struct { + uint64_t base; + uint64_t decode_len; + uint64_t region_len; + uint64_t block_size; + uint8_t flags; + uint8_t rsvd1[3]; + uint8_t sanitize; + uint8_t rsvd2[3]; + } QEMU_PACKED records[]; + } QEMU_PACKED *out = (void *)payload_out; + struct { + uint32_t num_extents_supported; + uint32_t num_extents_available; + uint32_t num_tags_supported; + uint32_t num_tags_available; + } QEMU_PACKED *extra_out; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + uint16_t record_count, out_pl_len, i; + + if (in->start_rid >= ct3d->dc.num_regions) { + return CXL_MBOX_INVALID_INPUT; + } + record_count = MIN(ct3d->dc.num_regions - in->start_rid, in->region_cnt); + + out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); + extra_out = (void *)out + out_pl_len; + out_pl_len += sizeof(*extra_out); + + assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE); + + stw_le_p(&out->host_id, 0); + out->num_regions = ct3d->dc.num_regions; + out->regions_returned = record_count; + + for (i = 0; i < record_count; i++) { + stq_le_p(&out->records[i].base, + ct3d->dc.regions[in->start_rid + i].base); + stq_le_p(&out->records[i].decode_len, + ct3d->dc.regions[in->start_rid + i].decode_len / + CXL_CAPACITY_MULTIPLIER); + stq_le_p(&out->records[i].region_len, + ct3d->dc.regions[in->start_rid + i].len); + stq_le_p(&out->records[i].block_size, + ct3d->dc.regions[in->start_rid + i].block_size); + build_dsmas_flags(&out->records[i].flags, + &ct3d->dc.regions[in->start_rid + i]); + /* Sanitize is bit 0 of flags. */ + out->records[i].sanitize = + ct3d->dc.regions[in->start_rid + i].flags & BIT(0); + } + + stl_le_p(&extra_out->num_extents_supported, CXL_NUM_EXTENTS_SUPPORTED); + stl_le_p(&extra_out->num_extents_available, CXL_NUM_EXTENTS_SUPPORTED - + ct3d->dc.total_extent_count); + stl_le_p(&extra_out->num_tags_supported, CXL_NUM_TAGS_SUPPORTED); + stl_le_p(&extra_out->num_tags_available, CXL_NUM_TAGS_SUPPORTED); + + *len_out = out_pl_len; + return CXL_MBOX_SUCCESS; +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3402,6 +3506,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = { static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { [FMAPI_DCD_MGMT][GET_DCD_INFO] = { "GET_DCD_INFO", cmd_fm_get_dcd_info, 0, 0 }, + [FMAPI_DCD_MGMT][GET_HOST_DC_REGION_CONFIG] = { "GET_HOST_DC_REGION_CONFIG", + cmd_fm_get_host_dc_region_config, 4, 0 }, }; /* From 0686f160b767615279ca39cfebf77c0b2e67816d Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:01 +0100 Subject: [PATCH 91/97] hw/cxl: Move definition for dynamic_capacity_uuid and enum for DC event types to header Move definition/enum to cxl_events.h for shared use in next patch Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-6-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 15 --------------- include/hw/cxl/cxl_events.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 6b0889c9ae..52d3910ed9 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1876,21 +1876,6 @@ void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log, } } -/* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */ -static const QemuUUID dynamic_capacity_uuid = { - .data = UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f, - 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a), -}; - -typedef enum CXLDCEventType { - DC_EVENT_ADD_CAPACITY = 0x0, - DC_EVENT_RELEASE_CAPACITY = 0x1, - DC_EVENT_FORCED_RELEASE_CAPACITY = 0x2, - DC_EVENT_REGION_CONFIG_UPDATED = 0x3, - DC_EVENT_ADD_CAPACITY_RSP = 0x4, - DC_EVENT_CAPACITY_RELEASED = 0x5, -} CXLDCEventType; - /* * Check whether the range [dpa, dpa + len - 1] has overlaps with extents in * the list. diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index 38cadaa0f3..758b075a64 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -184,4 +184,19 @@ typedef struct CXLEventDynamicCapacity { uint32_t tags_avail; } QEMU_PACKED CXLEventDynamicCapacity; +/* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */ +static const QemuUUID dynamic_capacity_uuid = { + .data = UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f, + 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a), +}; + +typedef enum CXLDCEventType { + DC_EVENT_ADD_CAPACITY = 0x0, + DC_EVENT_RELEASE_CAPACITY = 0x1, + DC_EVENT_FORCED_RELEASE_CAPACITY = 0x2, + DC_EVENT_REGION_CONFIG_UPDATED = 0x3, + DC_EVENT_ADD_CAPACITY_RSP = 0x4, + DC_EVENT_CAPACITY_RELEASED = 0x5, +} CXLDCEventType; + #endif /* CXL_EVENTS_H */ From 69798d000b95a147f73dfce8c80cff92aa929dcb Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:02 +0100 Subject: [PATCH 92/97] hw/mem: cxl_type3: Add DC Region bitmap lock Add a lock on the bitmap of each CXLDCRegion in preparation for the next patch which implements FMAPI Set DC Region Configuration. This command can modify the block size, which means the region's bitmap must be updated accordingly. The lock becomes necessary when commands that add/release extents (meaning they update the bitmap too) are enabled on a different CCI than the CCI on which the FMAPI commands are enabled. Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 4 ++++ include/hw/cxl/cxl_device.h | 1 + 2 files changed, 5 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 52d3910ed9..a7a1857a0c 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -692,6 +692,7 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp) }; ct3d->dc.total_capacity += region->len; region->blk_bitmap = bitmap_new(region->len / region->block_size); + qemu_mutex_init(®ion->bitmap_lock); } QTAILQ_INIT(&ct3d->dc.extents); QTAILQ_INIT(&ct3d->dc.extents_pending); @@ -1020,6 +1021,7 @@ void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, return; } + QEMU_LOCK_GUARD(®ion->bitmap_lock); bitmap_set(region->blk_bitmap, (dpa - region->base) / region->block_size, len / region->block_size); } @@ -1046,6 +1048,7 @@ bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, * if bits between [dpa, dpa + len) are all 1s, meaning the DPA range is * backed with DC extents, return true; else return false. */ + QEMU_LOCK_GUARD(®ion->bitmap_lock); return find_next_zero_bit(region->blk_bitmap, nr + nbits, nr) == nr + nbits; } @@ -1067,6 +1070,7 @@ void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, nr = (dpa - region->base) / region->block_size; nbits = len / region->block_size; + QEMU_LOCK_GUARD(®ion->bitmap_lock); bitmap_clear(region->blk_bitmap, nr, nbits); } diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 7e0a66906f..42ae5b7479 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -540,6 +540,7 @@ typedef struct CXLDCRegion { uint8_t flags; unsigned long *blk_bitmap; uint64_t supported_blk_size_bitmask; + QemuMutex bitmap_lock; /* Following bools make up dsmas flags, as defined in the CDAT */ bool nonvolatile; bool sharable; From 1befc7bde30d2e09f20a44584aaefdfa31f60074 Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:03 +0100 Subject: [PATCH 93/97] hw/cxl: mailbox-utils: 0x5602 - FMAPI Set DC Region Config FM DCD Management command 0x5602 implemented per CXL r3.2 Spec Section 7.6.7.6.3 Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-8-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 87 ++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 6 +-- include/hw/cxl/cxl_device.h | 3 ++ include/hw/cxl/cxl_mailbox.h | 6 +++ 4 files changed, 99 insertions(+), 3 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index bf1710b251..b4a0f7d664 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -18,6 +18,7 @@ #include "hw/pci/pci.h" #include "hw/pci-bridge/cxl_upstream_port.h" #include "qemu/cutils.h" +#include "qemu/host-utils.h" #include "qemu/log.h" #include "qemu/units.h" #include "qemu/uuid.h" @@ -121,6 +122,7 @@ enum { FMAPI_DCD_MGMT = 0x56, #define GET_DCD_INFO 0x0 #define GET_HOST_DC_REGION_CONFIG 0x1 + #define SET_DC_REGION_CONFIG 0x2 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3390,6 +3392,84 @@ static CXLRetCode cmd_fm_get_host_dc_region_config(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* CXL r3.2 section 7.6.7.6.3: Set Host DC Region Configuration (Opcode 5602) */ +static CXLRetCode cmd_fm_set_dc_region_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t reg_id; + uint8_t rsvd[3]; + uint64_t block_sz; + uint8_t flags; + uint8_t rsvd2[3]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLEventDynamicCapacity dcEvent = {}; + CXLDCRegion *region = &ct3d->dc.regions[in->reg_id]; + + /* + * CXL r3.2 7.6.7.6.3: Set DC Region Configuration + * This command shall fail with Unsupported when the Sanitize on Release + * field does not match the region’s configuration... and the device + * does not support reconfiguration of the Sanitize on Release setting. + * + * Currently not reconfigurable, so always fail if sanitize bit (bit 0) + * doesn't match. + */ + if ((in->flags & 0x1) != (region->flags & 0x1)) { + return CXL_MBOX_UNSUPPORTED; + } + + if (in->reg_id >= DCD_MAX_NUM_REGION) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Check that no extents are in the region being reconfigured */ + if (!bitmap_empty(region->blk_bitmap, region->len / region->block_size)) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Check that new block size is supported */ + if (!is_power_of_2(in->block_sz) || + !(in->block_sz & region->supported_blk_size_bitmask)) { + return CXL_MBOX_INVALID_INPUT; + } + + /* Return success if new block size == current block size */ + if (in->block_sz == region->block_size) { + return CXL_MBOX_SUCCESS; + } + + /* Free bitmap and create new one for new block size. */ + qemu_mutex_lock(®ion->bitmap_lock); + g_free(region->blk_bitmap); + region->blk_bitmap = bitmap_new(region->len / in->block_sz); + qemu_mutex_unlock(®ion->bitmap_lock); + region->block_size = in->block_sz; + + /* Create event record and insert into event log */ + cxl_assign_event_header(&dcEvent.hdr, + &dynamic_capacity_uuid, + (1 << CXL_EVENT_TYPE_INFO), + sizeof(dcEvent), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + dcEvent.type = DC_EVENT_REGION_CONFIG_UPDATED; + dcEvent.validity_flags = 1; + dcEvent.host_id = 0; + dcEvent.updated_region_id = in->reg_id; + + if (cxl_event_insert(&ct3d->cxl_dstate, + CXL_EVENT_TYPE_DYNAMIC_CAP, + (CXLEventRecordRaw *)&dcEvent)) { + cxl_event_irq_assert(ct3d); + } + return CXL_MBOX_SUCCESS; +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3508,6 +3588,13 @@ static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { cmd_fm_get_dcd_info, 0, 0 }, [FMAPI_DCD_MGMT][GET_HOST_DC_REGION_CONFIG] = { "GET_HOST_DC_REGION_CONFIG", cmd_fm_get_host_dc_region_config, 4, 0 }, + [FMAPI_DCD_MGMT][SET_DC_REGION_CONFIG] = { "SET_DC_REGION_CONFIG", + cmd_fm_set_dc_region_config, 16, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, }; /* diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index a7a1857a0c..4a45b4510e 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1590,9 +1590,9 @@ void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type, pcie_aer_inject_error(PCI_DEVICE(obj), &err); } -static void cxl_assign_event_header(CXLEventRecordHdr *hdr, - const QemuUUID *uuid, uint32_t flags, - uint8_t length, uint64_t timestamp) +void cxl_assign_event_header(CXLEventRecordHdr *hdr, + const QemuUUID *uuid, uint32_t flags, + uint8_t length, uint64_t timestamp) { st24_le_p(&hdr->flags, flags); hdr->length = length; diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 42ae5b7479..c836fc17f0 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -721,4 +721,7 @@ void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, uint64_t len); bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, uint64_t len); +void cxl_assign_event_header(CXLEventRecordHdr *hdr, + const QemuUUID *uuid, uint32_t flags, + uint8_t length, uint64_t timestamp); #endif diff --git a/include/hw/cxl/cxl_mailbox.h b/include/hw/cxl/cxl_mailbox.h index 9008402d1c..a05d7cb5b7 100644 --- a/include/hw/cxl/cxl_mailbox.h +++ b/include/hw/cxl/cxl_mailbox.h @@ -8,6 +8,7 @@ #ifndef CXL_MAILBOX_H #define CXL_MAILBOX_H +#define CXL_MBOX_CONFIG_CHANGE_COLD_RESET (1) #define CXL_MBOX_IMMEDIATE_CONFIG_CHANGE (1 << 1) #define CXL_MBOX_IMMEDIATE_DATA_CHANGE (1 << 2) #define CXL_MBOX_IMMEDIATE_POLICY_CHANGE (1 << 3) @@ -15,5 +16,10 @@ #define CXL_MBOX_SECURITY_STATE_CHANGE (1 << 5) #define CXL_MBOX_BACKGROUND_OPERATION (1 << 6) #define CXL_MBOX_BACKGROUND_OPERATION_ABORT (1 << 7) +#define CXL_MBOX_SECONDARY_MBOX_SUPPORTED (1 << 8) +#define CXL_MBOX_REQUEST_ABORT_BACKGROUND_OP_SUPPORTED (1 << 9) +#define CXL_MBOX_CEL_10_TO_11_VALID (1 << 10) +#define CXL_MBOX_CONFIG_CHANGE_CONV_RESET (1 << 11) +#define CXL_MBOX_CONFIG_CHANGE_CXL_RESET (1 << 12) #endif From 21af9a917eca69996891dcbb93edcb6c5c53e52c Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:04 +0100 Subject: [PATCH 94/97] hw/cxl: mailbox-utils: 0x5603 - FMAPI Get DC Region Extent Lists FM DCD Management command 0x5603 implemented per CXL r3.2 Spec Section 7.6.7.6.4 Very similar to previously implemented command 0x4801. Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-9-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index b4a0f7d664..4b0fdbbdd8 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -123,6 +123,7 @@ enum { #define GET_DCD_INFO 0x0 #define GET_HOST_DC_REGION_CONFIG 0x1 #define SET_DC_REGION_CONFIG 0x2 + #define GET_DC_REGION_EXTENT_LIST 0x3 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3470,6 +3471,79 @@ static CXLRetCode cmd_fm_set_dc_region_config(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* CXL r3.2 section 7.6.7.6.4: Get DC Region Extent Lists (Opcode 5603h) */ +static CXLRetCode cmd_fm_get_dc_region_extent_list(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t rsvd[2]; + uint32_t extent_cnt; + uint32_t start_extent_id; + } QEMU_PACKED *in = (void *)payload_in; + struct { + uint16_t host_id; + uint8_t rsvd[2]; + uint32_t start_extent_id; + uint32_t extents_returned; + uint32_t total_extents; + uint32_t list_generation_num; + uint8_t rsvd2[4]; + CXLDCExtentRaw records[]; + } QEMU_PACKED *out = (void *)payload_out; + QEMU_BUILD_BUG_ON(sizeof(*in) != 0xc); + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLDCExtent *ent; + CXLDCExtentRaw *out_rec; + uint16_t record_count = 0, record_done = 0, i = 0; + uint16_t out_pl_len, max_size; + + if (in->host_id != 0) { + return CXL_MBOX_INVALID_INPUT; + } + + if (in->start_extent_id > ct3d->dc.nr_extents_accepted) { + return CXL_MBOX_INVALID_INPUT; + } + + record_count = MIN(in->extent_cnt, + ct3d->dc.nr_extents_accepted - in->start_extent_id); + max_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE - sizeof(*out); + record_count = MIN(record_count, max_size / sizeof(out->records[0])); + out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); + + stw_le_p(&out->host_id, in->host_id); + stl_le_p(&out->start_extent_id, in->start_extent_id); + stl_le_p(&out->extents_returned, record_count); + stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted); + stl_le_p(&out->list_generation_num, ct3d->dc.ext_list_gen_seq); + + if (record_count > 0) { + QTAILQ_FOREACH(ent, &ct3d->dc.extents, node) { + if (i++ < in->start_extent_id) { + continue; + } + out_rec = &out->records[record_done]; + stq_le_p(&out_rec->start_dpa, ent->start_dpa); + stq_le_p(&out_rec->len, ent->len); + memcpy(&out_rec->tag, ent->tag, 0x10); + stw_le_p(&out_rec->shared_seq, ent->shared_seq); + + record_done++; + if (record_done == record_count) { + break; + } + } + } + + *len_out = out_pl_len; + return CXL_MBOX_SUCCESS; +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3595,6 +3669,8 @@ static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { CXL_MBOX_CONFIG_CHANGE_CXL_RESET | CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, + [FMAPI_DCD_MGMT][GET_DC_REGION_EXTENT_LIST] = { "GET_DC_REGION_EXTENT_LIST", + cmd_fm_get_dc_region_extent_list, 12, 0 }, }; /* From 0a362772e0cff8745d0bda73757ba4c7cfbbc841 Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:05 +0100 Subject: [PATCH 95/97] hw/cxl: Create helper function to create DC Event Records from extents Prepatory patch for following FMAPI Add/Release Patches. Refactors part of qmp_cxl_process_dynamic_capacity_prescriptive() into a helper function to create DC Event Records and insert in the event log. Moves definition for CXL_NUM_EXTENTS_SUPPORTED to cxl.h so it can be accessed by cxl-mailbox-utils.c and cxl-events.c, where the helper function is defined. Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-10-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-events.c | 38 +++++++++++++++++++++++++++++++++++++ hw/cxl/cxl-mailbox-utils.c | 1 - hw/mem/cxl_type3.c | 37 +----------------------------------- include/hw/cxl/cxl.h | 1 + include/hw/cxl/cxl_device.h | 4 ++++ 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c index f90470930d..7583dd9162 100644 --- a/hw/cxl/cxl-events.c +++ b/hw/cxl/cxl-events.c @@ -258,3 +258,41 @@ void cxl_event_irq_assert(CXLType3Dev *ct3d) } } } + +void cxl_create_dc_event_records_for_extents(CXLType3Dev *ct3d, + CXLDCEventType type, + CXLDCExtentRaw extents[], + uint32_t ext_count) +{ + CXLEventDynamicCapacity event_rec = {}; + int i; + + cxl_assign_event_header(&event_rec.hdr, + &dynamic_capacity_uuid, + (1 << CXL_EVENT_TYPE_INFO), + sizeof(event_rec), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + event_rec.type = type; + event_rec.validity_flags = 1; + event_rec.host_id = 0; + event_rec.updated_region_id = 0; + event_rec.extents_avail = CXL_NUM_EXTENTS_SUPPORTED - + ct3d->dc.total_extent_count; + + for (i = 0; i < ext_count; i++) { + memcpy(&event_rec.dynamic_capacity_extent, + &extents[i], + sizeof(CXLDCExtentRaw)); + event_rec.flags = 0; + if (i < ext_count - 1) { + /* Set "More" flag */ + event_rec.flags |= BIT(0); + } + + if (cxl_event_insert(&ct3d->cxl_dstate, + CXL_EVENT_TYPE_DYNAMIC_CAP, + (CXLEventRecordRaw *)&event_rec)) { + cxl_event_irq_assert(ct3d); + } + } +} diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 4b0fdbbdd8..b6f30e8689 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -28,7 +28,6 @@ #define CXL_CAPACITY_MULTIPLIER (256 * MiB) #define CXL_DC_EVENT_LOG_SIZE 8 -#define CXL_NUM_EXTENTS_SUPPORTED 512 #define CXL_NUM_TAGS_SUPPORTED 0 #define CXL_ALERTS_LIFE_USED_WARN_THRESH (1 << 0) #define CXL_ALERTS_OVER_TEMP_WARN_THRESH (1 << 1) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 4a45b4510e..4e975b1a42 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1957,15 +1957,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path, CxlDynamicCapacityExtentList *records, Error **errp) { Object *obj; - CXLEventDynamicCapacity dCap = {}; - CXLEventRecordHdr *hdr = &dCap.hdr; CXLType3Dev *dcd; - uint8_t flags = 1 << CXL_EVENT_TYPE_INFO; uint32_t num_extents = 0; CxlDynamicCapacityExtentList *list; CXLDCExtentGroup *group = NULL; g_autofree CXLDCExtentRaw *extents = NULL; - uint8_t enc_log = CXL_EVENT_TYPE_DYNAMIC_CAP; uint64_t dpa, offset, len, block_size; g_autofree unsigned long *blk_bitmap = NULL; int i; @@ -2078,38 +2074,7 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path, dcd->dc.total_extent_count += num_extents; } - /* - * CXL r3.1 section 8.2.9.2.1.6: Dynamic Capacity Event Record - * - * All Dynamic Capacity event records shall set the Event Record Severity - * field in the Common Event Record Format to Informational Event. All - * Dynamic Capacity related events shall be logged in the Dynamic Capacity - * Event Log. - */ - cxl_assign_event_header(hdr, &dynamic_capacity_uuid, flags, sizeof(dCap), - cxl_device_get_timestamp(&dcd->cxl_dstate)); - - dCap.type = type; - /* FIXME: for now, validity flag is cleared */ - dCap.validity_flags = 0; - stw_le_p(&dCap.host_id, hid); - /* only valid for DC_REGION_CONFIG_UPDATED event */ - dCap.updated_region_id = 0; - for (i = 0; i < num_extents; i++) { - memcpy(&dCap.dynamic_capacity_extent, &extents[i], - sizeof(CXLDCExtentRaw)); - - dCap.flags = 0; - if (i < num_extents - 1) { - /* Set "More" flag */ - dCap.flags |= BIT(0); - } - - if (cxl_event_insert(&dcd->cxl_dstate, enc_log, - (CXLEventRecordRaw *)&dCap)) { - cxl_event_irq_assert(dcd); - } - } + cxl_create_dc_event_records_for_extents(dcd, type, extents, num_extents); } void qmp_cxl_add_dynamic_capacity(const char *path, uint16_t host_id, diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index de66ab8c35..998f495a98 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -23,6 +23,7 @@ #define CXL_DEVICE_REG_BAR_IDX 2 #define CXL_WINDOW_MAX 10 +#define CXL_NUM_EXTENTS_SUPPORTED 512 typedef struct PXBCXLDev PXBCXLDev; diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index c836fc17f0..71a5834c3d 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -724,4 +724,8 @@ bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa, void cxl_assign_event_header(CXLEventRecordHdr *hdr, const QemuUUID *uuid, uint32_t flags, uint8_t length, uint64_t timestamp); +void cxl_create_dc_event_records_for_extents(CXLType3Dev *ct3d, + CXLDCEventType type, + CXLDCExtentRaw extents[], + uint32_t ext_count); #endif From 42cbc937d4f6502b398674e38e393f354db52c4c Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:06 +0100 Subject: [PATCH 96/97] hw/cxl: mailbox-utils: 0x5604 - FMAPI Initiate DC Add FM DCD Management command 0x5604 implemented per CXL r3.2 Spec Section 7.6.7.6.5 Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-11-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 109 ++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 8 +-- include/hw/cxl/cxl_device.h | 4 ++ 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index b6f30e8689..5d08525529 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -123,6 +123,7 @@ enum { #define GET_HOST_DC_REGION_CONFIG 0x1 #define SET_DC_REGION_CONFIG 0x2 #define GET_DC_REGION_EXTENT_LIST 0x3 + #define INITIATE_DC_ADD 0x4 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3543,6 +3544,107 @@ static CXLRetCode cmd_fm_get_dc_region_extent_list(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* + * Helper function to convert CXLDCExtentRaw to CXLUpdateDCExtentListInPl + * in order to reuse cxl_detect_malformed_extent_list() function which accepts + * CXLUpdateDCExtentListInPl as a parameter. + */ +static void convert_raw_extents(CXLDCExtentRaw raw_extents[], + CXLUpdateDCExtentListInPl *extent_list, + int count) +{ + int i; + + extent_list->num_entries_updated = count; + + for (i = 0; i < count; i++) { + extent_list->updated_entries[i].start_dpa = raw_extents[i].start_dpa; + extent_list->updated_entries[i].len = raw_extents[i].len; + } +} + +/* CXL r3.2 Section 7.6.7.6.5: Initiate Dynamic Capacity Add (Opcode 5604h) */ +static CXLRetCode cmd_fm_initiate_dc_add(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t selection_policy; + uint8_t reg_num; + uint64_t length; + uint8_t tag[0x10]; + uint32_t ext_count; + CXLDCExtentRaw extents[]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + int i, rc; + + switch (in->selection_policy) { + case CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE: { + /* Adding extents exceeds device's extent tracking ability. */ + if (in->ext_count + ct3d->dc.total_extent_count > + CXL_NUM_EXTENTS_SUPPORTED) { + return CXL_MBOX_RESOURCES_EXHAUSTED; + } + + g_autofree CXLUpdateDCExtentListInPl *list = + g_malloc0(sizeof(*list) + + in->ext_count * sizeof(*list->updated_entries)); + + convert_raw_extents(in->extents, list, in->ext_count); + rc = cxl_detect_malformed_extent_list(ct3d, list); + + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw *ext = &in->extents[i]; + + /* Check requested extents do not overlap with pending ones. */ + if (cxl_extent_groups_overlaps_dpa_range(&ct3d->dc.extents_pending, + ext->start_dpa, + ext->len)) { + return CXL_MBOX_INVALID_EXTENT_LIST; + } + /* Check requested extents do not overlap with existing ones. */ + if (cxl_extents_overlaps_dpa_range(&ct3d->dc.extents, + ext->start_dpa, + ext->len)) { + return CXL_MBOX_INVALID_EXTENT_LIST; + } + } + + if (rc) { + return rc; + } + + CXLDCExtentGroup *group = NULL; + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw *ext = &in->extents[i]; + + group = cxl_insert_extent_to_extent_group(group, ext->start_dpa, + ext->len, ext->tag, + ext->shared_seq); + } + + cxl_extent_group_list_insert_tail(&ct3d->dc.extents_pending, group); + ct3d->dc.total_extent_count += in->ext_count; + cxl_create_dc_event_records_for_extents(ct3d, + DC_EVENT_ADD_CAPACITY, + in->extents, + in->ext_count); + + return CXL_MBOX_SUCCESS; + } + default: { + qemu_log_mask(LOG_UNIMP, + "CXL extent selection policy not supported.\n"); + return CXL_MBOX_INVALID_INPUT; + } + } +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3670,6 +3772,13 @@ static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, [FMAPI_DCD_MGMT][GET_DC_REGION_EXTENT_LIST] = { "GET_DC_REGION_EXTENT_LIST", cmd_fm_get_dc_region_extent_list, 12, 0 }, + [FMAPI_DCD_MGMT][INITIATE_DC_ADD] = { "INIT_DC_ADD", + cmd_fm_initiate_dc_add, ~0, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, }; /* diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 4e975b1a42..be609ff9d0 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1885,8 +1885,8 @@ void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log, * the list. * Return value: return true if has overlaps; otherwise, return false */ -static bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list, - uint64_t dpa, uint64_t len) +bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list, + uint64_t dpa, uint64_t len) { CXLDCExtent *ent; Range range1, range2; @@ -1931,8 +1931,8 @@ bool cxl_extents_contains_dpa_range(CXLDCExtentList *list, return false; } -static bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list, - uint64_t dpa, uint64_t len) +bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list, + uint64_t dpa, uint64_t len) { CXLDCExtentGroup *group; diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 71a5834c3d..89411c8093 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -728,4 +728,8 @@ void cxl_create_dc_event_records_for_extents(CXLType3Dev *ct3d, CXLDCEventType type, CXLDCExtentRaw extents[], uint32_t ext_count); +bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list, + uint64_t dpa, uint64_t len); +bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list, + uint64_t dpa, uint64_t len); #endif From fdd48ce20ce125cc992dfaace925f1bfae3dfdc1 Mon Sep 17 00:00:00 2001 From: Anisa Su Date: Mon, 14 Jul 2025 18:45:07 +0100 Subject: [PATCH 97/97] hw/cxl: mailbox-utils: 0x5605 - FMAPI Initiate DC Release FM DCD Management command 0x5605 implemented per CXL r3.2 Spec Section 7.6.7.6.6 Reviewed-by: Fan Ni Signed-off-by: Anisa Su Signed-off-by: Jonathan Cameron Message-Id: <20250714174509.1984430-12-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 5d08525529..68c7cc9891 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -124,6 +124,7 @@ enum { #define SET_DC_REGION_CONFIG 0x2 #define GET_DC_REGION_EXTENT_LIST 0x3 #define INITIATE_DC_ADD 0x4 + #define INITIATE_DC_RELEASE 0x5 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -3645,6 +3646,86 @@ static CXLRetCode cmd_fm_initiate_dc_add(const struct cxl_cmd *cmd, } } +#define CXL_EXTENT_REMOVAL_POLICY_MASK 0x0F +#define CXL_FORCED_REMOVAL_MASK (1 << 4) +/* + * CXL r3.2 Section 7.6.7.6.6: + * Initiate Dynamic Capacity Release (Opcode 5605h) + */ +static CXLRetCode cmd_fm_initiate_dc_release(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t flags; + uint8_t reg_num; + uint64_t length; + uint8_t tag[0x10]; + uint32_t ext_count; + CXLDCExtentRaw extents[]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + int i, rc; + + switch (in->flags & CXL_EXTENT_REMOVAL_POLICY_MASK) { + case CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE: { + CXLDCExtentList updated_list; + uint32_t updated_list_size; + g_autofree CXLUpdateDCExtentListInPl *list = + g_malloc0(sizeof(*list) + + in->ext_count * sizeof(*list->updated_entries)); + + convert_raw_extents(in->extents, list, in->ext_count); + rc = cxl_detect_malformed_extent_list(ct3d, list); + if (rc) { + return rc; + } + + /* + * Fail with Invalid PA if an extent is pending and Forced Removal + * flag not set. + */ + if (!(in->flags & CXL_FORCED_REMOVAL_MASK)) { + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw ext = in->extents[i]; + /* + * Check requested extents don't overlap with pending + * extents. + */ + if (cxl_extent_groups_overlaps_dpa_range( + &ct3d->dc.extents_pending, + ext.start_dpa, + ext.len)) { + return CXL_MBOX_INVALID_PA; + } + } + } + + rc = cxl_dc_extent_release_dry_run(ct3d, + list, + &updated_list, + &updated_list_size); + if (rc) { + return rc; + } + cxl_create_dc_event_records_for_extents(ct3d, + DC_EVENT_RELEASE_CAPACITY, + in->extents, + in->ext_count); + return CXL_MBOX_SUCCESS; + } + default: { + qemu_log_mask(LOG_UNIMP, + "CXL extent removal policy not supported.\n"); + return CXL_MBOX_INVALID_INPUT; + } + } +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3779,6 +3860,13 @@ static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { CXL_MBOX_CONFIG_CHANGE_CXL_RESET | CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, + [FMAPI_DCD_MGMT][INITIATE_DC_RELEASE] = { "INIT_DC_RELEASE", + cmd_fm_initiate_dc_release, ~0, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, }; /*