Merge remote-tracking branch 'origin/stable-10.0' into cr16-wip

This commit is contained in:
Jonas Bewig 2025-05-29 16:22:47 +02:00
commit 33c500e072
No known key found for this signature in database
GPG key ID: 8D99867797A4886F
60 changed files with 839 additions and 466 deletions

View file

@ -1 +1 @@
9.2.93
10.0.2

View file

@ -437,9 +437,8 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
return kvm_fd;
}
static void kvm_reset_parked_vcpus(void *param)
static void kvm_reset_parked_vcpus(KVMState *s)
{
KVMState *s = param;
struct KVMParkedVcpu *cpu;
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
@ -2738,7 +2737,6 @@ static int kvm_init(MachineState *ms)
}
qemu_register_reset(kvm_unpoison_all, NULL);
qemu_register_reset(kvm_reset_parked_vcpus, s);
if (s->kernel_irqchip_allowed) {
kvm_irqchip_create(s);
@ -2908,6 +2906,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg
void kvm_cpu_synchronize_post_reset(CPUState *cpu)
{
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
if (cpu == first_cpu) {
kvm_reset_parked_vcpus(kvm_state);
}
}
static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)

View file

@ -106,7 +106,7 @@ static int64_t decode_sleb128(const uint8_t **pp)
val |= (int64_t)(byte & 0x7f) << shift;
shift += 7;
} while (byte & 0x80);
if (shift < TARGET_LONG_BITS && (byte & 0x40)) {
if (shift < 64 && (byte & 0x40)) {
val |= -(int64_t)1 << shift;
}

View file

@ -69,11 +69,11 @@ safe_syscall_end:
/* code path setting errno */
0: neg a0, a0
j safe_syscall_set_errno_tail
tail safe_syscall_set_errno_tail
/* code path when we didn't execute the syscall */
2: li a0, QEMU_ERESTARTSYS
j safe_syscall_set_errno_tail
tail safe_syscall_set_errno_tail
.cfi_endproc
.size safe_syscall_base, .-safe_syscall_base

View file

@ -452,7 +452,7 @@ Backend ``memory`` (since 9.0)
``reconnect`` (since 9.2)
^^^^^^^^^^^^^^^^^^^^^^^^^
The ``reconnect`` option only allows specifiying second granularity timeouts,
The ``reconnect`` option only allows specifying second granularity timeouts,
which is not enough for all types of use cases, use ``reconnect-ms`` instead.
@ -462,7 +462,7 @@ Net device options
Stream ``reconnect`` (since 9.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``reconnect`` option only allows specifiying second granularity timeouts,
The ``reconnect`` option only allows specifying second granularity timeouts,
which is not enough for all types of use cases, use ``reconnect-ms`` instead.
VFIO device options

View file

@ -858,6 +858,15 @@ QEMU. Since all recent x86 hardware from the past >10 years is
capable of the 64-bit x86 extensions, a corresponding 64-bit OS should
be used instead.
32-bit hosts for 64-bit guests (removed in 10.0)
''''''''''''''''''''''''''''''''''''''''''''''''
In general, 32-bit hosts cannot support the memory space or atomicity
requirements of 64-bit guests. Prior to 10.0, QEMU attempted to
work around the atomicity issues in system mode by running all vCPUs
in a single thread context; in user mode atomicity was simply broken.
From 10.0, QEMU has disabled configuration of 64-bit guests on 32-bit hosts.
Guest Emulator ISAs
-------------------

View file

@ -5,7 +5,7 @@ Codebase
This section presents the various parts of QEMU and how the codebase is
organized.
Beyond giving succint descriptions, the goal is to offer links to various
Beyond giving succinct descriptions, the goal is to offer links to various
parts of the documentation/codebase.
Subsystems
@ -67,7 +67,7 @@ yet, so sometimes the source code is all you have.
* `chardev <https://gitlab.com/qemu-project/qemu/-/tree/master/chardev>`_:
Various backends used by char devices.
* `common-user <https://gitlab.com/qemu-project/qemu/-/tree/master/common-user>`_:
User-mode assembly code for dealing with signals occuring during syscalls.
User-mode assembly code for dealing with signals occurring during syscalls.
* `configs <https://gitlab.com/qemu-project/qemu/-/tree/master/configs>`_:
Makefiles defining configurations to build QEMU.
* `contrib <https://gitlab.com/qemu-project/qemu/-/tree/master/contrib>`_:
@ -102,7 +102,7 @@ yet, so sometimes the source code is all you have.
* `.gitlab-ci.d <https://gitlab.com/qemu-project/qemu/-/tree/master/.gitlab-ci.d>`_:
`CI <ci>` yaml and scripts.
* `include <https://gitlab.com/qemu-project/qemu/-/tree/master/include>`_:
All headers associated to different subsystems in QEMU. The hierachy used
All headers associated to different subsystems in QEMU. The hierarchy used
mirrors source code organization and naming.
* `hw <https://gitlab.com/qemu-project/qemu/-/tree/master/hw>`_:
`Devices <device-emulation>` and boards emulation. Devices are categorized by
@ -116,7 +116,7 @@ yet, so sometimes the source code is all you have.
* `monitor <https://gitlab.com/qemu-project/qemu/-/tree/master/monitor>`_:
`Monitor <QEMU monitor>` implementation (HMP & QMP).
* `nbd <https://gitlab.com/qemu-project/qemu/-/tree/master/nbd>`_:
QEMU `NBD (Network Block Device) <nbd>` server.
QEMU NBD (Network Block Device) server.
* `net <https://gitlab.com/qemu-project/qemu/-/tree/master/net>`_:
Network (host) support.
* `pc-bios <https://gitlab.com/qemu-project/qemu/-/tree/master/pc-bios>`_:

View file

@ -41,7 +41,7 @@ Schema or generating documentation from code that exists. It is merely
the rST syntax used to describe things. For instance, the Sphinx Python
domain adds syntax like ``:py:func:`` for describing Python functions in
documentation, but it's the autodoc module that is responsible for
reading python code and generating such syntax. QAPI is analagous here:
reading Python code and generating such syntax. QAPI is analogous here:
qapidoc.py is responsible for reading the QAPI Schema and generating rST
syntax, and qapi_domain.py is responsible for translating that special
syntax and providing APIs for Sphinx internals.
@ -514,7 +514,7 @@ the definition's "fully qualified name", allowing two different
namespaces to create an otherwise identically named definition.
This directive also influences how reference resolution works for any
references that do not explicity specify a namespace, so this directive
references that do not explicitly specify a namespace, so this directive
can be used to nudge references into preferring targets from within that
namespace.

View file

@ -500,8 +500,6 @@ What you should *never* do:
- expect it to work when loadvm'ing
- write to the FAT directory on the host system while accessing it with the guest system
.. _nbd:
NBD access
~~~~~~~~~~

View file

@ -434,16 +434,24 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
V9fsFidState *f;
GHashTableIter iter;
gpointer fid;
int err;
int nclosed = 0;
/* prevent multiple coroutines running this function simultaniously */
if (s->reclaiming) {
return;
}
s->reclaiming = true;
g_hash_table_iter_init(&iter, s->fids);
QSLIST_HEAD(, V9fsFidState) reclaim_list =
QSLIST_HEAD_INITIALIZER(reclaim_list);
/* Pick FIDs to be closed, collect them on reclaim_list. */
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) {
/*
* Unlink fids cannot be reclaimed. Check
* for them and skip them. Also skip fids
* Unlinked fids cannot be reclaimed, skip those, and also skip fids
* currently being operated on.
*/
if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
@ -493,23 +501,34 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
}
}
/*
* Now close the fid in reclaim list. Free them if they
* are already clunked.
* Close the picked FIDs altogether on a background I/O driver thread. Do
* this all at once to keep latency (i.e. amount of thread hops between main
* thread <-> fs driver background thread) as low as possible.
*/
v9fs_co_run_in_worker({
QSLIST_FOREACH(f, &reclaim_list, reclaim_next) {
err = (f->fid_type == P9_FID_DIR) ?
s->ops->closedir(&s->ctx, &f->fs_reclaim) :
s->ops->close(&s->ctx, &f->fs_reclaim);
if (!err) {
/* total_open_fd must only be mutated on main thread */
nclosed++;
}
}
});
total_open_fd -= nclosed;
/* Free the closed FIDs. */
while (!QSLIST_EMPTY(&reclaim_list)) {
f = QSLIST_FIRST(&reclaim_list);
QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next);
if (f->fid_type == P9_FID_FILE) {
v9fs_co_close(pdu, &f->fs_reclaim);
} else if (f->fid_type == P9_FID_DIR) {
v9fs_co_closedir(pdu, &f->fs_reclaim);
}
/*
* Now drop the fid reference, free it
* if clunked.
*/
put_fid(pdu, f);
}
s->reclaiming = false;
}
/*
@ -4324,6 +4343,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
s->ctx.fst = &fse->fst;
fsdev_throttle_init(s->ctx.fst);
s->reclaiming = false;
rc = 0;
out:
if (rc) {

View file

@ -362,6 +362,7 @@ struct V9fsState {
uint64_t qp_ndevices; /* Amount of entries in qpd_table. */
uint16_t qp_affix_next;
uint64_t qp_fullpath_next;
bool reclaiming;
};
/* 9p2000.L open flags */

View file

@ -213,7 +213,7 @@ static void npcm8xx_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
ARM_CPU_TYPE_NAME("cortex-a35"),
NULL
};

View file

@ -72,6 +72,7 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
for (el = machines; el; el = el->next) {
MachineClass *mc = el->data;
const char *default_cpu_type = machine_class_default_cpu_type(mc);
MachineInfo *info;
info = g_malloc0(sizeof(*info));
@ -90,8 +91,8 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
info->numa_mem_supported = mc->numa_mem_supported;
info->deprecated = !!mc->deprecation_reason;
info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi");
if (mc->default_cpu_type) {
info->default_cpu_type = g_strdup(mc->default_cpu_type);
if (default_cpu_type) {
info->default_cpu_type = g_strdup(default_cpu_type);
}
if (mc->default_ram_id) {
info->default_ram_id = g_strdup(mc->default_ram_id);

View file

@ -72,7 +72,7 @@ static void imx_gpio_update_int(IMXGPIOState *s)
static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
{
/* if this signal isn't configured as an input signal, nothing to do */
if (!extract32(s->gdir, line, 1)) {
if (extract32(s->gdir, line, 1)) {
return;
}

View file

@ -79,13 +79,12 @@ static void imx_i2c_reset(DeviceState *dev)
static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
{
/*
* raise an interrupt if the device is enabled and it is configured
* to generate some interrupts.
*/
if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
if (imx_i2c_is_enabled(s)) {
s->i2sr |= I2SR_IIF;
qemu_irq_raise(s->irq);
if (imx_i2c_interrupt_is_enabled(s)) {
qemu_irq_raise(s->irq);
}
}
}

View file

@ -1702,44 +1702,41 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
* cache.
*/
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
size_t *hdr_len, const uint8_t *buf,
size_t buf_size, size_t *buf_offset)
uint8_t *buf, size_t size)
{
size_t csum_size = ETH_HLEN + sizeof(struct ip_header) +
sizeof(struct udp_header);
buf += *buf_offset;
buf_size -= *buf_offset;
if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
(buf_size >= csum_size && buf_size < 1500) && /* normal sized MTU */
(size >= csum_size && size < 1500) && /* normal sized MTU */
(buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
(buf[23] == 17) && /* ip.protocol == UDP */
(buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
memcpy((uint8_t *)hdr + *hdr_len, buf, csum_size);
net_checksum_calculate((uint8_t *)hdr + *hdr_len, csum_size, CSUM_UDP);
net_checksum_calculate(buf, size, CSUM_UDP);
hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
*hdr_len += csum_size;
*buf_offset += csum_size;
}
}
static size_t receive_header(VirtIONet *n, struct virtio_net_hdr *hdr,
const void *buf, size_t buf_size,
size_t *buf_offset)
static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
const void *buf, size_t size)
{
size_t hdr_len = n->guest_hdr_len;
if (n->has_vnet_hdr) {
/* FIXME this cast is evil */
void *wbuf = (void *)buf;
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
size - n->host_hdr_len);
memcpy(hdr, buf, sizeof(struct virtio_net_hdr));
*buf_offset = n->host_hdr_len;
work_around_broken_dhclient(hdr, &hdr_len, buf, buf_size, buf_offset);
if (n->needs_vnet_hdr_swap) {
virtio_net_hdr_swap(VIRTIO_DEVICE(n), hdr);
if (n->needs_vnet_hdr_swap) {
virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
}
iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
} else {
struct virtio_net_hdr hdr = {
.flags = 0,
.gso_type = VIRTIO_NET_HDR_GSO_NONE
};
iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
}
return hdr_len;
}
static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
@ -1907,13 +1904,6 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
return (index == new_index) ? -1 : new_index;
}
typedef struct Header {
struct virtio_net_hdr_v1_hash virtio_net;
struct eth_header eth;
struct ip_header ip;
struct udp_header udp;
} Header;
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
size_t size)
{
@ -1923,15 +1913,15 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
size_t lens[VIRTQUEUE_MAX_SIZE];
struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
Header hdr;
struct virtio_net_hdr_v1_hash extra_hdr;
unsigned mhdr_cnt = 0;
size_t offset, i, guest_offset, j;
ssize_t err;
memset(&hdr.virtio_net, 0, sizeof(hdr.virtio_net));
memset(&extra_hdr, 0, sizeof(extra_hdr));
if (n->rss_data.enabled && n->rss_data.enabled_software_rss) {
int index = virtio_net_process_rss(nc, buf, size, &hdr.virtio_net);
int index = virtio_net_process_rss(nc, buf, size, &extra_hdr);
if (index >= 0) {
nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
}
@ -1996,20 +1986,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
if (n->mergeable_rx_bufs) {
mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
sg, elem->in_num,
offsetof(typeof(hdr),
virtio_net.hdr.num_buffers),
sizeof(hdr.virtio_net.hdr.num_buffers));
offsetof(typeof(extra_hdr), hdr.num_buffers),
sizeof(extra_hdr.hdr.num_buffers));
} else {
hdr.virtio_net.hdr.num_buffers = cpu_to_le16(1);
extra_hdr.hdr.num_buffers = cpu_to_le16(1);
}
guest_offset = n->has_vnet_hdr ?
receive_header(n, (struct virtio_net_hdr *)&hdr,
buf, size, &offset) :
n->guest_hdr_len;
iov_from_buf(sg, elem->in_num, 0, &hdr, guest_offset);
total += guest_offset;
receive_header(n, sg, elem->in_num, buf, size);
if (n->rss_data.populate_hash) {
offset = offsetof(typeof(extra_hdr), hash_value);
iov_from_buf(sg, elem->in_num, offset,
(char *)&extra_hdr + offset,
sizeof(extra_hdr.hash_value) +
sizeof(extra_hdr.hash_report));
}
offset = n->host_hdr_len;
total += n->guest_hdr_len;
guest_offset = n->guest_hdr_len;
} else {
guest_offset = 0;
}
@ -2035,11 +2028,11 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
}
if (mhdr_cnt) {
virtio_stw_p(vdev, &hdr.virtio_net.hdr.num_buffers, i);
virtio_stw_p(vdev, &extra_hdr.hdr.num_buffers, i);
iov_from_buf(mhdr_sg, mhdr_cnt,
0,
&hdr.virtio_net.hdr.num_buffers,
sizeof hdr.virtio_net.hdr.num_buffers);
&extra_hdr.hdr.num_buffers,
sizeof extra_hdr.hdr.num_buffers);
}
for (j = 0; j < i; j++) {

View file

@ -226,7 +226,6 @@ static void nvme_subsys_class_init(ObjectClass *oc, void *data)
dc->realize = nvme_subsys_realize;
dc->desc = "Virtual NVMe subsystem";
dc->hotpluggable = false;
device_class_set_props(dc, nvme_subsystem_props);
}

View file

@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s)
memory_region_transaction_commit();
}
static void gt64120_update_pci_cfgdata_mapping(GT64120State *s)
{
/* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */
static const MemoryRegionOps *pci_host_data_ops[] = {
&pci_host_data_be_ops, &pci_host_data_le_ops
};
PCIHostState *phb = PCI_HOST_BRIDGE(s);
memory_region_transaction_begin();
/*
* The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal
* Command Register determines how data transactions from the CPU to/from
* PCI are handled along with the setting of the Endianness bit in the CPU
* Configuration Register. See:
* - Table 16: 32-bit PCI Transaction Endianness
* - Table 158: PCI_0 Command, Offset: 0xc00
*/
if (memory_region_is_mapped(&phb->data_mem)) {
memory_region_del_subregion(&s->ISD_mem, &phb->data_mem);
object_unparent(OBJECT(&phb->data_mem));
}
memory_region_init_io(&phb->data_mem, OBJECT(phb),
pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1],
s, "pci-conf-data", 4);
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
&phb->data_mem, 1);
memory_region_transaction_commit();
}
static void gt64120_pci_mapping(GT64120State *s)
{
memory_region_transaction_begin();
@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
case GT_PCI0_CMD:
case GT_PCI1_CMD:
s->regs[saddr] = val & 0x0401fc0f;
gt64120_update_pci_cfgdata_mapping(s);
break;
case GT_PCI0_TOR:
case GT_PCI0_BS_SCS10:
@ -1024,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = {
},
};
static bool bswap(const GT64120State *s)
{
PCIHostState *phb = PCI_HOST_BRIDGE(s);
/*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/
bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0;
bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap);
/* Only swap for non-bridge devices in big-endian mode */
return !le_mode && !is_phb_dev0;
}
static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
{
GT64120State *s = opaque;
uint32_t val = pci_host_data_le_ops.read(opaque, addr, size);
if (bswap(s)) {
val = bswap32(val);
}
return val;
}
static void gt64120_pci_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
GT64120State *s = opaque;
if (bswap(s)) {
val = bswap32(val);
}
pci_host_data_le_ops.write(opaque, addr, val, size);
}
static const MemoryRegionOps gt64120_pci_data_ops = {
.read = gt64120_pci_data_read,
.write = gt64120_pci_data_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void gt64120_reset(DeviceState *dev)
{
GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
@ -1178,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev)
gt64120_isd_mapping(s);
gt64120_pci_mapping(s);
gt64120_update_pci_cfgdata_mapping(s);
}
static void gt64120_realize(DeviceState *dev, Error **errp)
@ -1202,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2,
&phb->conf_mem, 1);
memory_region_init_io(&phb->data_mem, OBJECT(phb),
&gt64120_pci_data_ops,
s, "pci-conf-data", 4);
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
&phb->data_mem, 1);
/*
* The whole address space decoded by the GT-64120A doesn't generate

View file

@ -217,12 +217,6 @@ const MemoryRegionOps pci_host_data_le_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
const MemoryRegionOps pci_host_data_be_ops = {
.read = pci_host_data_read,
.write = pci_host_data_write,
.endianness = DEVICE_BIG_ENDIAN,
};
static bool pci_host_needed(void *opaque)
{
PCIHostState *s = opaque;

View file

@ -104,8 +104,11 @@ static bool csr_qtest_callback(CharBackend *chr, gchar **words)
static void riscv_cpu_register_csr_qtest_callback(void)
{
static GOnce once;
g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback);
static bool first = true;
if (first) {
first = false;
qtest_set_command_cb(csr_qtest_callback);
}
}
#endif

View file

@ -802,6 +802,7 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
}
s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
g_free(val);
}
static void ccw_machine_class_init(ObjectClass *oc, void *data)

View file

@ -2316,6 +2316,8 @@ void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
}
}
static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val);
void virtio_reset(void *opaque)
{
VirtIODevice *vdev = opaque;
@ -2346,7 +2348,7 @@ void virtio_reset(void *opaque)
vdev->start_on_kick = false;
vdev->started = false;
vdev->broken = false;
vdev->guest_features = 0;
virtio_set_features_nocheck(vdev, 0);
vdev->queue_sel = 0;
vdev->status = 0;
vdev->disabled = false;

View file

@ -75,7 +75,8 @@ typedef struct MapCache {
} MapCache;
static MapCache *mapcache;
static MapCache *mapcache_grants;
static MapCache *mapcache_grants_ro;
static MapCache *mapcache_grants_rw;
static xengnttab_handle *xen_region_gnttabdev;
static inline void mapcache_lock(MapCache *mc)
@ -176,9 +177,12 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
* Grant mappings must use XC_PAGE_SIZE granularity since we can't
* map anything beyond the number of pages granted to us.
*/
mapcache_grants = xen_map_cache_init_single(f, opaque,
XC_PAGE_SHIFT,
max_mcache_size);
mapcache_grants_ro = xen_map_cache_init_single(f, opaque,
XC_PAGE_SHIFT,
max_mcache_size);
mapcache_grants_rw = xen_map_cache_init_single(f, opaque,
XC_PAGE_SHIFT,
max_mcache_size);
setrlimit(RLIMIT_AS, &rlimit_as);
}
@ -376,12 +380,12 @@ tryagain:
entry = &mc->entry[address_index % mc->nr_buckets];
while (entry && (lock || entry->lock) && entry->vaddr_base &&
(entry->paddr_index != address_index || entry->size != cache_size ||
while (entry && (!entry->vaddr_base ||
entry->paddr_index != address_index || entry->size != cache_size ||
!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping))) {
if (!free_entry && !entry->lock) {
if (!free_entry && (!entry->lock || !entry->vaddr_base)) {
free_entry = entry;
free_pentry = pentry;
}
@ -456,9 +460,13 @@ uint8_t *xen_map_cache(MemoryRegion *mr,
bool is_write)
{
bool grant = xen_mr_is_grants(mr);
MapCache *mc = grant ? mapcache_grants : mapcache;
MapCache *mc = mapcache;
uint8_t *p;
if (grant) {
mc = is_write ? mapcache_grants_rw : mapcache_grants_ro;
}
if (grant && !lock) {
/*
* Grants are only supported via address_space_map(). Anything
@ -523,7 +531,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
addr = xen_ram_addr_from_mapcache_single(mapcache, ptr);
if (addr == RAM_ADDR_INVALID) {
addr = xen_ram_addr_from_mapcache_single(mapcache_grants, ptr);
addr = xen_ram_addr_from_mapcache_single(mapcache_grants_ro, ptr);
}
if (addr == RAM_ADDR_INVALID) {
addr = xen_ram_addr_from_mapcache_single(mapcache_grants_rw, ptr);
}
return addr;
@ -626,7 +637,8 @@ static void xen_invalidate_map_cache_entry_single(MapCache *mc, uint8_t *buffer)
static void xen_invalidate_map_cache_entry_all(uint8_t *buffer)
{
xen_invalidate_map_cache_entry_single(mapcache, buffer);
xen_invalidate_map_cache_entry_single(mapcache_grants, buffer);
xen_invalidate_map_cache_entry_single(mapcache_grants_ro, buffer);
xen_invalidate_map_cache_entry_single(mapcache_grants_rw, buffer);
}
static void xen_invalidate_map_cache_entry_bh(void *opaque)

View file

@ -2162,7 +2162,7 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size);
* only useful on RAM regions.
*
* @mr: the region being updated.
* @readonly: whether rhe region is to be ROM or RAM.
* @readonly: whether the region is to be ROM or RAM.
*/
void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
@ -2173,7 +2173,7 @@ void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
* only useful on RAM regions.
*
* @mr: the region being updated.
* @nonvolatile: whether rhe region is to be non-volatile.
* @nonvolatile: whether the region is to be non-volatile.
*/
void memory_region_set_nonvolatile(MemoryRegion *mr, bool nonvolatile);

View file

@ -135,7 +135,8 @@ struct SysemuCPUOps;
* @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
* before the insn which triggers a watchpoint rather than after it.
* @gdb_arch_name: Optional callback that returns the architecture name known
* to GDB. The caller must free the returned string with g_free.
* to GDB. The returned value is expected to be a simple constant string:
* the caller will not g_free() it.
* @disas_set_info: Setup architecture specific components of disassembly info
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
* address before attempting to match it against watchpoints.

View file

@ -109,10 +109,6 @@ static const uint32_t reg800_keep_bits[DINO800_REGS] = {
struct DinoState {
PCIHostState parent_obj;
/*
* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
* so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops.
*/
uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */
uint32_t iar0;

View file

@ -68,6 +68,5 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len);
extern const MemoryRegionOps pci_host_conf_le_ops;
extern const MemoryRegionOps pci_host_conf_be_ops;
extern const MemoryRegionOps pci_host_data_le_ops;
extern const MemoryRegionOps pci_host_data_be_ops;
#endif /* PCI_HOST_H */

View file

@ -112,7 +112,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
void cpu_loop(CPUHPPAState *env)
{
CPUState *cs = env_cpu(env);
abi_ulong ret;
abi_ulong ret, si_code = 0;
int trapnr;
while (1) {
@ -169,7 +169,15 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
break;
case EXCP_ASSIST:
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
#define set_si_code(mask, val) \
if (env->fr[0] & mask) { si_code = val; }
set_si_code(R_FPSR_FLG_I_MASK, TARGET_FPE_FLTRES);
set_si_code(R_FPSR_FLG_U_MASK, TARGET_FPE_FLTUND);
set_si_code(R_FPSR_FLG_O_MASK, TARGET_FPE_FLTOVF);
set_si_code(R_FPSR_FLG_Z_MASK, TARGET_FPE_FLTDIV);
set_si_code(R_FPSR_FLG_V_MASK, TARGET_FPE_FLTINV);
#undef set_si_code
force_sig_fault(TARGET_SIGFPE, si_code, env->iaoq_f);
break;
case EXCP_BREAK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);

View file

@ -2185,20 +2185,24 @@ if not has_malloc_trim and get_option('malloc_trim').enabled()
endif
endif
gnu_source_prefix = '''
osdep_prefix = '''
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stddef.h>
#include <sys/types.h>
#include <string.h>
#include <limits.h>
/* Put unistd.h before time.h as that triggers localtime_r/gmtime_r
* function availability on recentish Mingw-w64 platforms. */
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
'''
# Check whether the glibc provides STATX_BASIC_STATS
has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix)
# Check whether statx() provides mount ID information
has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix)
have_vhost_user_blk_server = get_option('vhost_user_blk_server') \
.require(host_os == 'linux',
error_message: 'vhost_user_blk_server requires linux') \
@ -2560,8 +2564,6 @@ config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
config_host_data.set('CONFIG_HOGWEED', hogweed.found())
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
config_host_data.set('CONFIG_STATX', has_statx)
config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id)
config_host_data.set('CONFIG_ZSTD', zstd.found())
config_host_data.set('CONFIG_QPL', qpl.found())
config_host_data.set('CONFIG_UADK', uadk.found())
@ -2635,7 +2637,6 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix))
config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>'))
# Note that we need to specify prefix: here to avoid incorrectly
# thinking that Windows has posix_memalign()
@ -2657,7 +2658,7 @@ config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul', prefix: osdep_prefix))
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
if rbd.found()
config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS',
@ -2713,6 +2714,8 @@ config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE',
config_host_data.set('CONFIG_FIEMAP',
cc.has_header('linux/fiemap.h') and
cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP'))
config_host_data.set('CONFIG_GETCPU',
cc.has_header_symbol('sched.h', 'getcpu', prefix: osdep_prefix))
config_host_data.set('CONFIG_GETRANDOM',
cc.has_function('getrandom') and
cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK'))
@ -2757,8 +2760,7 @@ config_host_data.set('HAVE_UTMPX',
config_host_data.set('CONFIG_EVENTFD', cc.links('''
#include <sys/eventfd.h>
int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }'''))
config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + '''
#include <unistd.h>
config_host_data.set('CONFIG_FDATASYNC', cc.links(osdep_prefix + '''
int main(void) {
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
return fdatasync(0);
@ -2767,10 +2769,8 @@ config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + '''
#endif
}'''))
has_madvise = cc.links(gnu_source_prefix + '''
#include <sys/types.h>
has_madvise = cc.links(osdep_prefix + '''
#include <sys/mman.h>
#include <stddef.h>
int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''')
missing_madvise_proto = false
if has_madvise
@ -2780,21 +2780,18 @@ if has_madvise
# missing-prototype case, we try again with a definitely-bogus prototype.
# This will only compile if the system headers don't provide the prototype;
# otherwise the conflicting prototypes will cause a compiler error.
missing_madvise_proto = cc.links(gnu_source_prefix + '''
#include <sys/types.h>
missing_madvise_proto = cc.links(osdep_prefix + '''>
#include <sys/mman.h>
#include <stddef.h>
extern int madvise(int);
int main(void) { return madvise(0); }''')
endif
config_host_data.set('CONFIG_MADVISE', has_madvise)
config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto)
config_host_data.set('CONFIG_MEMFD', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_MEMFD', cc.links(osdep_prefix + '''
#include <sys/mman.h>
int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }'''))
config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + '''
#include <fcntl.h>
config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(osdep_prefix + '''
#if !defined(AT_EMPTY_PATH)
# error missing definition
#else
@ -2805,13 +2802,12 @@ config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + '''
# i.e. errno is set and -1 is returned. That's not really how POSIX defines the
# function. On the flip side, it has madvise() which is preferred anyways.
if host_os != 'darwin'
config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(osdep_prefix + '''
#include <sys/mman.h>
#include <stddef.h>
int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }'''))
endif
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(osdep_prefix + '''
#include <pthread.h>
static void *f(void *p) { return NULL; }
@ -2822,7 +2818,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_pref
pthread_setname_np(thread, "QEMU");
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(osdep_prefix + '''
#include <pthread.h>
static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; }
@ -2832,7 +2828,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_pre
pthread_create(&thread, 0, f, 0);
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + '''
#include <pthread.h>
#include <pthread_np.h>
@ -2844,9 +2840,8 @@ config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix +
pthread_set_name_np(thread, "QEMU");
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + '''
#include <pthread.h>
#include <time.h>
int main(void)
{
@ -2855,7 +2850,7 @@ config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_pre
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(osdep_prefix + '''
#include <pthread.h>
static void *f(void *p) { return NULL; }
@ -2872,15 +2867,10 @@ config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix +
CPU_FREE(cpuset);
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_SIGNALFD', cc.links(osdep_prefix + '''
#include <sys/signalfd.h>
#include <stddef.h>
int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }'''))
config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + '''
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
config_host_data.set('CONFIG_SPLICE', cc.links(osdep_prefix + '''
int main(void)
{
int len, fd = 0;
@ -2889,13 +2879,13 @@ config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + '''
return 0;
}'''))
config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + '''
config_host_data.set('HAVE_MLOCKALL', cc.links(osdep_prefix + '''
#include <sys/mman.h>
int main(void) {
return mlockall(MCL_FUTURE);
}'''))
config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + '''
config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(osdep_prefix + '''
#include <sys/mman.h>
int main(void) {
return mlockall(MCL_FUTURE | MCL_ONFAULT);
@ -2904,7 +2894,7 @@ config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + '''
have_l2tpv3 = false
if get_option('l2tpv3').allowed() and have_system
have_l2tpv3 = cc.has_type('struct mmsghdr',
prefix: gnu_source_prefix + '''
prefix: osdep_prefix + '''
#include <sys/socket.h>
#include <linux/ip.h>''')
endif
@ -3020,13 +3010,13 @@ if has_int128_type
endif
endif
config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_GETAUXVAL', cc.links(osdep_prefix + '''
#include <sys/auxv.h>
int main(void) {
return getauxval(AT_HWCAP) == 0;
}'''))
config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(gnu_source_prefix + '''
config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(osdep_prefix + '''
#include <sys/auxv.h>
int main(void) {
unsigned long hwcap = 0;
@ -3139,9 +3129,7 @@ config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \
.allowed())
have_afalg = get_option('crypto_afalg') \
.require(cc.compiles(gnu_source_prefix + '''
#include <errno.h>
#include <sys/types.h>
.require(cc.compiles(osdep_prefix + '''
#include <sys/socket.h>
#include <linux/if_alg.h>
int main(void) {

View file

@ -695,6 +695,7 @@ static void *multifd_send_thread(void *opaque)
if (qatomic_load_acquire(&p->pending_job)) {
bool is_device_state = multifd_payload_device_state(p->data);
size_t total_size;
int write_flags_masked = 0;
p->flags = 0;
p->iovs_num = 0;
@ -702,6 +703,9 @@ static void *multifd_send_thread(void *opaque)
if (is_device_state) {
multifd_device_state_send_prepare(p);
/* Device state packets cannot be sent via zerocopy */
write_flags_masked |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
} else {
ret = multifd_send_state->ops->send_prepare(p, &local_err);
if (ret != 0) {
@ -723,7 +727,8 @@ static void *multifd_send_thread(void *opaque)
&p->data->u.ram, &local_err);
} else {
ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num,
NULL, 0, p->write_flags,
NULL, 0,
p->write_flags & ~write_flags_masked,
&local_err);
}

View file

@ -555,7 +555,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
return false;
}
if (migrate_incoming_started()) {
if (!migrate_postcopy_preempt() && migrate_incoming_started()) {
error_setg(errp,
"Postcopy preempt must be set before incoming starts");
return false;
@ -563,7 +563,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
}
if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
if (migrate_incoming_started()) {
if (!migrate_multifd() && migrate_incoming_started()) {
error_setg(errp, "Multifd must be set before incoming starts");
return false;
}

View file

@ -370,7 +370,7 @@ static void plugin_reset_destroy(struct qemu_plugin_reset_data *data)
{
qemu_rec_mutex_lock(&plugin.lock);
plugin_reset_destroy__locked(data);
qemu_rec_mutex_lock(&plugin.lock);
qemu_rec_mutex_unlock(&plugin.lock);
}
static void plugin_flush_destroy(CPUState *cpu, run_on_cpu_data arg)

View file

@ -380,7 +380,7 @@
##
# @query-sgx:
#
# Returns information about SGX
# Returns information about configured SGX capabilities of guest
#
# Returns: @SGXInfo
#
@ -399,7 +399,7 @@
##
# @query-sgx-capabilities:
#
# Returns information from host SGX capabilities
# Returns information about SGX capabilities of host
#
# Returns: @SGXInfo
#

View file

@ -173,7 +173,7 @@
# configuration changed.
#
# The command may be used to notify the guest about block device
# capcity change. Currently only vhost-user-blk device supports
# capacity change. Currently only vhost-user-blk device supports
# this.
#
# @id: the device's ID or QOM path

View file

@ -23,7 +23,7 @@ def find_deps(exe_or_dll, search_path, analyzed_deps):
output = subprocess.check_output(["objdump", "-p", exe_or_dll], text=True)
output = output.split("\n")
for line in output:
if not line.startswith("\tDLL Name: "):
if not line.lstrip().startswith("DLL Name: "):
continue
dep = line.split("DLL Name: ")[1].strip()

View file

@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "qemu-main.h"
#include "qemu/main-loop.h"
#include "system/replay.h"
#include "system/system.h"
#ifdef CONFIG_SDL
@ -44,10 +45,12 @@ static void *qemu_default_main(void *opaque)
{
int status;
replay_mutex_lock();
bql_lock();
status = qemu_main_loop();
qemu_cleanup(status);
bql_unlock();
replay_mutex_unlock();
exit(status);
}
@ -67,6 +70,7 @@ int main(int argc, char **argv)
{
qemu_init(argc, argv);
bql_unlock();
replay_mutex_unlock();
if (qemu_main) {
QemuThread main_loop_thread;
qemu_thread_create(&main_loop_thread, "qemu_main",

View file

@ -7770,7 +7770,8 @@ static bool arm_check_ss_active(DisasContext *dc)
static void arm_post_translate_insn(DisasContext *dc)
{
if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) {
if (dc->condjmp &&
(dc->base.is_jmp == DISAS_NEXT || dc->base.is_jmp == DISAS_TOO_MANY)) {
if (dc->pc_save != dc->condlabel.pc_save) {
gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save);
}

View file

@ -118,11 +118,8 @@ BRBC 1111 01 ....... ... @op_bit_imm
@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm
@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm
# The 16-bit immediate is completely in the next word.
# Fields cannot be defined with no bits, so we cannot play
# the same trick and append to a zero-bit value.
# Defer reading the immediate until trans_{LDS,STS}.
@ldst_s .... ... rd:5 .... imm=0
%ldst_imm !function=next_word
@ldst_s .... ... rd:5 .... imm=%ldst_imm
MOV 0010 11 . ..... .... @op_rd_rr
MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d

View file

@ -1578,7 +1578,6 @@ static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
TCGv Rd = cpu_r[a->rd];
TCGv addr = tcg_temp_new_i32();
TCGv H = cpu_rampD;
a->imm = next_word(ctx);
tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
tcg_gen_shli_tl(addr, addr, 16);
@ -1783,7 +1782,6 @@ static bool trans_STS(DisasContext *ctx, arg_STS *a)
TCGv Rd = cpu_r[a->rd];
TCGv addr = tcg_temp_new_i32();
TCGv H = cpu_rampD;
a->imm = next_word(ctx);
tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
tcg_gen_shli_tl(addr, addr, 16);

View file

@ -95,7 +95,8 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
{
uint32_t soft_exp = get_float_exception_flags(&env->fp_status);
uint32_t hard_exp = 0;
uint32_t shadow = env->fr0_shadow;
uint32_t shadow = env->fr0_shadow & 0x3ffffff;
uint32_t fr1 = 0;
if (likely(soft_exp == 0)) {
env->fr[0] = (uint64_t)shadow << 32;
@ -108,9 +109,22 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, R_FPSR_ENA_O_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, R_FPSR_ENA_V_MASK);
shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
if (hard_exp & shadow) {
shadow = FIELD_DP32(shadow, FPSR, T, 1);
/* fill exception register #1, which is lower 32-bits of fr[0] */
#if !defined(CONFIG_USER_ONLY)
if (hard_exp & (R_FPSR_ENA_O_MASK | R_FPSR_ENA_U_MASK)) {
/* over- and underflow both set overflow flag only */
fr1 = FIELD_DP32(fr1, FPSR, C, 1);
fr1 = FIELD_DP32(fr1, FPSR, FLG_O, 1);
} else
#endif
{
fr1 |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
}
}
env->fr0_shadow = shadow;
env->fr[0] = (uint64_t)shadow << 32;
env->fr[0] = (uint64_t)shadow << 32 | fr1;
if (hard_exp & shadow) {
hppa_dynamic_excp(env, EXCP_ASSIST, ra);

View file

@ -177,6 +177,10 @@ void hppa_cpu_do_interrupt(CPUState *cs)
}
}
env->cr[CR_IIR] = ldl_phys(cs->as, paddr);
if (i == EXCP_ASSIST) {
/* stuff insn code into bits of FP exception register #1 */
env->fr[0] |= (env->cr[CR_IIR] & 0x03ffffff);
}
}
break;

View file

@ -774,11 +774,12 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE)
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE | \
CPUID_HT)
/* partly implemented:
CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */
/* missing:
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_TM, CPUID_PBE */
/*
* Kernel-only features that can be shown to usermode programs even if
@ -846,7 +847,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES)
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES | \
CPUID_EXT3_CMP_LEG)
#define TCG_EXT4_FEATURES 0
@ -5621,6 +5623,18 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING,
.xlevel = 0x80000008,
.model_id = "Zhaoxin YongFeng Processor",
.versions = (X86CPUVersionDefinition[]) {
{ .version = 1 },
{
.version = 2,
.note = "with the correct model number",
.props = (PropValue[]) {
{ "model", "0x5b" },
{ /* end of list */ }
}
},
{ /* end of list */ }
}
},
};

View file

@ -73,7 +73,7 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_HT;
ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |

View file

@ -293,6 +293,7 @@ void set_SF(CPUX86State *env, bool val)
void lflags_to_rflags(CPUX86State *env)
{
env->eflags &= ~(CC_C|CC_P|CC_A|CC_Z|CC_S|CC_O);
env->eflags |= get_CF(env) ? CC_C : 0;
env->eflags |= get_PF(env) ? CC_P : 0;
env->eflags |= get_AF(env) ? CC_A : 0;

View file

@ -352,7 +352,7 @@ static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv
break;
case X86_OP_SEG:
/* Note that gen_movl_seg takes care of interrupt shadow and TF. */
gen_movl_seg(s, op->n, s->T0);
gen_movl_seg(s, op->n, v, op->n == R_SS);
break;
case X86_OP_INT:
if (op->has_ea) {
@ -2372,7 +2372,7 @@ static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg)
gen_op_ld_v(s, MO_16, s->T1, s->A0);
/* load the segment here to handle exceptions properly */
gen_movl_seg(s, seg, s->T1);
gen_movl_seg(s, seg, s->T1, false);
}
static void gen_LDS(DisasContext *s, X86DecodedInsn *decode)

View file

@ -1992,25 +1992,36 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg)
/* move SRC to seg_reg and compute if the CPU state may change. Never
call this function with seg_reg == R_CS */
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src)
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit_irq)
{
if (PE(s) && !VM86(s)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, src);
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32);
/* abort translation because the addseg value may change or
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
interrupts for the next instruction */
if (seg_reg == R_SS) {
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
} else if (CODE32(s) && seg_reg < R_FS) {
TCGv_i32 sel = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(sel, src);
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel);
/* For move to DS/ES/SS, the addseg or ss32 flags may change. */
if (CODE32(s) && seg_reg < R_FS) {
s->base.is_jmp = DISAS_EOB_NEXT;
}
} else {
gen_op_movl_seg_real(s, seg_reg, src);
if (seg_reg == R_SS) {
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
}
}
/*
* For MOV or POP to SS (but not LSS) translation must always
* stop as a special handling must be done to disable hardware
* interrupts for the next instruction.
*
* This is the last instruction, so it's okay to overwrite
* HF_TF_MASK; the next TB will start with the flag set.
*
* DISAS_EOB_INHIBIT_IRQ is a superset of DISAS_EOB_NEXT which
* might have been set above.
*/
if (inhibit_irq) {
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
s->flags &= ~HF_TF_MASK;
}
}
@ -2258,7 +2269,7 @@ gen_eob(DisasContext *s, int mode)
if (mode == DISAS_EOB_RECHECK_TF) {
gen_helper_rechecking_single_step(tcg_env);
tcg_gen_exit_tb(NULL, 0);
} else if ((s->flags & HF_TF_MASK) && mode != DISAS_EOB_INHIBIT_IRQ) {
} else if (s->flags & HF_TF_MASK) {
gen_helper_single_step(tcg_env);
} else if (mode == DISAS_JUMP &&
/* give irqs a chance to happen */

View file

@ -306,7 +306,7 @@ static void gen_mips16_restore(DisasContext *ctx,
int astatic;
TCGv t0 = tcg_temp_new();
gen_op_addr_addi(ctx, t0, cpu_gpr[29], -framesize);
gen_op_addr_addi(ctx, t0, cpu_gpr[29], framesize);
if (do_ra) {
decr_and_load(ctx, 31, t0);
@ -386,7 +386,7 @@ static void gen_mips16_restore(DisasContext *ctx,
}
}
gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], -framesize);
gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], framesize);
}
#if defined(TARGET_MIPS64)

View file

@ -7082,7 +7082,7 @@ ObjectClass *ppc_cpu_class_by_name(const char *name)
if (strcmp(name, "max") == 0) {
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
if (mc) {
return object_class_by_name(mc->default_cpu_type);
return object_class_by_name(machine_class_default_cpu_type(mc));
}
}
#endif

View file

@ -79,6 +79,7 @@ const char *riscv_get_misa_ext_name(uint32_t bit);
const char *riscv_get_misa_ext_description(uint32_t bit);
#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr)
typedef struct riscv_cpu_profile {
struct riscv_cpu_profile *u_parent;

View file

@ -1662,9 +1662,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
target_ulong old_pte;
if (riscv_cpu_sxl(env) == MXL_RV32) {
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, pte, updated_pte);
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte));
old_pte = le32_to_cpu(old_pte);
} else {
old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte);
old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte));
old_pte = le64_to_cpu(old_pte);
}
if (old_pte != pte) {
goto restart;

View file

@ -703,14 +703,14 @@ vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm
# Vector widening ordered and unordered float reduction sum
vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm
vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm
vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r
vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r
vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r
vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r
vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r
vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r
vmorn_mm 011100 - ..... ..... 010 ..... 1010111 @r
vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r
vmand_mm 011001 1 ..... ..... 010 ..... 1010111 @r
vmnand_mm 011101 1 ..... ..... 010 ..... 1010111 @r
vmandn_mm 011000 1 ..... ..... 010 ..... 1010111 @r
vmxor_mm 011011 1 ..... ..... 010 ..... 1010111 @r
vmor_mm 011010 1 ..... ..... 010 ..... 1010111 @r
vmnor_mm 011110 1 ..... ..... 010 ..... 1010111 @r
vmorn_mm 011100 1 ..... ..... 010 ..... 1010111 @r
vmxnor_mm 011111 1 ..... ..... 010 ..... 1010111 @r
vcpop_m 010000 . ..... 10000 010 ..... 1010111 @r2_vm
vfirst_m 010000 . ..... 10001 010 ..... 1010111 @r2_vm
vmsbf_m 010100 . ..... 00001 010 ..... 1010111 @r2_vm
@ -732,7 +732,7 @@ vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm
vrgatherei16_vv 001110 . ..... ..... 000 ..... 1010111 @r_vm
vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm
vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm
vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r
vcompress_vm 010111 1 ..... ..... 010 ..... 1010111 @r
vmv1r_v 100111 1 ..... 00000 011 ..... 1010111 @r2rd
vmv2r_v 100111 1 ..... 00001 011 ..... 1010111 @r2rd
vmv4r_v 100111 1 ..... 00011 011 ..... 1010111 @r2rd

View file

@ -119,8 +119,11 @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a)
REQUIRE_FPU;
REQUIRE_ZVFBFWMA(ctx);
uint8_t sew = ctx->sew;
if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) &&
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) {
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm) &&
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs1, sew, a->vm) &&
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
uint32_t data = 0;
gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
@ -146,8 +149,10 @@ static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a)
REQUIRE_FPU;
REQUIRE_ZVFBFWMA(ctx);
uint8_t sew = ctx->sew;
if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) &&
vext_check_ds(ctx, a->rd, a->rs2, a->vm)) {
vext_check_ds(ctx, a->rd, a->rs2, a->vm) &&
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
uint32_t data = 0;
gen_set_rm(ctx, RISCV_FRM_DYN);

View file

@ -100,10 +100,33 @@ static bool require_scale_rvfmin(DisasContext *s)
}
}
/* Destination vector register group cannot overlap source mask register. */
static bool require_vm(int vm, int vd)
/*
* Source and destination vector register groups cannot overlap source mask
* register:
*
* A vector register cannot be used to provide source operands with more than
* one EEW for a single instruction. A mask register source is considered to
* have EEW=1 for this constraint. An encoding that would result in the same
* vector register being read with two or more different EEWs, including when
* the vector register appears at different positions within two or more vector
* register groups, is reserved.
* (Section 5.2)
*
* A destination vector register group can overlap a source vector
* register group only if one of the following holds:
* 1. The destination EEW equals the source EEW.
* 2. The destination EEW is smaller than the source EEW and the overlap
* is in the lowest-numbered part of the source register group.
* 3. The destination EEW is greater than the source EEW, the source EMUL
* is at least 1, and the overlap is in the highest-numbered part of
* the destination register group.
* For the purpose of determining register group overlap constraints, mask
* elements have EEW=1.
* (Section 5.2)
*/
static bool require_vm(int vm, int v)
{
return (vm != 0 || vd != 0);
return (vm != 0 || v != 0);
}
static bool require_nf(int vd, int nf, int lmul)
@ -356,11 +379,41 @@ static bool vext_check_ld_index(DisasContext *s, int vd, int vs2,
return ret;
}
/*
* Check whether a vector register is used to provide source operands with
* more than one EEW for the vector instruction.
* Returns true if the instruction has valid encoding
* Returns false if encoding violates the mismatched input EEWs constraint
*/
static bool vext_check_input_eew(DisasContext *s, int vs1, uint8_t eew_vs1,
int vs2, uint8_t eew_vs2, int vm)
{
bool is_valid = true;
int8_t emul_vs1 = eew_vs1 - s->sew + s->lmul;
int8_t emul_vs2 = eew_vs2 - s->sew + s->lmul;
/* When vm is 0, vs1 & vs2(EEW!=1) group can't overlap v0 (EEW=1) */
if ((vs1 != -1 && !require_vm(vm, vs1)) ||
(vs2 != -1 && !require_vm(vm, vs2))) {
is_valid = false;
}
/* When eew_vs1 != eew_vs2, check whether vs1 and vs2 are overlapped */
if ((vs1 != -1 && vs2 != -1) && (eew_vs1 != eew_vs2) &&
is_overlapped(vs1, 1 << MAX(emul_vs1, 0),
vs2, 1 << MAX(emul_vs2, 0))) {
is_valid = false;
}
return is_valid;
}
static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
{
return require_vm(vm, vd) &&
require_align(vd, s->lmul) &&
require_align(vs, s->lmul);
require_align(vs, s->lmul) &&
vext_check_input_eew(s, vs, s->sew, -1, s->sew, vm);
}
/*
@ -379,6 +432,7 @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm)
{
return vext_check_ss(s, vd, vs2, vm) &&
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) &&
require_align(vs1, s->lmul);
}
@ -474,6 +528,7 @@ static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2,
static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
{
return vext_wide_check_common(s, vd, vm) &&
vext_check_input_eew(s, vs, s->sew, -1, 0, vm) &&
require_align(vs, s->lmul) &&
require_noover(vd, s->lmul + 1, vs, s->lmul);
}
@ -481,6 +536,7 @@ static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
{
return vext_wide_check_common(s, vd, vm) &&
vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm) &&
require_align(vs, s->lmul + 1);
}
@ -499,6 +555,7 @@ static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
{
return vext_check_ds(s, vd, vs2, vm) &&
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) &&
require_align(vs1, s->lmul) &&
require_noover(vd, s->lmul + 1, vs1, s->lmul);
}
@ -521,12 +578,14 @@ static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm)
{
return vext_check_ds(s, vd, vs1, vm) &&
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) &&
require_align(vs2, s->lmul + 1);
}
static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
{
bool ret = vext_narrow_check_common(s, vd, vs, vm);
bool ret = vext_narrow_check_common(s, vd, vs, vm) &&
vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm);
if (vd != vs) {
ret &= require_noover(vd, s->lmul, vs, s->lmul + 1);
}
@ -549,6 +608,7 @@ static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm)
{
return vext_check_sd(s, vd, vs2, vm) &&
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) &&
require_align(vs1, s->lmul);
}
@ -584,7 +644,9 @@ static bool vext_check_slide(DisasContext *s, int vd, int vs2,
{
bool ret = require_align(vs2, s->lmul) &&
require_align(vd, s->lmul) &&
require_vm(vm, vd);
require_vm(vm, vd) &&
vext_check_input_eew(s, -1, 0, vs2, s->sew, vm);
if (is_over) {
ret &= (vd != vs2);
}
@ -981,7 +1043,8 @@ static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew);
vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew) &&
vext_check_input_eew(s, -1, 0, a->rs2, eew, a->vm);
}
GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check)
@ -1033,7 +1096,8 @@ static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_st_index(s, a->rd, a->rs2, a->nf, eew);
vext_check_st_index(s, a->rd, a->rs2, a->nf, eew) &&
vext_check_input_eew(s, a->rd, s->sew, a->rs2, eew, a->vm);
}
GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check)
@ -1475,6 +1539,16 @@ static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
}
/* OPIVV with overwrite and WIDEN */
static bool opivv_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
}
static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
gen_helper_gvec_4_ptr *fn,
bool (*checkfn)(DisasContext *, arg_rmrr *))
@ -1522,6 +1596,14 @@ static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
vext_check_ds(s, a->rd, a->rs2, a->vm);
}
static bool opivx_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
}
#define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
@ -1993,13 +2075,13 @@ GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
/* Vector Widening Integer Multiply-Add Instructions */
GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check)
GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_overwrite_widen_check)
GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_overwrite_widen_check)
GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_overwrite_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_overwrite_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_overwrite_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_overwrite_widen_check)
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_overwrite_widen_check)
/* Vector Integer Merge and Move Instructions */
static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
@ -2340,6 +2422,17 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
}
static bool opfvv_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
require_rvf(s) &&
require_scale_rvf(s) &&
vext_check_isa_ill(s) &&
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
}
/* OPFVV with WIDEN */
#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
@ -2379,11 +2472,21 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
vext_check_ds(s, a->rd, a->rs2, a->vm);
}
static bool opfvf_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
require_rvf(s) &&
require_scale_rvf(s) &&
vext_check_isa_ill(s) &&
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
}
/* OPFVF with WIDEN */
#define GEN_OPFVF_WIDEN_TRANS(NAME) \
#define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
if (opfvf_widen_check(s, a)) { \
if (CHECK(s, a)) { \
uint32_t data = 0; \
static gen_helper_opfvf *const fns[2] = { \
gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
@ -2399,8 +2502,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
return false; \
}
GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
GEN_OPFVF_WIDEN_TRANS(vfwadd_vf, opfvf_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwsub_vf, opfvf_widen_check)
static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
{
@ -2482,7 +2585,7 @@ GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check)
/* Vector Widening Floating-Point Multiply */
GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
GEN_OPFVF_WIDEN_TRANS(vfwmul_vf, opfvf_widen_check)
/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
@ -2503,14 +2606,14 @@ GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_overwrite_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_overwrite_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_overwrite_widen_check)
GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_overwrite_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_overwrite_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_overwrite_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_overwrite_widen_check)
GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_overwrite_widen_check)
/* Vector Floating-Point Square-Root Instruction */
@ -3426,6 +3529,7 @@ static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_input_eew(s, a->rs1, s->sew, a->rs2, s->sew, a->vm) &&
require_align(a->rd, s->lmul) &&
require_align(a->rs1, s->lmul) &&
require_align(a->rs2, s->lmul) &&
@ -3438,6 +3542,7 @@ static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a)
int8_t emul = MO_16 - s->sew + s->lmul;
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_input_eew(s, a->rs1, MO_16, a->rs2, s->sew, a->vm) &&
(emul >= -3 && emul <= 3) &&
require_align(a->rd, s->lmul) &&
require_align(a->rs1, emul) &&
@ -3457,6 +3562,7 @@ static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
{
return require_rvv(s) &&
vext_check_isa_ill(s) &&
vext_check_input_eew(s, -1, MO_64, a->rs2, s->sew, a->vm) &&
require_align(a->rd, s->lmul) &&
require_align(a->rs2, s->lmul) &&
(a->rd != a->rs2) &&
@ -3600,7 +3706,9 @@ static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div)
require_align(a->rd, s->lmul) &&
require_align(a->rs2, s->lmul - div) &&
require_vm(a->vm, a->rd) &&
require_noover(a->rd, s->lmul, a->rs2, s->lmul - div);
require_noover(a->rd, s->lmul, a->rs2, s->lmul - div) &&
vext_check_input_eew(s, -1, 0, a->rs2, s->sew, a->vm);
return ret;
}

View file

@ -58,33 +58,17 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
static bool cap_has_mp_state;
static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type,
uint64_t idx)
{
uint64_t id = KVM_REG_RISCV | type | idx;
#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
type | idx)
switch (riscv_cpu_mxl(env)) {
case MXL_RV32:
id |= KVM_REG_SIZE_U32;
break;
case MXL_RV64:
id |= KVM_REG_SIZE_U64;
break;
default:
g_assert_not_reached();
}
return id;
}
#define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \
type | idx)
static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
{
return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx;
}
static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
{
return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx;
}
#if defined(TARGET_RISCV64)
#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U64(type, idx)
#else
#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U32(type, idx)
#endif
static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b)
{
@ -107,45 +91,29 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu,
return kvm_encode_reg_size_id(id, size_b);
}
#define RISCV_CORE_REG(env, name) \
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \
#define RISCV_CORE_REG(name) \
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, \
KVM_REG_RISCV_CORE_REG(name))
#define RISCV_CSR_REG(env, name) \
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \
#define RISCV_CSR_REG(name) \
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CSR, \
KVM_REG_RISCV_CSR_REG(name))
#define RISCV_CONFIG_REG(env, name) \
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \
#define RISCV_CONFIG_REG(name) \
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, \
KVM_REG_RISCV_CONFIG_REG(name))
#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \
#define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \
KVM_REG_RISCV_TIMER_REG(name))
#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
#define RISCV_FP_F_REG(idx) KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_F, idx)
#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx)
#define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx)
#define RISCV_VECTOR_CSR_REG(env, name) \
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \
#define RISCV_VECTOR_CSR_REG(name) \
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \
KVM_REG_RISCV_VECTOR_CSR_REG(name))
#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
do { \
int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
if (_ret) { \
return _ret; \
} \
} while (0)
#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \
do { \
int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
if (_ret) { \
return _ret; \
} \
} while (0)
#define KVM_RISCV_GET_TIMER(cs, name, reg) \
do { \
int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), &reg); \
@ -248,7 +216,7 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
/* If we're here we're going to disable the MISA bit */
reg = 0;
id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
misa_cfg->kvm_reg_id);
ret = kvm_set_one_reg(cs, id, &reg);
if (ret != 0) {
@ -267,6 +235,53 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
}
}
#define KVM_CSR_CFG(_name, _env_prop, reg_id) \
{.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \
.kvm_reg_id = reg_id}
static KVMCPUConfig kvm_csr_cfgs[] = {
KVM_CSR_CFG("sstatus", mstatus, RISCV_CSR_REG(sstatus)),
KVM_CSR_CFG("sie", mie, RISCV_CSR_REG(sie)),
KVM_CSR_CFG("stvec", stvec, RISCV_CSR_REG(stvec)),
KVM_CSR_CFG("sscratch", sscratch, RISCV_CSR_REG(sscratch)),
KVM_CSR_CFG("sepc", sepc, RISCV_CSR_REG(sepc)),
KVM_CSR_CFG("scause", scause, RISCV_CSR_REG(scause)),
KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)),
KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)),
KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)),
};
static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
{
return (void *)&cpu->env + csr_cfg->offset;
}
static uint32_t kvm_cpu_csr_get_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
{
uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg);
return *val32;
}
static uint64_t kvm_cpu_csr_get_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
{
uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg);
return *val64;
}
static void kvm_cpu_csr_set_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg,
uint32_t val)
{
uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg);
*val32 = val;
}
static void kvm_cpu_csr_set_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg,
uint64_t val)
{
uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg);
*val64 = val;
}
#define KVM_EXT_CFG(_name, _prop, _reg_id) \
{.name = _name, .offset = CPU_CFG_OFFSET(_prop), \
.kvm_reg_id = _reg_id}
@ -434,7 +449,6 @@ static KVMCPUConfig kvm_sbi_dbcn = {
static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
{
CPURISCVState *env = &cpu->env;
uint64_t id, reg;
int i, ret;
@ -445,7 +459,7 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
continue;
}
id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
multi_ext_cfg->kvm_reg_id);
reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
ret = kvm_set_one_reg(cs, id, &reg);
@ -570,14 +584,14 @@ static int kvm_riscv_get_regs_core(CPUState *cs)
target_ulong reg;
CPURISCVState *env = &RISCV_CPU(cs)->env;
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), &reg);
if (ret) {
return ret;
}
env->pc = reg;
for (i = 1; i < 32; i++) {
uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i);
uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i);
ret = kvm_get_one_reg(cs, id, &reg);
if (ret) {
return ret;
@ -596,13 +610,13 @@ static int kvm_riscv_put_regs_core(CPUState *cs)
CPURISCVState *env = &RISCV_CPU(cs)->env;
reg = env->pc;
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), &reg);
if (ret) {
return ret;
}
for (i = 1; i < 32; i++) {
uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i);
uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i);
reg = env->gpr[i];
ret = kvm_set_one_reg(cs, id, &reg);
if (ret) {
@ -613,6 +627,66 @@ static int kvm_riscv_put_regs_core(CPUState *cs)
return ret;
}
static int kvm_riscv_get_regs_csr(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
uint64_t reg;
int i, ret;
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
if (!csr_cfg->supported) {
continue;
}
ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, &reg);
if (ret) {
return ret;
}
if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) {
kvm_cpu_csr_set_u32(cpu, csr_cfg, reg);
} else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) {
kvm_cpu_csr_set_u64(cpu, csr_cfg, reg);
} else {
g_assert_not_reached();
}
}
return 0;
}
static int kvm_riscv_put_regs_csr(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
uint64_t reg;
int i, ret;
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
if (!csr_cfg->supported) {
continue;
}
if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) {
reg = kvm_cpu_csr_get_u32(cpu, csr_cfg);
} else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) {
reg = kvm_cpu_csr_get_u64(cpu, csr_cfg);
} else {
g_assert_not_reached();
}
ret = kvm_set_one_reg(cs, csr_cfg->kvm_reg_id, &reg);
if (ret) {
return ret;
}
}
return 0;
}
static void kvm_riscv_reset_regs_csr(CPURISCVState *env)
{
env->mstatus = 0;
@ -626,40 +700,6 @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env)
env->satp = 0;
}
static int kvm_riscv_get_regs_csr(CPUState *cs)
{
CPURISCVState *env = &RISCV_CPU(cs)->env;
KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
return 0;
}
static int kvm_riscv_put_regs_csr(CPUState *cs)
{
CPURISCVState *env = &RISCV_CPU(cs)->env;
KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
return 0;
}
static int kvm_riscv_get_regs_fp(CPUState *cs)
{
int ret = 0;
@ -800,26 +840,26 @@ static int kvm_riscv_get_regs_vector(CPUState *cs)
return 0;
}
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), &reg);
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), &reg);
if (ret) {
return ret;
}
env->vstart = reg;
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), &reg);
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), &reg);
if (ret) {
return ret;
}
env->vl = reg;
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), &reg);
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), &reg);
if (ret) {
return ret;
}
env->vtype = reg;
if (kvm_v_vlenb.supported) {
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), &reg);
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), &reg);
if (ret) {
return ret;
}
@ -857,26 +897,26 @@ static int kvm_riscv_put_regs_vector(CPUState *cs)
}
reg = env->vstart;
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), &reg);
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), &reg);
if (ret) {
return ret;
}
reg = env->vl;
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), &reg);
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), &reg);
if (ret) {
return ret;
}
reg = env->vtype;
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), &reg);
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), &reg);
if (ret) {
return ret;
}
if (kvm_v_vlenb.supported) {
reg = cpu->cfg.vlenb;
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), &reg);
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), &reg);
for (int i = 0; i < 32; i++) {
/*
@ -955,25 +995,24 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
{
CPURISCVState *env = &cpu->env;
struct kvm_one_reg reg;
int ret;
reg.id = RISCV_CONFIG_REG(env, mvendorid);
reg.id = RISCV_CONFIG_REG(mvendorid);
reg.addr = (uint64_t)&cpu->cfg.mvendorid;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve mvendorid from host, error %d", ret);
}
reg.id = RISCV_CONFIG_REG(env, marchid);
reg.id = RISCV_CONFIG_REG(marchid);
reg.addr = (uint64_t)&cpu->cfg.marchid;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve marchid from host, error %d", ret);
}
reg.id = RISCV_CONFIG_REG(env, mimpid);
reg.id = RISCV_CONFIG_REG(mimpid);
reg.addr = (uint64_t)&cpu->cfg.mimpid;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
@ -988,7 +1027,7 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
struct kvm_one_reg reg;
int ret;
reg.id = RISCV_CONFIG_REG(env, isa);
reg.id = RISCV_CONFIG_REG(isa);
reg.addr = (uint64_t)&env->misa_ext_mask;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
@ -1005,11 +1044,10 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
KVMCPUConfig *cbomz_cfg)
{
CPURISCVState *env = &cpu->env;
struct kvm_one_reg reg;
int ret;
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
cbomz_cfg->kvm_reg_id);
reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg);
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
@ -1023,7 +1061,6 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
KVMScratchCPU *kvmcpu)
{
CPURISCVState *env = &cpu->env;
uint64_t val;
int i, ret;
@ -1031,7 +1068,7 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
struct kvm_one_reg reg;
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
multi_ext_cfg->kvm_reg_id);
reg.addr = (uint64_t)&val;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
@ -1061,6 +1098,32 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
}
}
static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu)
{
uint64_t val;
int i, ret;
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
struct kvm_one_reg reg;
reg.id = csr_cfg->kvm_reg_id;
reg.addr = (uint64_t)&val;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
if (errno == EINVAL) {
csr_cfg->supported = false;
} else {
error_report("Unable to read KVM CSR %s: %s",
csr_cfg->name, strerror(errno));
exit(EXIT_FAILURE);
}
} else {
csr_cfg->supported = true;
}
}
}
static int uint64_cmp(const void *a, const void *b)
{
uint64_t val1 = *(const uint64_t *)a;
@ -1078,7 +1141,6 @@ static int uint64_cmp(const void *a, const void *b)
}
static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu,
KVMScratchCPU *kvmcpu,
struct kvm_reg_list *reglist)
{
struct kvm_reg_list *reg_search;
@ -1118,12 +1180,31 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
}
}
static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist)
{
struct kvm_reg_list *reg_search;
uint64_t reg_id;
for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
reg_id = csr_cfg->kvm_reg_id;
reg_search = bsearch(&reg_id, reglist->reg, reglist->n,
sizeof(uint64_t), uint64_cmp);
if (!reg_search) {
continue;
}
csr_cfg->supported = true;
}
}
static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
{
g_autofree struct kvm_reg_list *reglist = NULL;
KVMCPUConfig *multi_ext_cfg;
struct kvm_one_reg reg;
struct kvm_reg_list rl_struct;
struct kvm_reg_list *reglist;
uint64_t val, reg_id, *reg_search;
int i, ret;
@ -1135,7 +1216,9 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
* (EINVAL). Use read_legacy() in this case.
*/
if (errno == EINVAL) {
return kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
kvm_riscv_read_csr_cfg_legacy(kvmcpu);
return;
} else if (errno != E2BIG) {
/*
* E2BIG is an expected error message for the API since we
@ -1164,7 +1247,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
multi_ext_cfg = &kvm_multi_ext_cfgs[i];
reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT,
reg_id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
multi_ext_cfg->kvm_reg_id);
reg_search = bsearch(&reg_id, reglist->reg, reglist->n,
sizeof(uint64_t), uint64_cmp);
@ -1197,7 +1280,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
kvm_riscv_read_vlenb(cpu, kvmcpu, reglist);
}
kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist);
kvm_riscv_check_sbi_dbcn_support(cpu, reglist);
kvm_riscv_read_csr_cfg(reglist);
}
static void riscv_init_kvm_registers(Object *cpu_obj)
@ -1211,7 +1295,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
kvm_riscv_init_machine_ids(cpu, &kvmcpu);
kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
kvm_riscv_init_cfg(cpu, &kvmcpu);
kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
}
@ -1343,12 +1427,11 @@ void kvm_arch_init_irq_routing(KVMState *s)
static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
{
CPURISCVState *env = &cpu->env;
target_ulong reg;
uint64_t id;
int ret;
id = RISCV_CONFIG_REG(env, mvendorid);
id = RISCV_CONFIG_REG(mvendorid);
/*
* cfg.mvendorid is an uint32 but a target_ulong will
* be written. Assign it to a target_ulong var to avoid
@ -1360,13 +1443,13 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
return ret;
}
id = RISCV_CONFIG_REG(env, marchid);
id = RISCV_CONFIG_REG(marchid);
ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
if (ret != 0) {
return ret;
}
id = RISCV_CONFIG_REG(env, mimpid);
id = RISCV_CONFIG_REG(mimpid);
ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
return ret;
@ -1916,7 +1999,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
if (cpu->cfg.ext_zicbom &&
riscv_cpu_option_set(kvm_cbom_blocksize.name)) {
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
kvm_cbom_blocksize.kvm_reg_id);
reg.addr = (uint64_t)&val;
ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, &reg);
@ -1935,7 +2018,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
if (cpu->cfg.ext_zicboz &&
riscv_cpu_option_set(kvm_cboz_blocksize.name)) {
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
kvm_cboz_blocksize.kvm_reg_id);
reg.addr = (uint64_t)&val;
ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, &reg);

View file

@ -31,6 +31,15 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
uint8_t val);
static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
/*
* Convert the PMP permissions to match the truth table in the Smepmp spec.
*/
static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg)
{
return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) |
(cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2);
}
/*
* Accessor method to extract address matching type 'a field' from cfg reg
*/
@ -45,11 +54,6 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg)
*/
static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
{
/* mseccfg.RLB is set */
if (MSECCFG_RLB_ISSET(env)) {
return 0;
}
if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
return 1;
}
@ -62,6 +66,53 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
return 0;
}
/*
* Check whether a PMP is locked for writing or not.
* (i.e. has LOCK flag and mseccfg.RLB is unset)
*/
static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
{
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
}
/*
* Check whether `val` is an invalid Smepmp config value
*/
static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val)
{
/* No check if mseccfg.MML is not set or if mseccfg.RLB is set */
if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) {
return 0;
}
/*
* Adding a rule with executable privileges that either is M-mode-only
* or a locked Shared-Region is not possible
*/
switch (pmp_get_smepmp_operation(val)) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 12:
case 14:
case 15:
return 0;
case 9:
case 10:
case 11:
case 13:
return 1;
default:
g_assert_not_reached();
}
}
/*
* Count the number of active rules.
*/
@ -90,45 +141,13 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
{
if (pmp_index < MAX_RISCV_PMPS) {
bool locked = true;
if (riscv_cpu_cfg(env)->ext_smepmp) {
/* mseccfg.RLB is set */
if (MSECCFG_RLB_ISSET(env)) {
locked = false;
}
/* mseccfg.MML is not set */
if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
locked = false;
}
/* mseccfg.MML is set */
if (MSECCFG_MML_ISSET(env)) {
/* not adding execute bit */
if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
locked = false;
}
/* shared region and not adding X bit */
if ((val & PMP_LOCK) != PMP_LOCK &&
(val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
locked = false;
}
}
if (pmp_is_readonly(env, pmp_index)) {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpcfg write - read only\n");
} else if (pmp_is_invalid_smepmp_cfg(env, val)) {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpcfg write - invalid\n");
} else {
if (!pmp_is_locked(env, pmp_index)) {
locked = false;
}
}
if (locked) {
qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
} else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) {
/* If !mseccfg.MML then ignore writes with encoding RW=01 */
if ((val & PMP_WRITE) && !(val & PMP_READ) &&
!MSECCFG_MML_ISSET(env)) {
return false;
}
env->pmp_state.pmp[pmp_index].cfg_reg = val;
pmp_update_rule_addr(env, pmp_index);
return true;
@ -352,16 +371,6 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
const uint8_t a_field =
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
/*
* Convert the PMP permissions to match the truth table in the
* Smepmp spec.
*/
const uint8_t smepmp_operation =
((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
(env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
/*
* If the PMP entry is not off and the address is in range,
@ -380,6 +389,9 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
/*
* If mseccfg.MML Bit set, do the enhanced pmp priv check
*/
const uint8_t smepmp_operation =
pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg);
if (mode == PRV_M) {
switch (smepmp_operation) {
case 0:
@ -524,14 +536,14 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) {
if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpaddr write - pmpcfg + 1 locked\n");
"ignoring pmpaddr write - pmpcfg+1 read only\n");
return;
}
}
if (!pmp_is_locked(env, addr_index)) {
if (!pmp_is_readonly(env, addr_index)) {
if (env->pmp_state.pmp[addr_index].addr_reg != val) {
env->pmp_state.pmp[addr_index].addr_reg = val;
pmp_update_rule_addr(env, addr_index);
@ -542,7 +554,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
}
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpaddr write - locked\n");
"ignoring pmpaddr write - read only\n");
}
} else {
qemu_log_mask(LOG_GUEST_ERROR,

View file

@ -5113,9 +5113,11 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
} \
\
for (i = i_max; i < vl; ++i) { \
if (vm || vext_elem_mask(v0, i)) { \
*((ETYPE *)vd + H(i)) = 0; \
if (!vm && !vext_elem_mask(v0, i)) { \
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
continue; \
} \
*((ETYPE *)vd + H(i)) = 0; \
} \
\
env->vstart = 0; \

View file

@ -16,8 +16,6 @@ class Aarch64Replay(ReplayKernelBase):
'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'),
'7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7')
# Failing on Darwin: https://gitlab.com/qemu-project/qemu/-/issues/2907
@skipIfOperatingSystem('Darwin')
def test_aarch64_virt(self):
self.set_machine('virt')
self.cpu = 'cortex-a53'

View file

@ -73,9 +73,8 @@ lower_a32_serror:
mov x0, SYS_WRITE0
adr x1, .error
semihosting_call
mov x0, SYS_EXIT
mov x1, 1
semihosting_call
mov x0, 1 /* EXIT_FAILURE */
bl _exit
/* never returns */
.section .rodata

View file

@ -1,6 +1,6 @@
t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',

73
tests/tcg/plugins/reset.c Normal file
View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2025 Linaro Ltd
*
* Test the reset/uninstall cycle of a plugin.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <glib.h>
#include <qemu-plugin.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
static qemu_plugin_id_t plugin_id;
static bool was_reset;
static bool was_uninstalled;
static void after_uninstall(qemu_plugin_id_t id)
{
g_assert(was_reset && !was_uninstalled);
qemu_plugin_outs("uninstall done\n");
was_uninstalled = true;
}
static void tb_exec_after_reset(unsigned int vcpu_index, void *userdata)
{
g_assert(was_reset && !was_uninstalled);
qemu_plugin_uninstall(plugin_id, after_uninstall);
}
static void tb_trans_after_reset(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
g_assert(was_reset && !was_uninstalled);
qemu_plugin_register_vcpu_tb_exec_cb(tb, tb_exec_after_reset,
QEMU_PLUGIN_CB_NO_REGS, NULL);
}
static void after_reset(qemu_plugin_id_t id)
{
g_assert(!was_reset && !was_uninstalled);
qemu_plugin_outs("reset done\n");
was_reset = true;
qemu_plugin_register_vcpu_tb_trans_cb(id, tb_trans_after_reset);
}
static void tb_exec_before_reset(unsigned int vcpu_index, void *userdata)
{
g_assert(!was_reset && !was_uninstalled);
qemu_plugin_reset(plugin_id, after_reset);
}
static void tb_trans_before_reset(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
g_assert(!was_reset && !was_uninstalled);
qemu_plugin_register_vcpu_tb_exec_cb(tb, tb_exec_before_reset,
QEMU_PLUGIN_CB_NO_REGS, NULL);
}
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info,
int argc, char **argv)
{
plugin_id = id;
qemu_plugin_register_vcpu_tb_trans_cb(id, tb_trans_before_reset);
return 0;
}
/* Since we uninstall the plugin, we can't use qemu_plugin_register_atexit_cb,
* so we use destructor attribute instead. */
static void __attribute__((destructor)) on_plugin_exit(void)
{
g_assert(was_reset && was_uninstalled);
qemu_plugin_outs("plugin exit\n");
}