Merge remote-tracking branch 'origin/stable-10.0' into cr16-wip
This commit is contained in:
commit
33c500e072
60 changed files with 839 additions and 466 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
9.2.93
|
||||
10.0.2
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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>`_:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
39
hw/9pfs/9p.c
39
hw/9pfs/9p.c
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
>64120_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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
82
meson.build
82
meson.build
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */ }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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), ®); \
|
||||
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), ®); \
|
||||
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), ®); \
|
||||
|
|
@ -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, ®);
|
||||
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, ®);
|
||||
|
|
@ -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), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), ®);
|
||||
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, ®);
|
||||
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), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vstart = reg;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vl = reg;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vtype = reg;
|
||||
|
||||
if (kvm_v_vlenb.supported) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®);
|
||||
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), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = env->vl;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = env->vtype;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®);
|
||||
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), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®);
|
||||
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
|
||||
|
|
@ -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, ®);
|
||||
|
|
@ -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, ®);
|
||||
|
|
@ -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, ®);
|
||||
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(®_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(®_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, ®);
|
||||
|
|
@ -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, ®);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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; \
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
73
tests/tcg/plugins/reset.c
Normal 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");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue