aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/iscsi.c7
-rw-r--r--block/nfs.c51
-rw-r--r--cpus-common.c14
-rw-r--r--docs/specs/acpi_hw_reduced_hotplug.rst3
-rw-r--r--hw/acpi/Makefile.objs4
-rw-r--r--hw/acpi/aml-build-stub.c79
-rw-r--r--hw/acpi/generic_event_device.c15
-rw-r--r--hw/acpi/nvdimm.c72
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/mps2-tz.c2
-rw-r--r--hw/arm/virt-acpi-build.c6
-rw-r--r--hw/arm/virt.c35
-rw-r--r--hw/arm/xlnx-versal-virt.c74
-rw-r--r--hw/arm/xlnx-versal.c115
-rw-r--r--hw/block/vhost-user-blk.c4
-rw-r--r--hw/display/qxl.c43
-rw-r--r--hw/display/virtio-vga.c1
-rw-r--r--hw/hyperv/hyperv.c15
-rw-r--r--hw/i386/acpi-build.c52
-rw-r--r--hw/i386/acpi-build.h3
-rw-r--r--hw/i386/pc.c3
-rw-r--r--hw/i386/pc_piix.c2
-rw-r--r--hw/i386/pc_q35.c2
-rw-r--r--hw/i386/vmmouse.c23
-rw-r--r--hw/i386/vmport.c25
-rw-r--r--hw/i386/vmport.h34
-rw-r--r--hw/isa/isa-bus.c15
-rw-r--r--hw/mem/Kconfig2
-rw-r--r--hw/pci/pcie.c25
-rw-r--r--hw/rdma/rdma_backend.c50
-rw-r--r--hw/rdma/rdma_rm.c3
-rw-r--r--hw/rtc/mc146818rtc.c5
-rw-r--r--hw/vfio/platform.c5
-rw-r--r--hw/virtio/vhost-user.c143
-rw-r--r--hw/virtio/vhost.c2
-rw-r--r--hw/virtio/virtio-pci.c1
-rw-r--r--include/hw/acpi/aml-build.h1
-rw-r--r--include/hw/acpi/generic_event_device.h1
-rw-r--r--include/hw/arm/virt.h1
-rw-r--r--include/hw/arm/xlnx-versal.h31
-rw-r--r--include/hw/i386/pc.h13
-rw-r--r--include/hw/isa/isa.h2
-rw-r--r--include/hw/mem/nvdimm.h3
-rw-r--r--include/hw/rtc/mc146818rtc.h1
-rw-r--r--include/qemu/lockable.h7
-rw-r--r--include/qemu/rcu.h2
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--migration/migration.c3
-rw-r--r--migration/multifd.c8
-rw-r--r--migration/ram.c3
-rw-r--r--monitor/misc.c4
-rwxr-xr-xscripts/checkpatch.pl33
-rw-r--r--target/arm/Makefile.objs18
-rw-r--r--target/arm/cpu-param.h2
-rw-r--r--target/arm/cpu.c3
-rw-r--r--target/arm/cpu.h38
-rw-r--r--target/arm/cpu64.c8
-rw-r--r--target/arm/helper.c183
-rw-r--r--target/arm/neon-dp.decode86
-rw-r--r--target/arm/neon-ls.decode52
-rw-r--r--target/arm/neon-shared.decode66
-rw-r--r--target/arm/translate-a64.c17
-rw-r--r--target/arm/translate-a64.h9
-rw-r--r--target/arm/translate-neon.inc.c714
-rw-r--r--target/arm/translate-vfp.inc.c6
-rw-r--r--target/arm/translate.c714
-rw-r--r--target/arm/translate.h26
-rw-r--r--tests/data/acpi/pc/DSDTbin5131 -> 5125 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpihmatbin6455 -> 6449 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.bridgebin6990 -> 6984 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.cphpbin5594 -> 5588 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.dimmpxmbin6784 -> 6778 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.ipmikcsbin5203 -> 5197 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.memhpbin6490 -> 6484 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.numamembin5137 -> 5131 bytes
-rw-r--r--tests/data/acpi/pc/SSDT.dimmpxmbin685 -> 734 bytes
-rw-r--r--tests/data/acpi/pc/WAETbin0 -> 40 bytes
-rw-r--r--tests/data/acpi/q35/DSDTbin7869 -> 7863 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpihmatbin9193 -> 9187 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.bridgebin7886 -> 7880 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.cphpbin8332 -> 8326 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.dimmpxmbin9522 -> 9516 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ipmibtbin7944 -> 7938 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.memhpbin9228 -> 9222 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.mmio64bin8999 -> 8993 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.numamembin7875 -> 7869 bytes
-rw-r--r--tests/data/acpi/q35/SSDT.dimmpxmbin685 -> 734 bytes
-rw-r--r--tests/data/acpi/q35/WAETbin0 -> 40 bytes
-rw-r--r--tests/data/acpi/virt/DSDT.memhpbin6644 -> 6668 bytes
-rw-r--r--tests/data/acpi/virt/NFIT.memhpbin0 -> 224 bytes
-rw-r--r--tests/data/acpi/virt/SSDT.memhpbin0 -> 736 bytes
-rw-r--r--tests/qtest/bios-tables-test.c9
-rw-r--r--tests/qtest/fuzz/fuzz.c19
-rw-r--r--ui/spice-display.c14
-rw-r--r--util/log.c4
-rw-r--r--util/qemu-timer.c17
-rw-r--r--util/rcu.c8
-rw-r--r--util/thread-pool.c3
-rw-r--r--util/vfio-helpers.c5
99 files changed, 1882 insertions, 1189 deletions
diff --git a/block/iscsi.c b/block/iscsi.c
index 914a1de9fb..a8b76979d8 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1394,20 +1394,17 @@ static void iscsi_nop_timed_event(void *opaque)
{
IscsiLun *iscsilun = opaque;
- qemu_mutex_lock(&iscsilun->mutex);
+ QEMU_LOCK_GUARD(&iscsilun->mutex);
if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
error_report("iSCSI: NOP timeout. Reconnecting...");
iscsilun->request_timed_out = true;
} else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
- goto out;
+ return;
}
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
iscsi_set_events(iscsilun);
-
-out:
- qemu_mutex_unlock(&iscsilun->mutex);
}
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
diff --git a/block/nfs.c b/block/nfs.c
index 18c0a73694..385d756e1d 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -273,15 +273,14 @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
nfs_co_init_task(bs, &task);
task.iov = iov;
- qemu_mutex_lock(&client->mutex);
- if (nfs_pread_async(client->context, client->fh,
- offset, bytes, nfs_co_generic_cb, &task) != 0) {
- qemu_mutex_unlock(&client->mutex);
- return -ENOMEM;
- }
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
+ if (nfs_pread_async(client->context, client->fh,
+ offset, bytes, nfs_co_generic_cb, &task) != 0) {
+ return -ENOMEM;
+ }
- nfs_set_events(client);
- qemu_mutex_unlock(&client->mutex);
+ nfs_set_events(client);
+ }
while (!task.complete) {
qemu_coroutine_yield();
}
@@ -320,19 +319,18 @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
buf = iov->iov[0].iov_base;
}
- qemu_mutex_lock(&client->mutex);
- if (nfs_pwrite_async(client->context, client->fh,
- offset, bytes, buf,
- nfs_co_generic_cb, &task) != 0) {
- qemu_mutex_unlock(&client->mutex);
- if (my_buffer) {
- g_free(buf);
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
+ if (nfs_pwrite_async(client->context, client->fh,
+ offset, bytes, buf,
+ nfs_co_generic_cb, &task) != 0) {
+ if (my_buffer) {
+ g_free(buf);
+ }
+ return -ENOMEM;
}
- return -ENOMEM;
- }
- nfs_set_events(client);
- qemu_mutex_unlock(&client->mutex);
+ nfs_set_events(client);
+ }
while (!task.complete) {
qemu_coroutine_yield();
}
@@ -355,15 +353,14 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
nfs_co_init_task(bs, &task);
- qemu_mutex_lock(&client->mutex);
- if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
- &task) != 0) {
- qemu_mutex_unlock(&client->mutex);
- return -ENOMEM;
- }
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
+ if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
+ &task) != 0) {
+ return -ENOMEM;
+ }
- nfs_set_events(client);
- qemu_mutex_unlock(&client->mutex);
+ nfs_set_events(client);
+ }
while (!task.complete) {
qemu_coroutine_yield();
}
diff --git a/cpus-common.c b/cpus-common.c
index eaf590cb38..55d5df8923 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -22,6 +22,7 @@
#include "exec/cpu-common.h"
#include "hw/core/cpu.h"
#include "sysemu/cpus.h"
+#include "qemu/lockable.h"
static QemuMutex qemu_cpu_list_lock;
static QemuCond exclusive_cond;
@@ -71,7 +72,7 @@ static int cpu_get_free_index(void)
void cpu_list_add(CPUState *cpu)
{
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
cpu->cpu_index = cpu_get_free_index();
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
@@ -79,15 +80,13 @@ void cpu_list_add(CPUState *cpu)
assert(!cpu_index_auto_assigned);
}
QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
void cpu_list_remove(CPUState *cpu)
{
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (!QTAILQ_IN_USE(cpu, node)) {
/* there is nothing to undo since cpu_exec_init() hasn't been called */
- qemu_mutex_unlock(&qemu_cpu_list_lock);
return;
}
@@ -95,7 +94,6 @@ void cpu_list_remove(CPUState *cpu)
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
struct qemu_work_item {
@@ -237,7 +235,7 @@ void cpu_exec_start(CPUState *cpu)
* see cpu->running == true, and it will kick the CPU.
*/
if (unlikely(atomic_read(&pending_cpus))) {
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (!cpu->has_waiter) {
/* Not counted in pending_cpus, let the exclusive item
* run. Since we have the lock, just set cpu->running to true
@@ -252,7 +250,6 @@ void cpu_exec_start(CPUState *cpu)
* waiter at cpu_exec_end.
*/
}
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
}
@@ -280,7 +277,7 @@ void cpu_exec_end(CPUState *cpu)
* next cpu_exec_start.
*/
if (unlikely(atomic_read(&pending_cpus))) {
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (cpu->has_waiter) {
cpu->has_waiter = false;
atomic_set(&pending_cpus, pending_cpus - 1);
@@ -288,7 +285,6 @@ void cpu_exec_end(CPUState *cpu)
qemu_cond_signal(&exclusive_cond);
}
}
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
}
diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst
index 911a98255b..0bd3f9399f 100644
--- a/docs/specs/acpi_hw_reduced_hotplug.rst
+++ b/docs/specs/acpi_hw_reduced_hotplug.rst
@@ -63,7 +63,8 @@ GED IO interface (4 byte access)
bits:
0: Memory hotplug event
1: System power down event
- 2-31: Reserved
+ 2: NVDIMM hotplug event
+ 3-31: Reserved
**write_access:**
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 777da07f4d..cab9bcd457 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -20,6 +20,6 @@ common-obj-$(CONFIG_TPM) += tpm.o
common-obj-$(CONFIG_IPMI) += ipmi.o
common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o
else
-common-obj-y += acpi-stub.o
+common-obj-y += acpi-stub.o aml-build-stub.o
endif
-common-obj-$(CONFIG_ALL) += acpi-stub.o acpi-x86-stub.o ipmi-stub.o
+common-obj-$(CONFIG_ALL) += acpi-stub.o aml-build-stub.o acpi-x86-stub.o ipmi-stub.o
diff --git a/hw/acpi/aml-build-stub.c b/hw/acpi/aml-build-stub.c
new file mode 100644
index 0000000000..58b2e16227
--- /dev/null
+++ b/hw/acpi/aml-build-stub.c
@@ -0,0 +1,79 @@
+/*
+ * ACPI aml builder stubs for platforms that don't support ACPI.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+
+void aml_append(Aml *parent_ctx, Aml *child)
+{
+}
+
+Aml *aml_resource_template(void)
+{
+ return NULL;
+}
+
+Aml *aml_device(const char *name_format, ...)
+{
+ return NULL;
+}
+
+Aml *aml_eisaid(const char *str)
+{
+ return NULL;
+}
+
+Aml *aml_name_decl(const char *name, Aml *val)
+{
+ return NULL;
+}
+
+Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
+ uint8_t aln, uint8_t len)
+{
+ return NULL;
+}
+
+Aml *aml_irq_no_flags(uint8_t irq)
+{
+ return NULL;
+}
+
+Aml *aml_int(const uint64_t val)
+{
+ return NULL;
+}
+
+Aml *aml_package(uint8_t num_elements)
+{
+ return NULL;
+}
+
+Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz,
+ uint8_t channel)
+{
+ return NULL;
+}
+
+Aml *aml_buffer(int buffer_size, uint8_t *byte_list)
+{
+ return NULL;
+}
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 021ed2bf23..5d17f78a1e 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -16,6 +16,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/irq.h"
#include "hw/mem/pc-dimm.h"
+#include "hw/mem/nvdimm.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
@@ -23,6 +24,7 @@
static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
ACPI_GED_PWR_DOWN_EVT,
+ ACPI_GED_NVDIMM_HOTPLUG_EVT,
};
/*
@@ -110,6 +112,11 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
break;
+ case ACPI_GED_NVDIMM_HOTPLUG_EVT:
+ aml_append(if_ctx,
+ aml_notify(aml_name("\\_SB.NVDR"),
+ aml_int(0x80)));
+ break;
default:
/*
* Please make sure all the events in ged_supported_events[]
@@ -175,7 +182,11 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
AcpiGedState *s = ACPI_GED(hotplug_dev);
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
+ nvdimm_acpi_plug_cb(hotplug_dev, dev);
+ } else {
+ acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ }
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -192,6 +203,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_MEM_HOTPLUG_EVT;
} else if (ev & ACPI_POWER_DOWN_STATUS) {
sel = ACPI_GED_PWR_DOWN_EVT;
+ } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
+ sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index eb6a37b14e..fa7bf8b507 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -900,11 +900,13 @@ void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev)
}
void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
+ struct AcpiGenericAddress dsm_io,
FWCfgState *fw_cfg, Object *owner)
{
+ state->dsm_io = dsm_io;
memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state,
- "nvdimm-acpi-io", NVDIMM_ACPI_IO_LEN);
- memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr);
+ "nvdimm-acpi-io", dsm_io.bit_width >> 3);
+ memory_region_add_subregion(io, dsm_io.address, &state->io_mr);
state->dsm_mem = g_array_new(false, true /* clear */, 1);
acpi_data_push(state->dsm_mem, sizeof(NvdimmDsmIn));
@@ -933,12 +935,15 @@ void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
#define NVDIMM_QEMU_RSVD_UUID "648B9CF2-CDA1-4312-8AD9-49C4AF32BD62"
-static void nvdimm_build_common_dsm(Aml *dev)
+static void nvdimm_build_common_dsm(Aml *dev,
+ NVDIMMState *nvdimm_state)
{
Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *elsectx2;
Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid;
Aml *pckg, *pckg_index, *pckg_buf, *field, *dsm_out_buf, *dsm_out_buf_size;
+ Aml *whilectx, *offset;
uint8_t byte_list[1];
+ AmlRegionSpace rs;
method = aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED);
uuid = aml_arg(0);
@@ -949,9 +954,16 @@ static void nvdimm_build_common_dsm(Aml *dev)
aml_append(method, aml_store(aml_name(NVDIMM_ACPI_MEM_ADDR), dsm_mem));
+ if (nvdimm_state->dsm_io.space_id == AML_AS_SYSTEM_IO) {
+ rs = AML_SYSTEM_IO;
+ } else {
+ rs = AML_SYSTEM_MEMORY;
+ }
+
/* map DSM memory and IO into ACPI namespace. */
- aml_append(method, aml_operation_region(NVDIMM_DSM_IOPORT, AML_SYSTEM_IO,
- aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN));
+ aml_append(method, aml_operation_region(NVDIMM_DSM_IOPORT, rs,
+ aml_int(nvdimm_state->dsm_io.address),
+ nvdimm_state->dsm_io.bit_width >> 3));
aml_append(method, aml_operation_region(NVDIMM_DSM_MEMORY,
AML_SYSTEM_MEMORY, dsm_mem, sizeof(NvdimmDsmIn)));
@@ -966,7 +978,7 @@ static void nvdimm_build_common_dsm(Aml *dev)
field = aml_field(NVDIMM_DSM_IOPORT, AML_DWORD_ACC, AML_NOLOCK,
AML_PRESERVE);
aml_append(field, aml_named_field(NVDIMM_DSM_NOTIFY,
- NVDIMM_ACPI_IO_LEN * BITS_PER_BYTE));
+ nvdimm_state->dsm_io.bit_width));
aml_append(method, field);
/*
@@ -1091,13 +1103,46 @@ static void nvdimm_build_common_dsm(Aml *dev)
/* RLEN is not included in the payload returned to guest. */
aml_append(method, aml_subtract(aml_name(NVDIMM_DSM_OUT_BUF_SIZE),
aml_int(4), dsm_out_buf_size));
+
+ /*
+ * As per ACPI spec 6.3, Table 19-419 Object Conversion Rules, if
+ * the Buffer Field <= to the size of an Integer (in bits), it will
+ * be treated as an integer. Moreover, the integer size depends on
+ * DSDT tables revision number. If revision number is < 2, integer
+ * size is 32 bits, otherwise it is 64 bits.
+ * Because of this CreateField() canot be used if RLEN < Integer Size.
+ *
+ * Also please note that APCI ASL operator SizeOf() doesn't support
+ * Integer and there isn't any other way to figure out the Integer
+ * size. Hence we assume 8 byte as Integer size and if RLEN < 8 bytes,
+ * build dsm_out_buf byte by byte.
+ */
+ ifctx = aml_if(aml_lless(dsm_out_buf_size, aml_int(8)));
+ offset = aml_local(2);
+ aml_append(ifctx, aml_store(aml_int(0), offset));
+ aml_append(ifctx, aml_name_decl("TBUF", aml_buffer(1, NULL)));
+ aml_append(ifctx, aml_store(aml_buffer(0, NULL), dsm_out_buf));
+
+ whilectx = aml_while(aml_lless(offset, dsm_out_buf_size));
+ /* Copy 1 byte at offset from ODAT to temporary buffer(TBUF). */
+ aml_append(whilectx, aml_store(aml_derefof(aml_index(
+ aml_name(NVDIMM_DSM_OUT_BUF), offset)),
+ aml_index(aml_name("TBUF"), aml_int(0))));
+ aml_append(whilectx, aml_concatenate(dsm_out_buf, aml_name("TBUF"),
+ dsm_out_buf));
+ aml_append(whilectx, aml_increment(offset));
+ aml_append(ifctx, whilectx);
+
+ aml_append(ifctx, aml_return(dsm_out_buf));
+ aml_append(method, ifctx);
+
+ /* If RLEN >= Integer size, just use CreateField() operator */
aml_append(method, aml_store(aml_shiftleft(dsm_out_buf_size, aml_int(3)),
dsm_out_buf_size));
aml_append(method, aml_create_field(aml_name(NVDIMM_DSM_OUT_BUF),
aml_int(0), dsm_out_buf_size, "OBUF"));
- aml_append(method, aml_concatenate(aml_buffer(0, NULL), aml_name("OBUF"),
- dsm_out_buf));
- aml_append(method, aml_return(dsm_out_buf));
+ aml_append(method, aml_return(aml_name("OBUF")));
+
aml_append(dev, method);
}
@@ -1234,7 +1279,8 @@ static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots)
}
static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
- BIOSLinker *linker, GArray *dsm_dma_area,
+ BIOSLinker *linker,
+ NVDIMMState *nvdimm_state,
uint32_t ram_slots)
{
Aml *ssdt, *sb_scope, *dev;
@@ -1262,7 +1308,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
*/
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012")));
- nvdimm_build_common_dsm(dev);
+ nvdimm_build_common_dsm(dev, nvdimm_state);
/* 0 is reserved for root device. */
nvdimm_build_device_dsm(dev, 0);
@@ -1281,7 +1327,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
NVDIMM_ACPI_MEM_ADDR);
bios_linker_loader_alloc(linker,
- NVDIMM_DSM_MEM_FILE, dsm_dma_area,
+ NVDIMM_DSM_MEM_FILE, nvdimm_state->dsm_mem,
sizeof(NvdimmDsmIn), false /* high memory */);
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t),
@@ -1303,7 +1349,7 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
return;
}
- nvdimm_build_ssdt(table_offsets, table_data, linker, state->dsm_mem,
+ nvdimm_build_ssdt(table_offsets, table_data, linker, state,
ram_slots);
device_list = nvdimm_get_device_list();
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 188419dc1e..5364172537 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -25,6 +25,7 @@ config ARM_VIRT
select DIMM
select ACPI_MEMORY_HOTPLUG
select ACPI_HW_REDUCED
+ select ACPI_NVDIMM
config CHEETAH
bool
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index a8dea7dde1..2c43041564 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -395,7 +395,7 @@ static void mps2tz_common_init(MachineState *machine)
exit(EXIT_FAILURE);
}
- sysbus_init_child_obj(OBJECT(machine), "iotkit", &mms->iotkit,
+ sysbus_init_child_obj(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit,
sizeof(mms->iotkit), mmc->armsse_type);
iotkitdev = DEVICE(&mms->iotkit);
object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory),
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 81d41a3990..f22b1e6097 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -44,6 +44,7 @@
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
#include "hw/arm/virt.h"
+#include "hw/mem/nvdimm.h"
#include "sysemu/numa.h"
#include "sysemu/reset.h"
#include "kvm_arm.h"
@@ -826,6 +827,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
}
}
+ if (ms->nvdimms_state->is_enabled) {
+ nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
+ ms->nvdimms_state, ms->ram_slots);
+ }
+
if (its_class_name() && !vmc->no_its) {
acpi_add_table(table_offsets, tables_blob);
build_iort(tables_blob, tables->linker, vms);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 626822554d..171e6908ec 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -150,6 +150,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
+ [VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@@ -567,6 +568,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
+ if (ms->nvdimms_state->is_enabled) {
+ event |= ACPI_GED_NVDIMM_HOTPLUG_EVT;
+ }
+
dev = qdev_create(NULL, TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
@@ -1884,6 +1889,18 @@ static void machvirt_init(MachineState *machine)
create_platform_bus(vms);
+ if (machine->nvdimms_state->is_enabled) {
+ const struct AcpiGenericAddress arm_virt_nvdimm_acpi_dsmio = {
+ .space_id = AML_AS_SYSTEM_MEMORY,
+ .address = vms->memmap[VIRT_NVDIMM_ACPI].base,
+ .bit_width = NVDIMM_ACPI_IO_LEN << 3
+ };
+
+ nvdimm_init_acpi_state(machine->nvdimms_state, sysmem,
+ arm_virt_nvdimm_acpi_dsmio,
+ vms->fw_cfg, OBJECT(vms));
+ }
+
vms->bootinfo.ram_size = machine->ram_size;
vms->bootinfo.nb_cpus = smp_cpus;
vms->bootinfo.board_id = -1;
@@ -2075,19 +2092,20 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ const MachineState *ms = MACHINE(hotplug_dev);
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
- if (is_nvdimm) {
- error_setg(errp, "nvdimm is not yet supported");
- return;
- }
-
if (!vms->acpi_dev) {
error_setg(errp,
"memory hotplug is not enabled: missing acpi-ged device");
return;
}
+ if (is_nvdimm && !ms->nvdimms_state->is_enabled) {
+ error_setg(errp, "nvdimm is not enabled: add 'nvdimm=on' to '-M'");
+ return;
+ }
+
pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp);
}
@@ -2095,6 +2113,8 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ MachineState *ms = MACHINE(hotplug_dev);
+ bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
Error *local_err = NULL;
pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err);
@@ -2102,6 +2122,10 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev,
goto out;
}
+ if (is_nvdimm) {
+ nvdimm_plug(ms->nvdimms_state);
+ }
+
hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev),
dev, &error_abort);
@@ -2226,6 +2250,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->plug = virt_machine_device_plug_cb;
hc->unplug_request = virt_machine_device_unplug_request_cb;
mc->numa_mem_supported = true;
+ mc->nvdimm_supported = true;
mc->auto_enable_numa_with_memhp = true;
mc->default_ram_id = "mach-virt.ram";
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 878a275140..7e749e1926 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -20,6 +20,7 @@
#include "hw/arm/sysbus-fdt.h"
#include "hw/arm/fdt.h"
#include "cpu.h"
+#include "hw/qdev-properties.h"
#include "hw/arm/xlnx-versal.h"
#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
@@ -256,6 +257,53 @@ static void fdt_add_zdma_nodes(VersalVirt *s)
}
}
+static void fdt_add_sd_nodes(VersalVirt *s)
+{
+ const char clocknames[] = "clk_xin\0clk_ahb";
+ const char compat[] = "arasan,sdhci-8.9a";
+ int i;
+
+ for (i = ARRAY_SIZE(s->soc.pmc.iou.sd) - 1; i >= 0; i--) {
+ uint64_t addr = MM_PMC_SD0 + MM_PMC_SD0_SIZE * i;
+ char *name = g_strdup_printf("/sdhci@%" PRIx64, addr);
+
+ qemu_fdt_add_subnode(s->fdt, name);
+
+ qemu_fdt_setprop_cells(s->fdt, name, "clocks",
+ s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
+ qemu_fdt_setprop(s->fdt, name, "clock-names",
+ clocknames, sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, VERSAL_SD0_IRQ_0 + i * 2,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
+ 2, addr, 2, MM_PMC_SD0_SIZE);
+ qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
+ g_free(name);
+ }
+}
+
+static void fdt_add_rtc_node(VersalVirt *s)
+{
+ const char compat[] = "xlnx,zynqmp-rtc";
+ const char interrupt_names[] = "alarm\0sec";
+ char *name = g_strdup_printf("/rtc@%x", MM_PMC_RTC);
+
+ qemu_fdt_add_subnode(s->fdt, name);
+
+ qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_ALARM_IRQ,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI,
+ GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_SECONDS_IRQ,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop(s->fdt, name, "interrupt-names",
+ interrupt_names, sizeof(interrupt_names));
+ qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
+ 2, MM_PMC_RTC, 2, MM_PMC_RTC_SIZE);
+ qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
+ g_free(name);
+}
+
static void fdt_nop_memory_nodes(void *fdt, Error **errp)
{
Error *err = NULL;
@@ -411,10 +459,23 @@ static void create_virtio_regions(VersalVirt *s)
}
}
+static void sd_plugin_card(SDHCIState *sd, DriveInfo *di)
+{
+ BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ DeviceState *card;
+
+ card = qdev_create(qdev_get_child_bus(DEVICE(sd), "sd-bus"), TYPE_SD_CARD);
+ object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card),
+ &error_fatal);
+ qdev_prop_set_drive(card, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(card), true, "realized", &error_fatal);
+}
+
static void versal_virt_init(MachineState *machine)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine);
int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
+ int i;
/*
* If the user provides an Operating System to be loaded, we expect them
@@ -440,7 +501,7 @@ static void versal_virt_init(MachineState *machine)
psci_conduit = QEMU_PSCI_CONDUIT_SMC;
}
- sysbus_init_child_obj(OBJECT(machine), "xlnx-ve", &s->soc,
+ sysbus_init_child_obj(OBJECT(machine), "xlnx-versal", &s->soc,
sizeof(s->soc), TYPE_XLNX_VERSAL);
object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram),
"ddr", &error_abort);
@@ -455,6 +516,8 @@ static void versal_virt_init(MachineState *machine)
fdt_add_gic_nodes(s);
fdt_add_timer_nodes(s);
fdt_add_zdma_nodes(s);
+ fdt_add_sd_nodes(s);
+ fdt_add_rtc_node(s);
fdt_add_cpu_nodes(s, psci_conduit);
fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz);
fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz);
@@ -464,14 +527,19 @@ static void versal_virt_init(MachineState *machine)
memory_region_add_subregion_overlap(get_system_memory(),
0, &s->soc.fpd.apu.mr, 0);
+ /* Plugin SD cards. */
+ for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) {
+ sd_plugin_card(&s->soc.pmc.iou.sd[i], drive_get_next(IF_SD));
+ }
+
s->binfo.ram_size = machine->ram_size;
s->binfo.loader_start = 0x0;
s->binfo.get_dtb = versal_virt_get_dtb;
s->binfo.modify_dtb = versal_virt_modify_dtb;
if (machine->kernel_filename) {
- arm_load_kernel(s->soc.fpd.apu.cpu[0], machine, &s->binfo);
+ arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
} else {
- AddressSpace *as = arm_boot_address_space(s->soc.fpd.apu.cpu[0],
+ AddressSpace *as = arm_boot_address_space(&s->soc.fpd.apu.cpu[0],
&s->binfo);
/* Some boot-loaders (e.g u-boot) don't like blobs at address 0 (NULL).
* Offset things by 4K. */
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index 94460f2343..321171bcce 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -20,9 +20,7 @@
#include "hw/arm/boot.h"
#include "kvm_arm.h"
#include "hw/misc/unimp.h"
-#include "hw/intc/arm_gicv3_common.h"
#include "hw/arm/xlnx-versal.h"
-#include "hw/char/pl011.h"
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
#define GEM_REVISION 0x40070106
@@ -33,23 +31,15 @@ static void versal_create_apu_cpus(Versal *s)
for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) {
Object *obj;
- char *name;
-
- obj = object_new(XLNX_VERSAL_ACPU_TYPE);
- if (!obj) {
- /* Secondary CPUs start in PSCI powered-down state */
- error_report("Unable to create apu.cpu[%d] of type %s",
- i, XLNX_VERSAL_ACPU_TYPE);
- exit(EXIT_FAILURE);
- }
-
- name = g_strdup_printf("apu-cpu[%d]", i);
- object_property_add_child(OBJECT(s), name, obj, &error_fatal);
- g_free(name);
+ object_initialize_child(OBJECT(s), "apu-cpu[*]",
+ &s->fpd.apu.cpu[i], sizeof(s->fpd.apu.cpu[i]),
+ XLNX_VERSAL_ACPU_TYPE, &error_abort, NULL);
+ obj = OBJECT(&s->fpd.apu.cpu[i]);
object_property_set_int(obj, s->cfg.psci_conduit,
"psci-conduit", &error_abort);
if (i) {
+ /* Secondary CPUs start in PSCI powered-down state */
object_property_set_bool(obj, true,
"start-powered-off", &error_abort);
}
@@ -59,7 +49,6 @@ static void versal_create_apu_cpus(Versal *s)
object_property_set_link(obj, OBJECT(&s->fpd.apu.mr), "memory",
&error_abort);
object_property_set_bool(obj, true, "realized", &error_fatal);
- s->fpd.apu.cpu[i] = ARM_CPU(obj);
}
}
@@ -97,7 +86,7 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic)
}
for (i = 0; i < nr_apu_cpus; i++) {
- DeviceState *cpudev = DEVICE(s->fpd.apu.cpu[i]);
+ DeviceState *cpudev = DEVICE(&s->fpd.apu.cpu[i]);
int ppibase = XLNX_VERSAL_NR_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
qemu_irq maint_irq;
int ti;
@@ -145,16 +134,17 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic)
DeviceState *dev;
MemoryRegion *mr;
- dev = qdev_create(NULL, TYPE_PL011);
- s->lpd.iou.uart[i] = SYS_BUS_DEVICE(dev);
+ sysbus_init_child_obj(OBJECT(s), name,
+ &s->lpd.iou.uart[i], sizeof(s->lpd.iou.uart[i]),
+ TYPE_PL011);
+ dev = DEVICE(&s->lpd.iou.uart[i]);
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
- object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal);
qdev_init_nofail(dev);
- mr = sysbus_mmio_get_region(s->lpd.iou.uart[i], 0);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
- sysbus_connect_irq(s->lpd.iou.uart[i], 0, pic[irqs[i]]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
g_free(name);
}
}
@@ -171,25 +161,26 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
DeviceState *dev;
MemoryRegion *mr;
- dev = qdev_create(NULL, "cadence_gem");
- s->lpd.iou.gem[i] = SYS_BUS_DEVICE(dev);
- object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal);
+ sysbus_init_child_obj(OBJECT(s), name,
+ &s->lpd.iou.gem[i], sizeof(s->lpd.iou.gem[i]),
+ TYPE_CADENCE_GEM);
+ dev = DEVICE(&s->lpd.iou.gem[i]);
if (nd->used) {
qemu_check_nic_model(nd, "cadence_gem");
qdev_set_nic_properties(dev, nd);
}
- object_property_set_int(OBJECT(s->lpd.iou.gem[i]),
+ object_property_set_int(OBJECT(dev),
2, "num-priority-queues",
&error_abort);
- object_property_set_link(OBJECT(s->lpd.iou.gem[i]),
+ object_property_set_link(OBJECT(dev),
OBJECT(&s->mr_ps), "dma",
&error_abort);
qdev_init_nofail(dev);
- mr = sysbus_mmio_get_region(s->lpd.iou.gem[i], 0);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
- sysbus_connect_irq(s->lpd.iou.gem[i], 0, pic[irqs[i]]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
g_free(name);
}
}
@@ -203,22 +194,72 @@ static void versal_create_admas(Versal *s, qemu_irq *pic)
DeviceState *dev;
MemoryRegion *mr;
- dev = qdev_create(NULL, "xlnx.zdma");
- s->lpd.iou.adma[i] = SYS_BUS_DEVICE(dev);
- object_property_set_int(OBJECT(s->lpd.iou.adma[i]), 128, "bus-width",
- &error_abort);
- object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal);
+ sysbus_init_child_obj(OBJECT(s), name,
+ &s->lpd.iou.adma[i], sizeof(s->lpd.iou.adma[i]),
+ TYPE_XLNX_ZDMA);
+ dev = DEVICE(&s->lpd.iou.adma[i]);
+ object_property_set_int(OBJECT(dev), 128, "bus-width", &error_abort);
qdev_init_nofail(dev);
- mr = sysbus_mmio_get_region(s->lpd.iou.adma[i], 0);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->mr_ps,
MM_ADMA_CH0 + i * MM_ADMA_CH0_SIZE, mr);
- sysbus_connect_irq(s->lpd.iou.adma[i], 0, pic[VERSAL_ADMA_IRQ_0 + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_ADMA_IRQ_0 + i]);
g_free(name);
}
}
+#define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */
+static void versal_create_sds(Versal *s, qemu_irq *pic)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->pmc.iou.sd); i++) {
+ DeviceState *dev;
+ MemoryRegion *mr;
+
+ sysbus_init_child_obj(OBJECT(s), "sd[*]",
+ &s->pmc.iou.sd[i], sizeof(s->pmc.iou.sd[i]),
+ TYPE_SYSBUS_SDHCI);
+ dev = DEVICE(&s->pmc.iou.sd[i]);
+
+ object_property_set_uint(OBJECT(dev),
+ 3, "sd-spec-version", &error_fatal);
+ object_property_set_uint(OBJECT(dev), SDHCI_CAPABILITIES, "capareg",
+ &error_fatal);
+ object_property_set_uint(OBJECT(dev), UHS_I, "uhs", &error_fatal);
+ qdev_init_nofail(dev);
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(&s->mr_ps,
+ MM_PMC_SD0 + i * MM_PMC_SD0_SIZE, mr);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+ pic[VERSAL_SD0_IRQ_0 + i * 2]);
+ }
+}
+
+static void versal_create_rtc(Versal *s, qemu_irq *pic)
+{
+ SysBusDevice *sbd;
+ MemoryRegion *mr;
+
+ sysbus_init_child_obj(OBJECT(s), "rtc", &s->pmc.rtc, sizeof(s->pmc.rtc),
+ TYPE_XLNX_ZYNQMP_RTC);
+ sbd = SYS_BUS_DEVICE(&s->pmc.rtc);
+ qdev_init_nofail(DEVICE(sbd));
+
+ mr = sysbus_mmio_get_region(sbd, 0);
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_RTC, mr);
+
+ /*
+ * TODO: Connect the ALARM and SECONDS interrupts once our RTC model
+ * supports them.
+ */
+ sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]);
+}
+
/* This takes the board allocated linear DDR memory and creates aliases
* for each split DDR range/aperture on the Versal address map.
*/
@@ -301,6 +342,8 @@ static void versal_realize(DeviceState *dev, Error **errp)
versal_create_uarts(s, pic);
versal_create_gems(s, pic);
versal_create_admas(s, pic);
+ versal_create_sds(s, pic);
+ versal_create_rtc(s, pic);
versal_map_ddr(s);
versal_unimp(s);
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 17df5338e7..6c485d1c9e 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -441,7 +441,9 @@ reconnect:
virtio_err:
g_free(s->vhost_vqs);
+ s->vhost_vqs = NULL;
g_free(s->inflight);
+ s->inflight = NULL;
for (i = 0; i < s->num_queues; i++) {
virtio_delete_queue(s->virtqs[i]);
}
@@ -462,7 +464,9 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
vhost_dev_cleanup(&s->dev);
vhost_dev_free_inflight(s->inflight);
g_free(s->vhost_vqs);
+ s->vhost_vqs = NULL;
g_free(s->inflight);
+ s->inflight = NULL;
for (i = 0; i < s->num_queues; i++) {
virtio_delete_queue(s->virtqs[i]);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 227da69a50..d5627119ec 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -478,18 +478,19 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
cmd->u.surface_create.stride);
return 1;
}
- qemu_mutex_lock(&qxl->track_lock);
- if (cmd->type == QXL_SURFACE_CMD_CREATE) {
- qxl->guest_surfaces.cmds[id] = ext->cmd.data;
- qxl->guest_surfaces.count++;
- if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
- qxl->guest_surfaces.max = qxl->guest_surfaces.count;
- }
- if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
- qxl->guest_surfaces.cmds[id] = 0;
- qxl->guest_surfaces.count--;
+ WITH_QEMU_LOCK_GUARD(&qxl->track_lock) {
+ if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+ qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+ qxl->guest_surfaces.count++;
+ if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) {
+ qxl->guest_surfaces.max = qxl->guest_surfaces.count;
+ }
+ }
+ if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+ qxl->guest_surfaces.cmds[id] = 0;
+ qxl->guest_surfaces.count--;
+ }
}
- qemu_mutex_unlock(&qxl->track_lock);
break;
}
case QXL_CMD_CURSOR:
@@ -958,10 +959,9 @@ static void interface_update_area_complete(QXLInstance *sin,
int i;
int qxl_i;
- qemu_mutex_lock(&qxl->ssd.lock);
+ QEMU_LOCK_GUARD(&qxl->ssd.lock);
if (surface_id != 0 || !num_updated_rects ||
!qxl->render_update_cookie_num) {
- qemu_mutex_unlock(&qxl->ssd.lock);
return;
}
trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
@@ -980,7 +980,6 @@ static void interface_update_area_complete(QXLInstance *sin,
* Don't bother copying or scheduling the bh since we will flip
* the whole area anyway on completion of the update_area async call
*/
- qemu_mutex_unlock(&qxl->ssd.lock);
return;
}
qxl_i = qxl->num_dirty_rects;
@@ -991,7 +990,6 @@ static void interface_update_area_complete(QXLInstance *sin,
trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
qxl->num_dirty_rects);
qemu_bh_schedule(qxl->update_area_bh);
- qemu_mutex_unlock(&qxl->ssd.lock);
}
/* called from spice server thread context only */
@@ -1694,15 +1692,14 @@ static void ioport_write(void *opaque, hwaddr addr,
case QXL_IO_MONITORS_CONFIG_ASYNC:
async_common:
async = QXL_ASYNC;
- qemu_mutex_lock(&d->async_lock);
- if (d->current_async != QXL_UNDEFINED_IO) {
- qxl_set_guest_bug(d, "%d async started before last (%d) complete",
- io_port, d->current_async);
- qemu_mutex_unlock(&d->async_lock);
- return;
+ WITH_QEMU_LOCK_GUARD(&d->async_lock) {
+ if (d->current_async != QXL_UNDEFINED_IO) {
+ qxl_set_guest_bug(d, "%d async started before last (%d) complete",
+ io_port, d->current_async);
+ return;
+ }
+ d->current_async = orig_io_port;
}
- d->current_async = orig_io_port;
- qemu_mutex_unlock(&d->async_lock);
break;
default:
break;
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 2b4c2aa126..95757a6619 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -114,6 +114,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
*/
vpci_dev->modern_mem_bar_idx = 2;
vpci_dev->msix_bar_idx = 4;
+ vpci_dev->modern_io_bar_idx = 5;
if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) {
/*
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 8ca3706f5b..4ddafe1de1 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -15,6 +15,7 @@
#include "sysemu/kvm.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
+#include "qemu/lockable.h"
#include "qemu/queue.h"
#include "qemu/rcu.h"
#include "qemu/rcu_queue.h"
@@ -491,7 +492,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
int ret;
MsgHandler *mh;
- qemu_mutex_lock(&handlers_mutex);
+ QEMU_LOCK_GUARD(&handlers_mutex);
QLIST_FOREACH(mh, &msg_handlers, link) {
if (mh->conn_id == conn_id) {
if (handler) {
@@ -501,7 +502,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
g_free_rcu(mh, rcu);
ret = 0;
}
- goto unlock;
+ return ret;
}
}
@@ -515,8 +516,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
} else {
ret = -ENOENT;
}
-unlock:
- qemu_mutex_unlock(&handlers_mutex);
+
return ret;
}
@@ -565,7 +565,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
int ret;
EventFlagHandler *handler;
- qemu_mutex_lock(&handlers_mutex);
+ QEMU_LOCK_GUARD(&handlers_mutex);
QLIST_FOREACH(handler, &event_flag_handlers, link) {
if (handler->conn_id == conn_id) {
if (notifier) {
@@ -575,7 +575,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
g_free_rcu(handler, rcu);
ret = 0;
}
- goto unlock;
+ return ret;
}
}
@@ -588,8 +588,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
} else {
ret = -ENOENT;
}
-unlock:
- qemu_mutex_unlock(&handlers_mutex);
+
return ret;
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 23c77eeb95..2e15f6848e 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -128,6 +128,12 @@ typedef struct FwCfgTPMConfig {
static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg);
+const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio = {
+ .space_id = AML_AS_SYSTEM_IO,
+ .address = NVDIMM_ACPI_IO_BASE,
+ .bit_width = NVDIMM_ACPI_IO_LEN << 3
+};
+
static void init_common_fadt_data(MachineState *ms, Object *o,
AcpiFadtData *data)
{
@@ -1151,14 +1157,11 @@ static Aml *build_kbd_device_aml(void)
{
Aml *dev;
Aml *crs;
- Aml *method;
dev = aml_device("KBD");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0303")));
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0f)));
- aml_append(dev, method);
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
@@ -1173,14 +1176,11 @@ static Aml *build_mouse_device_aml(void)
{
Aml *dev;
Aml *crs;
- Aml *method;
dev = aml_device("MOU");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0f)));
- aml_append(dev, method);
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
crs = aml_resource_template();
aml_append(crs, aml_irq_no_flags(12));
@@ -1294,6 +1294,7 @@ static void build_isa_devices_aml(Aml *table)
error_report("No ISA bus, unable to define IPMI ACPI data");
} else {
build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
+ isa_build_aml(ISA_BUS(obj), scope);
}
aml_append(table, scope);
@@ -2238,9 +2239,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
TPM_CRB_ADDR_SIZE, AML_READ_WRITE));
aml_append(dev, aml_name_decl("_CRS", crs));
- method = aml_method("_STA", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_return(aml_int(0x0f)));
- aml_append(dev, method);
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
tpm_build_ppi_acpi(tpm, dev);
@@ -2513,6 +2512,34 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
build_header(linker, table_data, (void *)(table_data->data + dmar_start),
"DMAR", table_data->len - dmar_start, 1, NULL, NULL);
}
+
+/*
+ * Windows ACPI Emulated Devices Table
+ * (Version 1.0 - April 6, 2009)
+ * Spec: http://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/WAET.docx
+ *
+ * Helpful to speedup Windows guests and ignored by others.
+ */
+static void
+build_waet(GArray *table_data, BIOSLinker *linker)
+{
+ int waet_start = table_data->len;
+
+ /* WAET header */
+ acpi_data_push(table_data, sizeof(AcpiTableHeader));
+ /*
+ * Set "ACPI PM timer good" flag.
+ *
+ * Tells Windows guests that our ACPI PM timer is reliable in the
+ * sense that guest can read it only once to obtain a reliable value.
+ * Which avoids costly VMExits caused by guest re-reading it unnecessarily.
+ */
+ build_append_int_noprefix(table_data, 1 << 1 /* ACPI PM timer good */, 4);
+
+ build_header(linker, table_data, (void *)(table_data->data + waet_start),
+ "WAET", table_data->len - waet_start, 1, NULL, NULL);
+}
+
/*
* IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2
* accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf
@@ -2860,6 +2887,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
machine->nvdimms_state, machine->ram_slots);
}
+ acpi_add_table(table_offsets, tables_blob);
+ build_waet(tables_blob, tables->linker);
+
/* Add tables supplied by user (if any) */
for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
unsigned len = acpi_table_len(u);
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index 007332e51c..74df5fc612 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -1,6 +1,9 @@
#ifndef HW_I386_ACPI_BUILD_H
#define HW_I386_ACPI_BUILD_H
+#include "hw/acpi/acpi-defs.h"
+
+extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio;
void acpi_setup(void);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 5143c51653..f6b8431c8b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -91,6 +91,7 @@
#include "qapi/qmp/qerror.h"
#include "config-devices.h"
#include "e820_memory_layout.h"
+#include "vmport.h"
#include "fw_cfg.h"
#include "trace.h"
@@ -1152,7 +1153,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
i8042 = isa_create_simple(isa_bus, "i8042");
if (!no_vmport) {
- vmport_init(isa_bus);
+ isa_create_simple(isa_bus, TYPE_VMPORT);
vmmouse = isa_try_create(isa_bus, "vmmouse");
} else {
vmmouse = NULL;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 22dee0e76c..b75087d71b 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -61,6 +61,7 @@
#include "migration/misc.h"
#include "sysemu/numa.h"
#include "hw/mem/nvdimm.h"
+#include "hw/i386/acpi-build.h"
#define MAX_IDE_BUS 2
@@ -297,6 +298,7 @@ static void pc_init1(MachineState *machine,
if (machine->nvdimms_state->is_enabled) {
nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
+ x86_nvdimm_acpi_dsmio,
x86ms->fw_cfg, OBJECT(pcms));
}
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d37c425e22..d2806c1b29 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -54,6 +54,7 @@
#include "qemu/error-report.h"
#include "sysemu/numa.h"
#include "hw/mem/nvdimm.h"
+#include "hw/i386/acpi-build.h"
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
@@ -315,6 +316,7 @@ static void pc_q35_init(MachineState *machine)
if (machine->nvdimms_state->is_enabled) {
nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
+ x86_nvdimm_acpi_dsmio,
x86ms->fw_cfg, OBJECT(pcms));
}
}
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index e8e62bd96b..b3aef41327 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -25,10 +25,11 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "ui/console.h"
-#include "hw/i386/pc.h"
#include "hw/input/i8042.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
+#include "vmport.h"
+#include "cpu.h"
/* debug only vmmouse */
//#define DEBUG_VMMOUSE
@@ -70,6 +71,26 @@ typedef struct VMMouseState
ISAKBDState *i8042;
} VMMouseState;
+static void vmmouse_get_data(uint32_t *data)
+{
+ X86CPU *cpu = X86_CPU(current_cpu);
+ CPUX86State *env = &cpu->env;
+
+ data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+ data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+ data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+}
+
+static void vmmouse_set_data(const uint32_t *data)
+{
+ X86CPU *cpu = X86_CPU(current_cpu);
+ CPUX86State *env = &cpu->env;
+
+ env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+ env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+ env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
static uint32_t vmmouse_get_status(VMMouseState *s)
{
DPRINTF("vmmouse_get_status()\n");
diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c
index 1f31e27c8a..1aaaab691a 100644
--- a/hw/i386/vmport.c
+++ b/hw/i386/vmport.c
@@ -23,10 +23,10 @@
*/
#include "qemu/osdep.h"
#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-#include "hw/input/i8042.h"
#include "sysemu/hw_accel.h"
#include "qemu/log.h"
+#include "vmport.h"
+#include "cpu.h"
#include "trace.h"
#define VMPORT_CMD_GETVERSION 0x0a
@@ -109,27 +109,6 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
return ram_size;
}
-/* vmmouse helpers */
-void vmmouse_get_data(uint32_t *data)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
- CPUX86State *env = &cpu->env;
-
- data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
- data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
- data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
-}
-
-void vmmouse_set_data(const uint32_t *data)
-{
- X86CPU *cpu = X86_CPU(current_cpu);
- CPUX86State *env = &cpu->env;
-
- env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
- env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
- env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
-}
-
static const MemoryRegionOps vmport_ops = {
.read = vmport_ioport_read,
.write = vmport_ioport_write,
diff --git a/hw/i386/vmport.h b/hw/i386/vmport.h
new file mode 100644
index 0000000000..47eda7a22b
--- /dev/null
+++ b/hw/i386/vmport.h
@@ -0,0 +1,34 @@
+/*
+ * QEMU VMPort emulation
+ *
+ * Copyright (C) 2007 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_I386_VMPORT_H
+#define HW_I386_VMPORT_H
+
+#define TYPE_VMPORT "vmport"
+
+typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address);
+
+void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque);
+
+#endif
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 798dd9194e..1f2189f4d5 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -207,6 +207,21 @@ ISADevice *isa_vga_init(ISABus *bus)
}
}
+void isa_build_aml(ISABus *bus, Aml *scope)
+{
+ BusChild *kid;
+ ISADevice *dev;
+ ISADeviceClass *dc;
+
+ QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) {
+ dev = ISA_DEVICE(kid->child);
+ dc = ISA_DEVICE_GET_CLASS(dev);
+ if (dc->build_aml) {
+ dc->build_aml(dev, scope);
+ }
+ }
+}
+
static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
{
ISADevice *d = ISA_DEVICE(dev);
diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
index 2ad052a536..c27844900d 100644
--- a/hw/mem/Kconfig
+++ b/hw/mem/Kconfig
@@ -8,4 +8,4 @@ config MEM_DEVICE
config NVDIMM
bool
default y
- depends on (PC || PSERIES)
+ depends on (PC || PSERIES || ARM_VIRT)
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 0eb3a2a5d2..abc99b6eff 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -415,6 +415,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
{
PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
+ uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
PCIDevice *pci_dev = PCI_DEVICE(dev);
/* Don't send event when device is enabled during qemu machine creation:
@@ -430,6 +431,13 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
+ /* Check if hot-plug is disabled on the slot */
+ if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
+ error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'",
+ DEVICE(hotplug_pdev)->id);
+ return;
+ }
+
/* To enable multifunction hot-plug, we just ensure the function
* 0 added last. When function 0 is added, we set the sltsta and
* inform OS via event notification.
@@ -441,7 +449,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
}
- pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
+ pcie_cap_slot_event(hotplug_pdev,
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
}
}
@@ -470,8 +478,19 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
Error *local_err = NULL;
PCIDevice *pci_dev = PCI_DEVICE(dev);
PCIBus *bus = pci_get_bus(pci_dev);
+ PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
+ uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
+ uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
+
+ /* Check if hot-unplug is disabled on the slot */
+ if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
+ error_setg(errp, "Hot-unplug failed: "
+ "unsupported by the port device '%s'",
+ DEVICE(hotplug_pdev)->id);
+ return;
+ }
- pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err);
+ pcie_cap_slot_plug_common(hotplug_pdev, dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -490,7 +509,7 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
return;
}
- pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev));
+ pcie_cap_slot_push_attention_button(hotplug_pdev);
}
/* pci express slot for pci express root/downstream port
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
index 3dd39fe1a7..db7e5c8be5 100644
--- a/hw/rdma/rdma_backend.c
+++ b/hw/rdma/rdma_backend.c
@@ -95,36 +95,36 @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
struct ibv_wc wc[2];
RdmaProtectedGSList *cqe_ctx_list;
- qemu_mutex_lock(&rdma_dev_res->lock);
- do {
- ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc);
+ WITH_QEMU_LOCK_GUARD(&rdma_dev_res->lock) {
+ do {
+ ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc);
- trace_rdma_poll_cq(ne, ibcq);
+ trace_rdma_poll_cq(ne, ibcq);
- for (i = 0; i < ne; i++) {
- bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id);
- if (unlikely(!bctx)) {
- rdma_error_report("No matching ctx for req %"PRId64,
- wc[i].wr_id);
- continue;
- }
+ for (i = 0; i < ne; i++) {
+ bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id);
+ if (unlikely(!bctx)) {
+ rdma_error_report("No matching ctx for req %"PRId64,
+ wc[i].wr_id);
+ continue;
+ }
- comp_handler(bctx->up_ctx, &wc[i]);
+ comp_handler(bctx->up_ctx, &wc[i]);
- if (bctx->backend_qp) {
- cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list;
- } else {
- cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list;
- }
+ if (bctx->backend_qp) {
+ cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list;
+ } else {
+ cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list;
+ }
- rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id);
- rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
- g_free(bctx);
- }
- total_ne += ne;
- } while (ne > 0);
- atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne);
- qemu_mutex_unlock(&rdma_dev_res->lock);
+ rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id);
+ rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
+ g_free(bctx);
+ }
+ total_ne += ne;
+ } while (ne > 0);
+ atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne);
+ }
if (ne < 0) {
rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno);
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
index 7e9ea283c9..60957f88db 100644
--- a/hw/rdma/rdma_rm.c
+++ b/hw/rdma/rdma_rm.c
@@ -147,14 +147,13 @@ static inline void rdma_res_tbl_dealloc(RdmaRmResTbl *tbl, uint32_t handle)
{
trace_rdma_res_tbl_dealloc(tbl->name, handle);
- qemu_mutex_lock(&tbl->lock);
+ QEMU_LOCK_GUARD(&tbl->lock);
if (handle < tbl->tbl_sz) {
clear_bit(handle, tbl->bitmap);
tbl->used--;
}
- qemu_mutex_unlock(&tbl->lock);
}
int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index dc4269cc55..d18c09911b 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -908,7 +908,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
{
ISADevice *isadev = ISA_DEVICE(dev);
RTCState *s = MC146818_RTC(dev);
- int base = 0x70;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
@@ -951,7 +950,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
qemu_register_suspend_notifier(&s->suspend_notifier);
memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2);
- isa_register_ioport(isadev, &s->io, base);
+ isa_register_ioport(isadev, &s->io, RTC_ISA_BASE);
/* register rtc 0x70 port for coalesced_pio */
memory_region_set_flush_coalesced(&s->io);
@@ -960,7 +959,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
- qdev_set_legacy_instance_id(dev, base, 3);
+ qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3);
qemu_register_reset(rtc_reset, s);
object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL);
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 6b2952c034..ac2cefc9b1 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -22,6 +22,7 @@
#include "hw/vfio/vfio-platform.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
+#include "qemu/lockable.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/range.h"
@@ -216,7 +217,7 @@ static void vfio_intp_interrupt(VFIOINTp *intp)
VFIOPlatformDevice *vdev = intp->vdev;
bool delay_handling = false;
- qemu_mutex_lock(&vdev->intp_mutex);
+ QEMU_LOCK_GUARD(&vdev->intp_mutex);
if (intp->state == VFIO_IRQ_INACTIVE) {
QLIST_FOREACH(tmp, &vdev->intp_list, next) {
if (tmp->state == VFIO_IRQ_ACTIVE ||
@@ -236,7 +237,6 @@ static void vfio_intp_interrupt(VFIOINTp *intp)
QSIMPLEQ_INSERT_TAIL(&vdev->pending_intp_queue,
intp, pqnext);
ret = event_notifier_test_and_clear(intp->interrupt);
- qemu_mutex_unlock(&vdev->intp_mutex);
return;
}
@@ -266,7 +266,6 @@ static void vfio_intp_interrupt(VFIOINTp *intp)
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
vdev->mmap_timeout);
}
- qemu_mutex_unlock(&vdev->intp_mutex);
}
/**
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 08e7e63790..ec21e8fbe8 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -407,18 +407,79 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
return 0;
}
+static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
+ struct vhost_dev *dev,
+ VhostUserMsg *msg,
+ int *fds, size_t *fd_num,
+ bool track_ramblocks)
+{
+ int i, fd;
+ ram_addr_t offset;
+ MemoryRegion *mr;
+ struct vhost_memory_region *reg;
+
+ msg->hdr.request = VHOST_USER_SET_MEM_TABLE;
+
+ for (i = 0; i < dev->mem->nregions; ++i) {
+ reg = dev->mem->regions + i;
+
+ assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
+ mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr,
+ &offset);
+ fd = memory_region_get_fd(mr);
+ if (fd > 0) {
+ if (track_ramblocks) {
+ assert(*fd_num < VHOST_MEMORY_MAX_NREGIONS);
+ trace_vhost_user_set_mem_table_withfd(*fd_num, mr->name,
+ reg->memory_size,
+ reg->guest_phys_addr,
+ reg->userspace_addr,
+ offset);
+ u->region_rb_offset[i] = offset;
+ u->region_rb[i] = mr->ram_block;
+ } else if (*fd_num == VHOST_MEMORY_MAX_NREGIONS) {
+ error_report("Failed preparing vhost-user memory table msg");
+ return -1;
+ }
+ msg->payload.memory.regions[*fd_num].userspace_addr =
+ reg->userspace_addr;
+ msg->payload.memory.regions[*fd_num].memory_size =
+ reg->memory_size;
+ msg->payload.memory.regions[*fd_num].guest_phys_addr =
+ reg->guest_phys_addr;
+ msg->payload.memory.regions[*fd_num].mmap_offset = offset;
+ fds[(*fd_num)++] = fd;
+ } else if (track_ramblocks) {
+ u->region_rb_offset[i] = 0;
+ u->region_rb[i] = NULL;
+ }
+ }
+
+ msg->payload.memory.nregions = *fd_num;
+
+ if (!*fd_num) {
+ error_report("Failed initializing vhost-user memory map, "
+ "consider using -object memory-backend-file share=on");
+ return -1;
+ }
+
+ msg->hdr.size = sizeof(msg->payload.memory.nregions);
+ msg->hdr.size += sizeof(msg->payload.memory.padding);
+ msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion);
+
+ return 1;
+}
+
static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
struct vhost_memory *mem)
{
struct vhost_user *u = dev->opaque;
int fds[VHOST_MEMORY_MAX_NREGIONS];
- int i, fd;
size_t fd_num = 0;
VhostUserMsg msg_reply;
int region_i, msg_i;
VhostUserMsg msg = {
- .hdr.request = VHOST_USER_SET_MEM_TABLE,
.hdr.flags = VHOST_USER_VERSION,
};
@@ -433,48 +494,11 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
u->region_rb_len = dev->mem->nregions;
}
- for (i = 0; i < dev->mem->nregions; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- ram_addr_t offset;
- MemoryRegion *mr;
-
- assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
- mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr,
- &offset);
- fd = memory_region_get_fd(mr);
- if (fd > 0) {
- assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
- trace_vhost_user_set_mem_table_withfd(fd_num, mr->name,
- reg->memory_size,
- reg->guest_phys_addr,
- reg->userspace_addr, offset);
- u->region_rb_offset[i] = offset;
- u->region_rb[i] = mr->ram_block;
- msg.payload.memory.regions[fd_num].userspace_addr =
- reg->userspace_addr;
- msg.payload.memory.regions[fd_num].memory_size = reg->memory_size;
- msg.payload.memory.regions[fd_num].guest_phys_addr =
- reg->guest_phys_addr;
- msg.payload.memory.regions[fd_num].mmap_offset = offset;
- fds[fd_num++] = fd;
- } else {
- u->region_rb_offset[i] = 0;
- u->region_rb[i] = NULL;
- }
- }
-
- msg.payload.memory.nregions = fd_num;
-
- if (!fd_num) {
- error_report("Failed initializing vhost-user memory map, "
- "consider using -object memory-backend-file share=on");
+ if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num,
+ true) < 0) {
return -1;
}
- msg.hdr.size = sizeof(msg.payload.memory.nregions);
- msg.hdr.size += sizeof(msg.payload.memory.padding);
- msg.hdr.size += fd_num * sizeof(VhostUserMemoryRegion);
-
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1;
}
@@ -545,7 +569,6 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
{
struct vhost_user *u = dev->opaque;
int fds[VHOST_MEMORY_MAX_NREGIONS];
- int i, fd;
size_t fd_num = 0;
bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler;
bool reply_supported = virtio_has_feature(dev->protocol_features,
@@ -559,7 +582,6 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
}
VhostUserMsg msg = {
- .hdr.request = VHOST_USER_SET_MEM_TABLE,
.hdr.flags = VHOST_USER_VERSION,
};
@@ -567,42 +589,11 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
}
- for (i = 0; i < dev->mem->nregions; ++i) {
- struct vhost_memory_region *reg = dev->mem->regions + i;
- ram_addr_t offset;
- MemoryRegion *mr;
-
- assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
- mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr,
- &offset);
- fd = memory_region_get_fd(mr);
- if (fd > 0) {
- if (fd_num == VHOST_MEMORY_MAX_NREGIONS) {
- error_report("Failed preparing vhost-user memory table msg");
- return -1;
- }
- msg.payload.memory.regions[fd_num].userspace_addr =
- reg->userspace_addr;
- msg.payload.memory.regions[fd_num].memory_size = reg->memory_size;
- msg.payload.memory.regions[fd_num].guest_phys_addr =
- reg->guest_phys_addr;
- msg.payload.memory.regions[fd_num].mmap_offset = offset;
- fds[fd_num++] = fd;
- }
- }
-
- msg.payload.memory.nregions = fd_num;
-
- if (!fd_num) {
- error_report("Failed initializing vhost-user memory map, "
- "consider using -object memory-backend-file share=on");
+ if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num,
+ false) < 0) {
return -1;
}
- msg.hdr.size = sizeof(msg.payload.memory.nregions);
- msg.hdr.size += sizeof(msg.payload.memory.padding);
- msg.hdr.size += fd_num * sizeof(VhostUserMemoryRegion);
-
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1;
}
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 01ebe12f28..aff98a0ede 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1514,7 +1514,7 @@ void vhost_dev_set_config_notifier(struct vhost_dev *hdev,
void vhost_dev_free_inflight(struct vhost_inflight *inflight)
{
- if (inflight->addr) {
+ if (inflight && inflight->addr) {
qemu_memfd_free(inflight->addr, inflight->size, inflight->fd);
inflight->addr = NULL;
inflight->fd = -1;
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 4cb784389c..d028c17c24 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1705,6 +1705,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
*
* region 0 -- virtio legacy io bar
* region 1 -- msi-x bar
+ * region 2 -- virtio modern io bar (off by default)
* region 4+5 -- virtio modern memory (64bit) bar
*
*/
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 0f4ed53d7f..1539fe0667 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -33,7 +33,6 @@ struct Aml {
uint8_t op;
AmlBlockFlags block_flags;
};
-typedef struct Aml Aml;
typedef enum {
AML_COMPATIBILITY = 0,
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index d157eac088..9eb86ca4fd 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -82,6 +82,7 @@
*/
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
#define ACPI_GED_PWR_DOWN_EVT 0x2
+#define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4
typedef struct GEDState {
MemoryRegion io;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 60b2f521eb..6d67ace76e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -79,6 +79,7 @@ enum {
VIRT_SECURE_MEM,
VIRT_PCDIMM_ACPI,
VIRT_ACPI_GED,
+ VIRT_NVDIMM_ACPI,
VIRT_LOWMEMMAP_LAST,
};
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
index 6c0a692b2f..9c9f47ba9d 100644
--- a/include/hw/arm/xlnx-versal.h
+++ b/include/hw/arm/xlnx-versal.h
@@ -14,7 +14,12 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
+#include "hw/sd/sdhci.h"
#include "hw/intc/arm_gicv3.h"
+#include "hw/char/pl011.h"
+#include "hw/dma/xlnx-zdma.h"
+#include "hw/net/cadence_gem.h"
+#include "hw/rtc/xlnx-zynqmp-rtc.h"
#define TYPE_XLNX_VERSAL "xlnx-versal"
#define XLNX_VERSAL(obj) OBJECT_CHECK(Versal, (obj), TYPE_XLNX_VERSAL)
@@ -23,6 +28,7 @@
#define XLNX_VERSAL_NR_UARTS 2
#define XLNX_VERSAL_NR_GEMS 2
#define XLNX_VERSAL_NR_ADMAS 8
+#define XLNX_VERSAL_NR_SDS 2
#define XLNX_VERSAL_NR_IRQS 192
typedef struct Versal {
@@ -33,7 +39,7 @@ typedef struct Versal {
struct {
struct {
MemoryRegion mr;
- ARMCPU *cpu[XLNX_VERSAL_NR_ACPUS];
+ ARMCPU cpu[XLNX_VERSAL_NR_ACPUS];
GICv3State gic;
} apu;
} fpd;
@@ -49,12 +55,21 @@ typedef struct Versal {
MemoryRegion mr_ocm;
struct {
- SysBusDevice *uart[XLNX_VERSAL_NR_UARTS];
- SysBusDevice *gem[XLNX_VERSAL_NR_GEMS];
- SysBusDevice *adma[XLNX_VERSAL_NR_ADMAS];
+ PL011State uart[XLNX_VERSAL_NR_UARTS];
+ CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
+ XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
} iou;
} lpd;
+ /* The Platform Management Controller subsystem. */
+ struct {
+ struct {
+ SDHCIState sd[XLNX_VERSAL_NR_SDS];
+ } iou;
+
+ XlnxZynqMPRTC rtc;
+ } pmc;
+
struct {
MemoryRegion *mr_ddr;
uint32_t psci_conduit;
@@ -77,6 +92,10 @@ typedef struct Versal {
#define VERSAL_GEM1_IRQ_0 58
#define VERSAL_GEM1_WAKE_IRQ_0 59
#define VERSAL_ADMA_IRQ_0 60
+#define VERSAL_RTC_APB_ERR_IRQ 121
+#define VERSAL_SD0_IRQ_0 126
+#define VERSAL_RTC_ALARM_IRQ 142
+#define VERSAL_RTC_SECONDS_IRQ 143
/* Architecturally reserved IRQs suitable for virtualization. */
#define VERSAL_RSVD_IRQ_FIRST 111
@@ -126,6 +145,10 @@ typedef struct Versal {
#define MM_FPD_CRF 0xfd1a0000U
#define MM_FPD_CRF_SIZE 0x140000
+#define MM_PMC_SD0 0xf1040000U
+#define MM_PMC_SD0_SIZE 0x10000
#define MM_PMC_CRP 0xf1260000U
#define MM_PMC_CRP_SIZE 0x10000
+#define MM_PMC_RTC 0xf12a0000
+#define MM_PMC_RTC_SIZE 0x10000
#endif
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 6ab6eda046..05e19455bb 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -129,19 +129,6 @@ typedef struct PCMachineClass {
GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled);
-/* vmport.c */
-#define TYPE_VMPORT "vmport"
-typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address);
-
-static inline void vmport_init(ISABus *bus)
-{
- isa_create_simple(bus, TYPE_VMPORT);
-}
-
-void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque);
-void vmmouse_get_data(uint32_t *data);
-void vmmouse_set_data(const uint32_t *data);
-
/* pc.c */
extern int fd_bootchk;
diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h
index 59a4d4b50a..02c2350274 100644
--- a/include/hw/isa/isa.h
+++ b/include/hw/isa/isa.h
@@ -69,6 +69,7 @@ typedef struct IsaDmaClass {
typedef struct ISADeviceClass {
DeviceClass parent_class;
+ void (*build_aml)(ISADevice *dev, Aml *scope);
} ISADeviceClass;
struct ISABus {
@@ -107,6 +108,7 @@ ISADevice *isa_try_create(ISABus *bus, const char *name);
ISADevice *isa_create_simple(ISABus *bus, const char *name);
ISADevice *isa_vga_init(ISABus *bus);
+void isa_build_aml(ISABus *bus, Aml *scope);
/**
* isa_register_ioport: Install an I/O port region on the ISA bus.
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index 4807ca615b..a3c08955e8 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -26,6 +26,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/acpi/bios-linker-loader.h"
#include "qemu/uuid.h"
+#include "hw/acpi/aml-build.h"
#define NVDIMM_DEBUG 0
#define nvdimm_debug(fmt, ...) \
@@ -147,10 +148,12 @@ struct NVDIMMState {
*/
int32_t persistence;
char *persistence_string;
+ struct AcpiGenericAddress dsm_io;
};
typedef struct NVDIMMState NVDIMMState;
void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
+ struct AcpiGenericAddress dsm_io,
FWCfgState *fw_cfg, Object *owner);
void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
BIOSLinker *linker, NVDIMMState *state,
diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h
index 10c93a096a..3713181b56 100644
--- a/include/hw/rtc/mc146818rtc.h
+++ b/include/hw/rtc/mc146818rtc.h
@@ -47,6 +47,7 @@ typedef struct RTCState {
} RTCState;
#define RTC_ISA_IRQ 8
+#define RTC_ISA_BASE 0x70
ISADevice *mc146818_rtc_init(ISABus *bus, int base_year,
qemu_irq intercept_irq);
diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index 1aeb2cb1a6..b620023141 100644
--- a/include/qemu/lockable.h
+++ b/include/qemu/lockable.h
@@ -152,7 +152,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
* }
*/
#define WITH_QEMU_LOCK_GUARD(x) \
- WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__)
+ WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
/**
* QEMU_LOCK_GUARD - Lock an object until the end of the scope
@@ -169,8 +169,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
* return; <-- mutex is automatically unlocked
* }
*/
-#define QEMU_LOCK_GUARD(x) \
- g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \
+#define QEMU_LOCK_GUARD(x) \
+ g_autoptr(QemuLockable) \
+ glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
#endif
diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
index 9c82683e37..570aa603eb 100644
--- a/include/qemu/rcu.h
+++ b/include/qemu/rcu.h
@@ -170,7 +170,7 @@ static inline void rcu_read_auto_unlock(RCUReadAuto *r)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock)
#define WITH_RCU_READ_LOCK_GUARD() \
- WITH_RCU_READ_LOCK_GUARD_(_rcu_read_auto##__COUNTER__)
+ WITH_RCU_READ_LOCK_GUARD_(glue(_rcu_read_auto, __COUNTER__))
#define WITH_RCU_READ_LOCK_GUARD_(var) \
for (g_autoptr(RCUReadAuto) var = rcu_read_auto_lock(); \
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 375770a80f..ecf3cde26c 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -24,6 +24,7 @@
typedef struct AdapterInfo AdapterInfo;
typedef struct AddressSpace AddressSpace;
typedef struct AioContext AioContext;
+typedef struct Aml Aml;
typedef struct AnnounceTimer AnnounceTimer;
typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
diff --git a/migration/migration.c b/migration/migration.c
index 187ac0410c..177cce9e95 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1653,11 +1653,10 @@ static void migrate_fd_cleanup_bh(void *opaque)
void migrate_set_error(MigrationState *s, const Error *error)
{
- qemu_mutex_lock(&s->error_mutex);
+ QEMU_LOCK_GUARD(&s->error_mutex);
if (!s->error) {
s->error = error_copy(error);
}
- qemu_mutex_unlock(&s->error_mutex);
}
void migrate_fd_error(MigrationState *s, const Error *error)
diff --git a/migration/multifd.c b/migration/multifd.c
index cb6a4a3ab8..9123c111a3 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -894,11 +894,11 @@ void multifd_recv_sync_main(void)
for (i = 0; i < migrate_multifd_channels(); i++) {
MultiFDRecvParams *p = &multifd_recv_state->params[i];
- qemu_mutex_lock(&p->mutex);
- if (multifd_recv_state->packet_num < p->packet_num) {
- multifd_recv_state->packet_num = p->packet_num;
+ WITH_QEMU_LOCK_GUARD(&p->mutex) {
+ if (multifd_recv_state->packet_num < p->packet_num) {
+ multifd_recv_state->packet_num = p->packet_num;
+ }
}
- qemu_mutex_unlock(&p->mutex);
trace_multifd_recv_sync_main_signal(p->id);
qemu_sem_post(&p->sem_sync);
}
diff --git a/migration/ram.c b/migration/ram.c
index 06cba88632..53166fc279 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1369,7 +1369,7 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
return NULL;
}
- qemu_mutex_lock(&rs->src_page_req_mutex);
+ QEMU_LOCK_GUARD(&rs->src_page_req_mutex);
if (!QSIMPLEQ_EMPTY(&rs->src_page_requests)) {
struct RAMSrcPageRequest *entry =
QSIMPLEQ_FIRST(&rs->src_page_requests);
@@ -1386,7 +1386,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
migration_consume_urgent_request();
}
}
- qemu_mutex_unlock(&rs->src_page_req_mutex);
return block;
}
diff --git a/monitor/misc.c b/monitor/misc.c
index 6c45fa490f..9723b466cd 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -1473,7 +1473,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
MonFdsetFd *mon_fdset_fd;
AddfdInfo *fdinfo;
- qemu_mutex_lock(&mon_fdsets_lock);
+ QEMU_LOCK_GUARD(&mon_fdsets_lock);
if (has_fdset_id) {
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
/* Break if match found or match impossible due to ordering by ID */
@@ -1494,7 +1494,6 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
if (fdset_id < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
"a non-negative value");
- qemu_mutex_unlock(&mon_fdsets_lock);
return NULL;
}
/* Use specified fdset ID */
@@ -1545,7 +1544,6 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
fdinfo->fdset_id = mon_fdset->id;
fdinfo->fd = mon_fdset_fd->fd;
- qemu_mutex_unlock(&mon_fdsets_lock);
return fdinfo;
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index e658e6546f..0ba213e9f2 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -35,8 +35,6 @@ my $summary_file = 0;
my $root;
my %debug;
my $help = 0;
-my $acpi_testexpected;
-my $acpi_nontestexpected;
sub help {
my ($exitcode) = @_;
@@ -1261,21 +1259,23 @@ sub WARN {
# According to tests/qtest/bios-tables-test.c: do not
# change expected file in the same commit with adding test
sub checkfilename {
- my ($name) = @_;
- if ($name =~ m#^tests/data/acpi/# and
- # make exception for a shell script that rebuilds the files
- not $name =~ m#^\.sh$# or
- $name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) {
- $acpi_testexpected = $name;
- } else {
- $acpi_nontestexpected = $name;
+ my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_;
+
+ # Note: shell script that rebuilds the expected files is in the same
+ # directory as files themselves.
+ # Note: allowed diff list can be changed both when changing expected
+ # files and when changing tests.
+ if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) {
+ $$acpi_testexpected = $name;
+ } elsif ($name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) {
+ $$acpi_nontestexpected = $name;
}
- if (defined $acpi_testexpected and defined $acpi_nontestexpected) {
+ if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) {
ERROR("Do not add expected files together with tests, " .
"follow instructions in " .
"tests/qtest/bios-tables-test.c: both " .
- $acpi_testexpected . " and " .
- $acpi_nontestexpected . " found\n");
+ $$acpi_testexpected . " and " .
+ $$acpi_nontestexpected . " found\n");
}
}
@@ -1325,6 +1325,9 @@ sub process {
my %suppress_whiletrailers;
my %suppress_export;
+ my $acpi_testexpected;
+ my $acpi_nontestexpected;
+
# Pre-scan the patch sanitizing the lines.
sanitise_line_reset();
@@ -1454,11 +1457,11 @@ sub process {
if ($line =~ /^diff --git.*?(\S+)$/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@ if (!$file);
- checkfilename($realfile);
+ checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected);
} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@ if (!$file);
- checkfilename($realfile);
+ checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected);
$p1_prefix = $1;
if (!$file && $tree && $p1_prefix ne '' &&
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index cf26c16f5f..775b3e24f2 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -18,6 +18,21 @@ target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE)
$(PYTHON) $(DECODETREE) --decode disas_sve -o $@ $<,\
"GEN", $(TARGET_DIR)$@)
+target/arm/decode-neon-shared.inc.c: $(SRC_PATH)/target/arm/neon-shared.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_neon_shared -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
+target/arm/decode-neon-dp.inc.c: $(SRC_PATH)/target/arm/neon-dp.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_neon_dp -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
+target/arm/decode-neon-ls.inc.c: $(SRC_PATH)/target/arm/neon-ls.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_neon_ls -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
target/arm/decode-vfp.inc.c: $(SRC_PATH)/target/arm/vfp.decode $(DECODETREE)
$(call quiet-command,\
$(PYTHON) $(DECODETREE) --static-decode disas_vfp -o $@ $<,\
@@ -49,6 +64,9 @@ target/arm/decode-t16.inc.c: $(SRC_PATH)/target/arm/t16.decode $(DECODETREE)
"GEN", $(TARGET_DIR)$@)
target/arm/translate-sve.o: target/arm/decode-sve.inc.c
+target/arm/translate.o: target/arm/decode-neon-shared.inc.c
+target/arm/translate.o: target/arm/decode-neon-dp.inc.c
+target/arm/translate.o: target/arm/decode-neon-ls.inc.c
target/arm/translate.o: target/arm/decode-vfp.inc.c
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
target/arm/translate.o: target/arm/decode-a32.inc.c
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
index d593b60b28..6321385b46 100644
--- a/target/arm/cpu-param.h
+++ b/target/arm/cpu-param.h
@@ -29,6 +29,6 @@
# define TARGET_PAGE_BITS_MIN 10
#endif
-#define NB_MMU_MODES 12
+#define NB_MMU_MODES 11
#endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 141d947775..5d64adfe76 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2686,6 +2686,7 @@ static void arm_max_initfn(Object *obj)
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */
+ t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */
cpu->isar.id_mmfr4 = t;
}
#endif
@@ -2754,7 +2755,7 @@ static const ARMCPUInfo arm_cpus[] = {
static Property arm_cpu_properties[] = {
DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false),
DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0),
- DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0),
+ DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0),
DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
mp_affinity, ARM64_AFFINITY_INVALID),
DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 8b9f2961ba..8608da6b6f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -894,7 +894,7 @@ struct ARMCPU {
uint64_t id_aa64dfr0;
uint64_t id_aa64dfr1;
} isar;
- uint32_t midr;
+ uint64_t midr;
uint32_t revidr;
uint32_t reset_fpsid;
uint32_t ctr;
@@ -2801,6 +2801,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* handling via the TLB. The only way to do a stage 1 translation without
* the immediate stage 2 translation is via the ATS or AT system insns,
* which can be slow-pathed and always do a page table walk.
+ * The only use of stage 2 translations is either as part of an s1+2
+ * lookup or when loading the descriptors during a stage 1 page table walk,
+ * and in both those cases we don't use the TLB.
* 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3"
* translation regimes, because they map reasonably well to each other
* and they can't both be active at the same time.
@@ -2816,15 +2819,15 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* NS EL1 EL1&0 stage 1+2 (aka NS PL1)
* NS EL1 EL1&0 stage 1+2 +PAN
* NS EL0 EL2&0
+ * NS EL2 EL2&0
* NS EL2 EL2&0 +PAN
* NS EL2 (aka NS PL2)
* S EL0 EL1&0 (aka S PL0)
* S EL1 EL1&0 (not used if EL3 is 32 bit)
* S EL1 EL1&0 +PAN
* S EL3 (aka S PL1)
- * NS EL1&0 stage 2
*
- * for a total of 12 different mmu_idx.
+ * for a total of 11 different mmu_idx.
*
* R profile CPUs have an MPU, but can use the same set of MMU indexes
* as A profile. They only need to distinguish NS EL0 and NS EL1 (and
@@ -2846,7 +2849,8 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* are not quite the same -- different CPU types (most notably M profile
* vs A/R profile) would like to use MMU indexes with different semantics,
* but since we don't ever need to use all of those in a single CPU we
- * can avoid setting NB_MMU_MODES to more than 8. The lower bits of
+ * can avoid having to set NB_MMU_MODES to "total number of A profile MMU
+ * modes + total number of M profile MMU modes". The lower bits of
* ARMMMUIdx are the core TLB mmu index, and the higher bits are always
* the same for any particular CPU.
* Variables of type ARMMUIdx are always full values, and the core
@@ -2894,8 +2898,6 @@ typedef enum ARMMMUIdx {
ARMMMUIdx_SE10_1_PAN = 9 | ARM_MMU_IDX_A,
ARMMMUIdx_SE3 = 10 | ARM_MMU_IDX_A,
- ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A,
-
/*
* These are not allocated TLBs and are used only for AT system
* instructions or for the first stage of an S12 page table walk.
@@ -2903,6 +2905,14 @@ typedef enum ARMMMUIdx {
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB,
+ /*
+ * Not allocated a TLB: used only for second stage of an S12 page
+ * table walk, or for descriptor loads during first stage of an S1
+ * page table walk. Note that if we ever want to have a TLB for this
+ * then various TLB flush insns which currently are no-ops or flush
+ * only stage 1 MMU indexes will need to change to flush stage 2.
+ */
+ ARMMMUIdx_Stage2 = 3 | ARM_MMU_IDX_NOTLB,
/*
* M-profile.
@@ -2936,7 +2946,6 @@ typedef enum ARMMMUIdxBit {
TO_CORE_BIT(SE10_1),
TO_CORE_BIT(SE10_1_PAN),
TO_CORE_BIT(SE3),
- TO_CORE_BIT(Stage2),
TO_CORE_BIT(MUser),
TO_CORE_BIT(MPriv),
@@ -3601,6 +3610,11 @@ static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id)
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0;
}
+static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id)
+{
+ return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0;
+}
+
/*
* 64-bit feature tests via id registers.
*/
@@ -3813,6 +3827,11 @@ static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
}
+static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0;
+}
+
/*
* Feature tests for "does this exist in either 32-bit or 64-bit?"
*/
@@ -3841,6 +3860,11 @@ static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)
return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id);
}
+static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id)
+{
+ return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id);
+}
+
/*
* Forward to the above feature tests given an ARMCPU pointer.
*/
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 74afc28d53..9bdf75b1ab 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -673,6 +673,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1);
t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */
t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */
+ t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */
cpu->isar.id_aa64mmfr1 = t;
t = cpu->isar.id_aa64mmfr2;
@@ -706,11 +707,12 @@ static void aarch64_max_initfn(Object *obj)
u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */
u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */
+ u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */
cpu->isar.id_mmfr4 = u;
- u = cpu->isar.id_aa64dfr0;
- u = FIELD_DP64(u, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */
- cpu->isar.id_aa64dfr0 = u;
+ t = cpu->isar.id_aa64dfr0;
+ t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */
+ cpu->isar.id_aa64dfr0 = t;
u = cpu->isar.id_dfr0;
u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index dfefb9b3d9..a94f650795 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -41,6 +41,7 @@
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ bool s1_is_el0,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr,
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
@@ -814,8 +815,7 @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0 |
- ARMMMUIdxBit_Stage2);
+ ARMMMUIdxBit_E10_0);
}
static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -826,46 +826,9 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush_by_mmuidx_all_cpus_synced(cs,
ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0 |
- ARMMMUIdxBit_Stage2);
+ ARMMMUIdxBit_E10_0);
}
-static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate by IPA. This has to invalidate any structures that
- * contain only stage 2 translation information, but does not need
- * to apply to structures that contain combined stage 1 and stage 2
- * translation information.
- * This must NOP if EL2 isn't implemented or SCR_EL3.NS is zero.
- */
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr;
-
- if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) {
- return;
- }
-
- pageaddr = sextract64(value << 12, 0, 40);
-
- tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
-}
-
-static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr;
-
- if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) {
- return;
- }
-
- pageaddr = sextract64(value << 12, 0, 40);
-
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_Stage2);
-}
static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
@@ -4055,8 +4018,7 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0 |
- ARMMMUIdxBit_Stage2);
+ ARMMMUIdxBit_E10_0);
raw_write(env, ri, value);
}
}
@@ -4538,11 +4500,6 @@ static int alle1_tlbmask(CPUARMState *env)
return ARMMMUIdxBit_SE10_1 |
ARMMMUIdxBit_SE10_1_PAN |
ARMMMUIdxBit_SE10_0;
- } else if (arm_feature(env, ARM_FEATURE_EL2)) {
- return ARMMMUIdxBit_E10_1 |
- ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0 |
- ARMMMUIdxBit_Stage2;
} else {
return ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
@@ -4689,44 +4646,6 @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
ARMMMUIdxBit_SE3);
}
-static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- /* Invalidate by IPA. This has to invalidate any structures that
- * contain only stage 2 translation information, but does not need
- * to apply to structures that contain combined stage 1 and stage 2
- * translation information.
- * This must NOP if EL2 isn't implemented or SCR_EL3.NS is zero.
- */
- ARMCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
- uint64_t pageaddr;
-
- if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) {
- return;
- }
-
- pageaddr = sextract64(value << 12, 0, 48);
-
- tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
-}
-
-static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- CPUState *cs = env_cpu(env);
- uint64_t pageaddr;
-
- if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) {
- return;
- }
-
- pageaddr = sextract64(value << 12, 0, 48);
-
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_Stage2);
-}
-
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -4965,12 +4884,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.writefn = tlbi_aa64_vae1_write },
{ .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1is_write },
+ .access = PL2_W, .type = ARM_CP_NOP },
{ .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1is_write },
+ .access = PL2_W, .type = ARM_CP_NOP },
{ .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
.access = PL2_W, .type = ARM_CP_NO_RAW,
@@ -4981,12 +4898,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.writefn = tlbi_aa64_alle1is_write },
{ .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1_write },
+ .access = PL2_W, .type = ARM_CP_NOP },
{ .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW,
- .writefn = tlbi_aa64_ipas2e1_write },
+ .access = PL2_W, .type = ARM_CP_NOP },
{ .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
.access = PL2_W, .type = ARM_CP_NO_RAW,
@@ -5067,20 +4982,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.writefn = tlbimva_hyp_is_write },
{ .name = "TLBIIPAS2",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_write },
+ .type = ARM_CP_NOP, .access = PL2_W },
{ .name = "TLBIIPAS2IS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_is_write },
+ .type = ARM_CP_NOP, .access = PL2_W },
{ .name = "TLBIIPAS2L",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_write },
+ .type = ARM_CP_NOP, .access = PL2_W },
{ .name = "TLBIIPAS2LIS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
- .type = ARM_CP_NO_RAW, .access = PL2_W,
- .writefn = tlbiipas2_is_write },
+ .type = ARM_CP_NOP, .access = PL2_W },
/* 32 bit cache operations */
{ .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
.type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access },
@@ -9997,9 +9908,10 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap)
*
* @env: CPUARMState
* @s2ap: The 2-bit stage2 access permissions (S2AP)
- * @xn: XN (execute-never) bit
+ * @xn: XN (execute-never) bits
+ * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0
*/
-static int get_S2prot(CPUARMState *env, int s2ap, int xn)
+static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0)
{
int prot = 0;
@@ -10009,9 +9921,32 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn)
if (s2ap & 2) {
prot |= PAGE_WRITE;
}
- if (!xn) {
- if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) {
+
+ if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) {
+ switch (xn) {
+ case 0:
prot |= PAGE_EXEC;
+ break;
+ case 1:
+ if (s1_is_el0) {
+ prot |= PAGE_EXEC;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ if (!s1_is_el0) {
+ prot |= PAGE_EXEC;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ } else {
+ if (!extract32(xn, 1, 1)) {
+ if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) {
+ prot |= PAGE_EXEC;
+ }
}
}
return prot;
@@ -10142,8 +10077,10 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
pcacheattrs = &cacheattrs;
}
- ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_Stage2, &s2pa,
- &txattrs, &s2prot, &s2size, fi, pcacheattrs);
+ ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, ARMMMUIdx_Stage2,
+ false,
+ &s2pa, &txattrs, &s2prot, &s2size, fi,
+ pcacheattrs);
if (ret) {
assert(fi->type != ARMFault_None);
fi->s2addr = addr;
@@ -10744,8 +10681,32 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,
};
}
+/**
+ * get_phys_addr_lpae: perform one stage of page table walk, LPAE format
+ *
+ * Returns false if the translation was successful. Otherwise, phys_ptr, attrs,
+ * prot and page_size may not be filled in, and the populated fsr value provides
+ * information on why the translation aborted, in the format of a long-format
+ * DFSR/IFSR fault register, with the following caveats:
+ * * the WnR bit is never set (the caller must do this).
+ *
+ * @env: CPUARMState
+ * @address: virtual address to get physical address for
+ * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH
+ * @mmu_idx: MMU index indicating required translation regime
+ * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page table
+ * walk), must be true if this is stage 2 of a stage 1+2 walk for an
+ * EL0 access). If @mmu_idx is anything else, @s1_is_el0 is ignored.
+ * @phys_ptr: set to the physical address corresponding to the virtual address
+ * @attrs: set to the memory transaction attributes to use
+ * @prot: set to the permissions for the page containing phys_ptr
+ * @page_size_ptr: set to the size of the page containing phys_ptr
+ * @fi: set to fault info if the translation fails
+ * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes
+ */
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ bool s1_is_el0,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr,
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
@@ -10964,13 +10925,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
}
ap = extract32(attrs, 4, 2);
- xn = extract32(attrs, 12, 1);
if (mmu_idx == ARMMMUIdx_Stage2) {
ns = true;
- *prot = get_S2prot(env, ap, xn);
+ xn = extract32(attrs, 11, 2);
+ *prot = get_S2prot(env, ap, xn, s1_is_el0);
} else {
ns = extract32(attrs, 3, 1);
+ xn = extract32(attrs, 12, 1);
pxn = extract32(attrs, 11, 1);
*prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn);
}
@@ -11837,6 +11799,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
/* S1 is done. Now do S2 translation. */
ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_Stage2,
+ mmu_idx == ARMMMUIdx_E10_0,
phys_ptr, attrs, &s2_prot,
page_size, fi,
cacheattrs != NULL ? &cacheattrs2 : NULL);
@@ -11961,7 +11924,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
}
if (regime_using_lpae_format(env, mmu_idx)) {
- return get_phys_addr_lpae(env, address, access_type, mmu_idx,
+ return get_phys_addr_lpae(env, address, access_type, mmu_idx, false,
phys_ptr, attrs, prot, page_size,
fi, cacheattrs);
} else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
new file mode 100644
index 0000000000..ec3a92fe75
--- /dev/null
+++ b/target/arm/neon-dp.decode
@@ -0,0 +1,86 @@
+# AArch32 Neon data-processing instruction descriptions
+#
+# Copyright (c) 2020 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+# VFP/Neon register fields; same as vfp.decode
+%vm_dp 5:1 0:4
+%vn_dp 7:1 16:4
+%vd_dp 22:1 12:4
+
+# Encodings for Neon data processing instructions where the T32 encoding
+# is a simple transformation of the A32 encoding.
+# More specifically, this file covers instructions where the A32 encoding is
+# 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+# and the T32 encoding is
+# 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+# This file works on the A32 encoding only; calling code for T32 has to
+# transform the insn into the A32 version first.
+
+######################################################################
+# 3-reg-same grouping:
+# 1111 001 U 0 D sz:2 Vn:4 Vd:4 opc:4 N Q M op Vm:4
+######################################################################
+
+&3same vm vn vd q size
+
+@3same .... ... . . . size:2 .... .... .... . q:1 . . .... \
+ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same
+VQADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 1 .... @3same
+
+@3same_logic .... ... . . . .. .... .... .... . q:1 .. .... \
+ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0
+
+VAND_3s 1111 001 0 0 . 00 .... .... 0001 ... 1 .... @3same_logic
+VBIC_3s 1111 001 0 0 . 01 .... .... 0001 ... 1 .... @3same_logic
+VORR_3s 1111 001 0 0 . 10 .... .... 0001 ... 1 .... @3same_logic
+VORN_3s 1111 001 0 0 . 11 .... .... 0001 ... 1 .... @3same_logic
+VEOR_3s 1111 001 1 0 . 00 .... .... 0001 ... 1 .... @3same_logic
+VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic
+VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic
+VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic
+
+VQSUB_S_3s 1111 001 0 0 . .. .... .... 0010 . . . 1 .... @3same
+VQSUB_U_3s 1111 001 1 0 . .. .... .... 0010 . . . 1 .... @3same
+
+VCGT_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 0 .... @3same
+VCGT_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 0 .... @3same
+VCGE_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 1 .... @3same
+VCGE_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 1 .... @3same
+
+VSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 0 .... @3same
+VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same
+
+VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same
+VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same
+VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same
+VMIN_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 1 .... @3same
+
+VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same
+VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same
+
+VTST_3s 1111 001 0 0 . .. .... .... 1000 . . . 1 .... @3same
+VCEQ_3s 1111 001 1 0 . .. .... .... 1000 . . . 1 .... @3same
+
+VMLA_3s 1111 001 0 0 . .. .... .... 1001 . . . 0 .... @3same
+VMLS_3s 1111 001 1 0 . .. .... .... 1001 . . . 0 .... @3same
+
+VMUL_3s 1111 001 0 0 . .. .... .... 1001 . . . 1 .... @3same
+VMUL_p_3s 1111 001 1 0 . .. .... .... 1001 . . . 1 .... @3same
diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode
new file mode 100644
index 0000000000..c7b03a72e8
--- /dev/null
+++ b/target/arm/neon-ls.decode
@@ -0,0 +1,52 @@
+# AArch32 Neon load/store instruction descriptions
+#
+# Copyright (c) 2020 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+
+# Encodings for Neon load/store instructions where the T32 encoding
+# is a simple transformation of the A32 encoding.
+# More specifically, this file covers instructions where the A32 encoding is
+# 0b1111_0100_xxx0_xxxx_xxxx_xxxx_xxxx_xxxx
+# and the T32 encoding is
+# 0b1111_1001_xxx0_xxxx_xxxx_xxxx_xxxx_xxxx
+# This file works on the A32 encoding only; calling code for T32 has to
+# transform the insn into the A32 version first.
+
+%vd_dp 22:1 12:4
+
+# Neon load/store multiple structures
+
+VLDST_multiple 1111 0100 0 . l:1 0 rn:4 .... itype:4 size:2 align:2 rm:4 \
+ vd=%vd_dp
+
+# Neon load single element to all lanes
+
+VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \
+ vd=%vd_dp
+
+# Neon load/store single structure to one lane
+%imm1_5_p1 5:1 !function=plus1
+%imm1_6_p1 6:1 !function=plus1
+
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \
+ vd=%vd_dp size=0 stride=1
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 align:2 rm:4 \
+ vd=%vd_dp size=1 stride=%imm1_5_p1
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 align:3 rm:4 \
+ vd=%vd_dp size=2 stride=%imm1_6_p1
diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode
new file mode 100644
index 0000000000..f297ba8cdf
--- /dev/null
+++ b/target/arm/neon-shared.decode
@@ -0,0 +1,66 @@
+# AArch32 Neon instruction descriptions
+#
+# Copyright (c) 2020 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+
+# Encodings for Neon instructions whose encoding is the same for
+# both A32 and T32.
+
+# More specifically, this covers:
+# 2reg scalar ext: 0b1111_1110_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx
+# 3same ext: 0b1111_110x_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx
+
+# VFP/Neon register fields; same as vfp.decode
+%vm_dp 5:1 0:4
+%vm_sp 0:4 5:1
+%vn_dp 7:1 16:4
+%vn_sp 16:4 7:1
+%vd_dp 22:1 12:4
+%vd_sp 12:4 22:1
+
+VCMLA 1111 110 rot:2 . 1 size:1 .... .... 1000 . q:1 . 0 .... \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+VCADD 1111 110 rot:1 1 . 0 size:1 .... .... 1000 . q:1 . 0 .... \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+# VUDOT and VSDOT
+VDOT 1111 110 00 . 10 .... .... 1101 . q:1 . u:1 .... \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+# VFM[AS]L
+VFML 1111 110 0 s:1 . 10 .... .... 1000 . 0 . 1 .... \
+ vm=%vm_sp vn=%vn_sp vd=%vd_dp q=0
+VFML 1111 110 0 s:1 . 10 .... .... 1000 . 1 . 1 .... \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp q=1
+
+VCMLA_scalar 1111 1110 0 . rot:2 .... .... 1000 . q:1 index:1 0 vm:4 \
+ vn=%vn_dp vd=%vd_dp size=0
+VCMLA_scalar 1111 1110 1 . rot:2 .... .... 1000 . q:1 . 0 .... \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp size=1 index=0
+
+VDOT_scalar 1111 1110 0 . 10 .... .... 1101 . q:1 index:1 u:1 rm:4 \
+ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+%vfml_scalar_q0_rm 0:3 5:1
+%vfml_scalar_q1_index 5:1 3:1
+VFML_scalar 1111 1110 0 . 0 s:1 .... .... 1000 . 0 . 1 index:1 ... \
+ rm=%vfml_scalar_q0_rm vn=%vn_sp vd=%vd_dp q=0
+VFML_scalar 1111 1110 0 . 0 s:1 .... .... 1000 . 1 . 1 . rm:3 \
+ index=%vfml_scalar_q1_index vn=%vn_dp vd=%vd_dp q=1
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index efb1c4adc4..a896f9c4b8 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -70,23 +70,6 @@ typedef struct AArch64DecodeTable {
AArch64DecodeFn *disas_fn;
} AArch64DecodeTable;
-/* Function prototype for gen_ functions for calling Neon helpers */
-typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
-typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
-typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
-typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
-typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
-typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
-typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
-typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
-typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
-typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
-typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
-typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
-typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
-typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
-typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp);
-
/* initialize TCG globals. */
void a64_translate_init(void)
{
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 4c2c91ae1b..f02fbb63a4 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -115,13 +115,4 @@ static inline int vec_full_reg_size(DisasContext *s)
bool disas_sve(DisasContext *, uint32_t);
-/* Note that the gvec expanders operate on offsets + sizes. */
-typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t);
-typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
- uint32_t, uint32_t);
-typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
- uint32_t, uint32_t, uint32_t);
-typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t,
- uint32_t, uint32_t, uint32_t);
-
#endif /* TARGET_ARM_TRANSLATE_A64_H */
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
new file mode 100644
index 0000000000..50b77b6d71
--- /dev/null
+++ b/target/arm/translate-neon.inc.c
@@ -0,0 +1,714 @@
+/*
+ * ARM translation: AArch32 Neon instructions
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2005-2007 CodeSourcery
+ * Copyright (c) 2007 OpenedHand, Ltd.
+ * Copyright (c) 2020 Linaro, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This file is intended to be included from translate.c; it uses
+ * some macros and definitions provided by that file.
+ * It might be possible to convert it to a standalone .c file eventually.
+ */
+
+static inline int plus1(DisasContext *s, int x)
+{
+ return x + 1;
+}
+
+/* Include the generated Neon decoder */
+#include "decode-neon-dp.inc.c"
+#include "decode-neon-ls.inc.c"
+#include "decode-neon-shared.inc.c"
+
+static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
+{
+ int opr_sz;
+ TCGv_ptr fpst;
+ gen_helper_gvec_3_ptr *fn_gvec_ptr;
+
+ if (!dc_isar_feature(aa32_vcma, s)
+ || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vn | a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ opr_sz = (1 + a->q) * 8;
+ fpst = get_fpstatus_ptr(1);
+ fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
+ tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(1, a->vn),
+ vfp_reg_offset(1, a->vm),
+ fpst, opr_sz, opr_sz, a->rot,
+ fn_gvec_ptr);
+ tcg_temp_free_ptr(fpst);
+ return true;
+}
+
+static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
+{
+ int opr_sz;
+ TCGv_ptr fpst;
+ gen_helper_gvec_3_ptr *fn_gvec_ptr;
+
+ if (!dc_isar_feature(aa32_vcma, s)
+ || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vn | a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ opr_sz = (1 + a->q) * 8;
+ fpst = get_fpstatus_ptr(1);
+ fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
+ tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(1, a->vn),
+ vfp_reg_offset(1, a->vm),
+ fpst, opr_sz, opr_sz, a->rot,
+ fn_gvec_ptr);
+ tcg_temp_free_ptr(fpst);
+ return true;
+}
+
+static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
+{
+ int opr_sz;
+ gen_helper_gvec_3 *fn_gvec;
+
+ if (!dc_isar_feature(aa32_dp, s)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vn | a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ opr_sz = (1 + a->q) * 8;
+ fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
+ tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(1, a->vn),
+ vfp_reg_offset(1, a->vm),
+ opr_sz, opr_sz, 0, fn_gvec);
+ return true;
+}
+
+static bool trans_VFML(DisasContext *s, arg_VFML *a)
+{
+ int opr_sz;
+
+ if (!dc_isar_feature(aa32_fhm, s)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ (a->vd & 0x10)) {
+ return false;
+ }
+
+ if (a->vd & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ opr_sz = (1 + a->q) * 8;
+ tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(a->q, a->vn),
+ vfp_reg_offset(a->q, a->vm),
+ cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
+ gen_helper_gvec_fmlal_a32);
+ return true;
+}
+
+static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
+{
+ gen_helper_gvec_3_ptr *fn_gvec_ptr;
+ int opr_sz;
+ TCGv_ptr fpst;
+
+ if (!dc_isar_feature(aa32_vcma, s)) {
+ return false;
+ }
+ if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vd | a->vn) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx
+ : gen_helper_gvec_fcmlah_idx);
+ opr_sz = (1 + a->q) * 8;
+ fpst = get_fpstatus_ptr(1);
+ tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(1, a->vn),
+ vfp_reg_offset(1, a->vm),
+ fpst, opr_sz, opr_sz,
+ (a->index << 2) | a->rot, fn_gvec_ptr);
+ tcg_temp_free_ptr(fpst);
+ return true;
+}
+
+static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
+{
+ gen_helper_gvec_3 *fn_gvec;
+ int opr_sz;
+ TCGv_ptr fpst;
+
+ if (!dc_isar_feature(aa32_dp, s)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vd | a->vn) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
+ opr_sz = (1 + a->q) * 8;
+ fpst = get_fpstatus_ptr(1);
+ tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(1, a->vn),
+ vfp_reg_offset(1, a->rm),
+ opr_sz, opr_sz, a->index, fn_gvec);
+ tcg_temp_free_ptr(fpst);
+ return true;
+}
+
+static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
+{
+ int opr_sz;
+
+ if (!dc_isar_feature(aa32_fhm, s)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
+ return false;
+ }
+
+ if (a->vd & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ opr_sz = (1 + a->q) * 8;
+ tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
+ vfp_reg_offset(a->q, a->vn),
+ vfp_reg_offset(a->q, a->rm),
+ cpu_env, opr_sz, opr_sz,
+ (a->index << 2) | a->s, /* is_2 == 0 */
+ gen_helper_gvec_fmlal_idx_a32);
+ return true;
+}
+
+static struct {
+ int nregs;
+ int interleave;
+ int spacing;
+} const neon_ls_element_type[11] = {
+ {1, 4, 1},
+ {1, 4, 2},
+ {4, 1, 1},
+ {2, 2, 2},
+ {1, 3, 1},
+ {1, 3, 2},
+ {3, 1, 1},
+ {1, 1, 1},
+ {1, 2, 1},
+ {1, 2, 2},
+ {2, 1, 1}
+};
+
+static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
+ int stride)
+{
+ if (rm != 15) {
+ TCGv_i32 base;
+
+ base = load_reg(s, rn);
+ if (rm == 13) {
+ tcg_gen_addi_i32(base, base, stride);
+ } else {
+ TCGv_i32 index;
+ index = load_reg(s, rm);
+ tcg_gen_add_i32(base, base, index);
+ tcg_temp_free_i32(index);
+ }
+ store_reg(s, rn, base);
+ }
+}
+
+static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
+{
+ /* Neon load/store multiple structures */
+ int nregs, interleave, spacing, reg, n;
+ MemOp endian = s->be_data;
+ int mmu_idx = get_mem_index(s);
+ int size = a->size;
+ TCGv_i64 tmp64;
+ TCGv_i32 addr, tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ return false;
+ }
+ if (a->itype > 10) {
+ return false;
+ }
+ /* Catch UNDEF cases for bad values of align field */
+ switch (a->itype & 0xc) {
+ case 4:
+ if (a->align >= 2) {
+ return false;
+ }
+ break;
+ case 8:
+ if (a->align == 3) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ nregs = neon_ls_element_type[a->itype].nregs;
+ interleave = neon_ls_element_type[a->itype].interleave;
+ spacing = neon_ls_element_type[a->itype].spacing;
+ if (size == 3 && (interleave | spacing) != 1) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /* For our purposes, bytes are always little-endian. */
+ if (size == 0) {
+ endian = MO_LE;
+ }
+ /*
+ * Consecutive little-endian elements from a single register
+ * can be promoted to a larger little-endian operation.
+ */
+ if (interleave == 1 && endian == MO_LE) {
+ size = 3;
+ }
+ tmp64 = tcg_temp_new_i64();
+ addr = tcg_temp_new_i32();
+ tmp = tcg_const_i32(1 << size);
+ load_reg_var(s, addr, a->rn);
+ for (reg = 0; reg < nregs; reg++) {
+ for (n = 0; n < 8 >> size; n++) {
+ int xs;
+ for (xs = 0; xs < interleave; xs++) {
+ int tt = a->vd + reg + spacing * xs;
+
+ if (a->l) {
+ gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
+ neon_store_element64(tt, n, size, tmp64);
+ } else {
+ neon_load_element64(tmp64, tt, n, size);
+ gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
+ }
+ tcg_gen_add_i32(addr, addr, tmp);
+ }
+ }
+ }
+ tcg_temp_free_i32(addr);
+ tcg_temp_free_i32(tmp);
+ tcg_temp_free_i64(tmp64);
+
+ gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
+ return true;
+}
+
+static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
+{
+ /* Neon load single structure to all lanes */
+ int reg, stride, vec_size;
+ int vd = a->vd;
+ int size = a->size;
+ int nregs = a->n + 1;
+ TCGv_i32 addr, tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ return false;
+ }
+
+ if (size == 3) {
+ if (nregs != 4 || a->a == 0) {
+ return false;
+ }
+ /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
+ size = 2;
+ }
+ if (nregs == 1 && a->a == 1 && size == 0) {
+ return false;
+ }
+ if (nregs == 3 && a->a == 1) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * VLD1 to all lanes: T bit indicates how many Dregs to write.
+ * VLD2/3/4 to all lanes: T bit indicates register stride.
+ */
+ stride = a->t ? 2 : 1;
+ vec_size = nregs == 1 ? stride * 8 : 8;
+
+ tmp = tcg_temp_new_i32();
+ addr = tcg_temp_new_i32();
+ load_reg_var(s, addr, a->rn);
+ for (reg = 0; reg < nregs; reg++) {
+ gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
+ s->be_data | size);
+ if ((vd & 1) && vec_size == 16) {
+ /*
+ * We cannot write 16 bytes at once because the
+ * destination is unaligned.
+ */
+ tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
+ 8, 8, tmp);
+ tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0),
+ neon_reg_offset(vd, 0), 8, 8);
+ } else {
+ tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
+ vec_size, vec_size, tmp);
+ }
+ tcg_gen_addi_i32(addr, addr, 1 << size);
+ vd += stride;
+ }
+ tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(addr);
+
+ gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
+
+ return true;
+}
+
+static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
+{
+ /* Neon load/store single structure to one lane */
+ int reg;
+ int nregs = a->n + 1;
+ int vd = a->vd;
+ TCGv_i32 addr, tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ return false;
+ }
+
+ /* Catch the UNDEF cases. This is unavoidably a bit messy. */
+ switch (nregs) {
+ case 1:
+ if (((a->align & (1 << a->size)) != 0) ||
+ (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) {
+ return false;
+ }
+ break;
+ case 3:
+ if ((a->align & 1) != 0) {
+ return false;
+ }
+ /* fall through */
+ case 2:
+ if (a->size == 2 && (a->align & 2) != 0) {
+ return false;
+ }
+ break;
+ case 4:
+ if ((a->size == 2) && ((a->align & 3) == 3)) {
+ return false;
+ }
+ break;
+ default:
+ abort();
+ }
+ if ((vd + a->stride * (nregs - 1)) > 31) {
+ /*
+ * Attempts to write off the end of the register file are
+ * UNPREDICTABLE; we choose to UNDEF because otherwise we would
+ * access off the end of the array that holds the register data.
+ */
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ tmp = tcg_temp_new_i32();
+ addr = tcg_temp_new_i32();
+ load_reg_var(s, addr, a->rn);
+ /*
+ * TODO: if we implemented alignment exceptions, we should check
+ * addr against the alignment encoded in a->align here.
+ */
+ for (reg = 0; reg < nregs; reg++) {
+ if (a->l) {
+ gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
+ s->be_data | a->size);
+ neon_store_element(vd, a->reg_idx, a->size, tmp);
+ } else { /* Store */
+ neon_load_element(tmp, vd, a->reg_idx, a->size);
+ gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
+ s->be_data | a->size);
+ }
+ vd += a->stride;
+ tcg_gen_addi_i32(addr, addr, 1 << a->size);
+ }
+ tcg_temp_free_i32(addr);
+ tcg_temp_free_i32(tmp);
+
+ gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
+
+ return true;
+}
+
+static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
+{
+ int vec_size = a->q ? 16 : 8;
+ int rd_ofs = neon_reg_offset(a->vd, 0);
+ int rn_ofs = neon_reg_offset(a->vn, 0);
+ int rm_ofs = neon_reg_offset(a->vm, 0);
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vn | a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
+ return true;
+}
+
+#define DO_3SAME(INSN, FUNC) \
+ static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \
+ { \
+ return do_3same(s, a, FUNC); \
+ }
+
+DO_3SAME(VADD, tcg_gen_gvec_add)
+DO_3SAME(VSUB, tcg_gen_gvec_sub)
+DO_3SAME(VAND, tcg_gen_gvec_and)
+DO_3SAME(VBIC, tcg_gen_gvec_andc)
+DO_3SAME(VORR, tcg_gen_gvec_or)
+DO_3SAME(VORN, tcg_gen_gvec_orc)
+DO_3SAME(VEOR, tcg_gen_gvec_xor)
+
+/* These insns are all gvec_bitsel but with the inputs in various orders. */
+#define DO_3SAME_BITSEL(INSN, O1, O2, O3) \
+ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
+ uint32_t rn_ofs, uint32_t rm_ofs, \
+ uint32_t oprsz, uint32_t maxsz) \
+ { \
+ tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \
+ } \
+ DO_3SAME(INSN, gen_##INSN##_3s)
+
+DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
+DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
+DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
+
+#define DO_3SAME_NO_SZ_3(INSN, FUNC) \
+ static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \
+ { \
+ if (a->size == 3) { \
+ return false; \
+ } \
+ return do_3same(s, a, FUNC); \
+ }
+
+DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
+DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
+DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
+DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
+DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
+
+#define DO_3SAME_CMP(INSN, COND) \
+ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
+ uint32_t rn_ofs, uint32_t rm_ofs, \
+ uint32_t oprsz, uint32_t maxsz) \
+ { \
+ tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
+ } \
+ DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
+
+DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
+DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
+DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
+DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
+DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
+
+static void gen_VTST_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &cmtst_op[vece]);
+}
+DO_3SAME_NO_SZ_3(VTST, gen_VTST_3s)
+
+#define DO_3SAME_GVEC4(INSN, OPARRAY) \
+ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
+ uint32_t rn_ofs, uint32_t rm_ofs, \
+ uint32_t oprsz, uint32_t maxsz) \
+ { \
+ tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), \
+ rn_ofs, rm_ofs, oprsz, maxsz, &OPARRAY[vece]); \
+ } \
+ DO_3SAME(INSN, gen_##INSN##_3s)
+
+DO_3SAME_GVEC4(VQADD_S, sqadd_op)
+DO_3SAME_GVEC4(VQADD_U, uqadd_op)
+DO_3SAME_GVEC4(VQSUB_S, sqsub_op)
+DO_3SAME_GVEC4(VQSUB_U, uqsub_op)
+
+static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz,
+ 0, gen_helper_gvec_pmul_b);
+}
+
+static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
+{
+ if (a->size != 0) {
+ return false;
+ }
+ return do_3same(s, a, gen_VMUL_p_3s);
+}
+
+#define DO_3SAME_GVEC3_NO_SZ_3(INSN, OPARRAY) \
+ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
+ uint32_t rn_ofs, uint32_t rm_ofs, \
+ uint32_t oprsz, uint32_t maxsz) \
+ { \
+ tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, \
+ oprsz, maxsz, &OPARRAY[vece]); \
+ } \
+ DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
+
+
+DO_3SAME_GVEC3_NO_SZ_3(VMLA, mla_op)
+DO_3SAME_GVEC3_NO_SZ_3(VMLS, mls_op)
+
+#define DO_3SAME_GVEC3_SHIFT(INSN, OPARRAY) \
+ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
+ uint32_t rn_ofs, uint32_t rm_ofs, \
+ uint32_t oprsz, uint32_t maxsz) \
+ { \
+ /* Note the operation is vshl vd,vm,vn */ \
+ tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, \
+ oprsz, maxsz, &OPARRAY[vece]); \
+ } \
+ DO_3SAME(INSN, gen_##INSN##_3s)
+
+DO_3SAME_GVEC3_SHIFT(VSHL_S, sshl_op)
+DO_3SAME_GVEC3_SHIFT(VSHL_U, ushl_op)
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
index b087bbd812..e1a9017598 100644
--- a/target/arm/translate-vfp.inc.c
+++ b/target/arm/translate-vfp.inc.c
@@ -1872,12 +1872,6 @@ static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vn | a->vm) & 0x10)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index d4ad2028f1..025747c0bd 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1313,8 +1313,9 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
#define ARM_CP_RW_BIT (1 << 20)
-/* Include the VFP decoder */
+/* Include the VFP and Neon decoders */
#include "translate-vfp.inc.c"
+#include "translate-neon.inc.c"
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{
@@ -2609,8 +2610,6 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
}
#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
-#define VFP_SREG(insn, bigbit, smallbit) \
- ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
if (dc_isar_feature(aa32_simd_r32, s)) { \
reg = (((insn) >> (bigbit)) & 0x0f) \
@@ -2621,11 +2620,8 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
reg = ((insn) >> (bigbit)) & 0x0f; \
}} while (0)
-#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
-#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
-#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
static void gen_neon_dup_low16(TCGv_i32 var)
@@ -3217,274 +3213,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
tcg_temp_free_i32(rd);
}
-
-static struct {
- int nregs;
- int interleave;
- int spacing;
-} const neon_ls_element_type[11] = {
- {1, 4, 1},
- {1, 4, 2},
- {4, 1, 1},
- {2, 2, 2},
- {1, 3, 1},
- {1, 3, 2},
- {3, 1, 1},
- {1, 1, 1},
- {1, 2, 1},
- {1, 2, 2},
- {2, 1, 1}
-};
-
-/* Translate a NEON load/store element instruction. Return nonzero if the
- instruction is invalid. */
-static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
-{
- int rd, rn, rm;
- int op;
- int nregs;
- int interleave;
- int spacing;
- int stride;
- int size;
- int reg;
- int load;
- int n;
- int vec_size;
- int mmu_idx;
- MemOp endian;
- TCGv_i32 addr;
- TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i64 tmp64;
-
- /* FIXME: this access check should not take precedence over UNDEF
- * for invalid encodings; we will generate incorrect syndrome information
- * for attempts to execute invalid vfp/neon encodings with FP disabled.
- */
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
-
- if (!s->vfp_enabled)
- return 1;
- VFP_DREG_D(rd, insn);
- rn = (insn >> 16) & 0xf;
- rm = insn & 0xf;
- load = (insn & (1 << 21)) != 0;
- endian = s->be_data;
- mmu_idx = get_mem_index(s);
- if ((insn & (1 << 23)) == 0) {
- /* Load store all elements. */
- op = (insn >> 8) & 0xf;
- size = (insn >> 6) & 3;
- if (op > 10)
- return 1;
- /* Catch UNDEF cases for bad values of align field */
- switch (op & 0xc) {
- case 4:
- if (((insn >> 5) & 1) == 1) {
- return 1;
- }
- break;
- case 8:
- if (((insn >> 4) & 3) == 3) {
- return 1;
- }
- break;
- default:
- break;
- }
- nregs = neon_ls_element_type[op].nregs;
- interleave = neon_ls_element_type[op].interleave;
- spacing = neon_ls_element_type[op].spacing;
- if (size == 3 && (interleave | spacing) != 1) {
- return 1;
- }
- /* For our purposes, bytes are always little-endian. */
- if (size == 0) {
- endian = MO_LE;
- }
- /* Consecutive little-endian elements from a single register
- * can be promoted to a larger little-endian operation.
- */
- if (interleave == 1 && endian == MO_LE) {
- size = 3;
- }
- tmp64 = tcg_temp_new_i64();
- addr = tcg_temp_new_i32();
- tmp2 = tcg_const_i32(1 << size);
- load_reg_var(s, addr, rn);
- for (reg = 0; reg < nregs; reg++) {
- for (n = 0; n < 8 >> size; n++) {
- int xs;
- for (xs = 0; xs < interleave; xs++) {
- int tt = rd + reg + spacing * xs;
-
- if (load) {
- gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
- neon_store_element64(tt, n, size, tmp64);
- } else {
- neon_load_element64(tmp64, tt, n, size);
- gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
- }
- tcg_gen_add_i32(addr, addr, tmp2);
- }
- }
- }
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i64(tmp64);
- stride = nregs * interleave * 8;
- } else {
- size = (insn >> 10) & 3;
- if (size == 3) {
- /* Load single element to all lanes. */
- int a = (insn >> 4) & 1;
- if (!load) {
- return 1;
- }
- size = (insn >> 6) & 3;
- nregs = ((insn >> 8) & 3) + 1;
-
- if (size == 3) {
- if (nregs != 4 || a == 0) {
- return 1;
- }
- /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
- size = 2;
- }
- if (nregs == 1 && a == 1 && size == 0) {
- return 1;
- }
- if (nregs == 3 && a == 1) {
- return 1;
- }
- addr = tcg_temp_new_i32();
- load_reg_var(s, addr, rn);
-
- /* VLD1 to all lanes: bit 5 indicates how many Dregs to write.
- * VLD2/3/4 to all lanes: bit 5 indicates register stride.
- */
- stride = (insn & (1 << 5)) ? 2 : 1;
- vec_size = nregs == 1 ? stride * 8 : 8;
-
- tmp = tcg_temp_new_i32();
- for (reg = 0; reg < nregs; reg++) {
- gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- if ((rd & 1) && vec_size == 16) {
- /* We cannot write 16 bytes at once because the
- * destination is unaligned.
- */
- tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0),
- 8, 8, tmp);
- tcg_gen_gvec_mov(0, neon_reg_offset(rd + 1, 0),
- neon_reg_offset(rd, 0), 8, 8);
- } else {
- tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0),
- vec_size, vec_size, tmp);
- }
- tcg_gen_addi_i32(addr, addr, 1 << size);
- rd += stride;
- }
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(addr);
- stride = (1 << size) * nregs;
- } else {
- /* Single element. */
- int idx = (insn >> 4) & 0xf;
- int reg_idx;
- switch (size) {
- case 0:
- reg_idx = (insn >> 5) & 7;
- stride = 1;
- break;
- case 1:
- reg_idx = (insn >> 6) & 3;
- stride = (insn & (1 << 5)) ? 2 : 1;
- break;
- case 2:
- reg_idx = (insn >> 7) & 1;
- stride = (insn & (1 << 6)) ? 2 : 1;
- break;
- default:
- abort();
- }
- nregs = ((insn >> 8) & 3) + 1;
- /* Catch the UNDEF cases. This is unavoidably a bit messy. */
- switch (nregs) {
- case 1:
- if (((idx & (1 << size)) != 0) ||
- (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
- return 1;
- }
- break;
- case 3:
- if ((idx & 1) != 0) {
- return 1;
- }
- /* fall through */
- case 2:
- if (size == 2 && (idx & 2) != 0) {
- return 1;
- }
- break;
- case 4:
- if ((size == 2) && ((idx & 3) == 3)) {
- return 1;
- }
- break;
- default:
- abort();
- }
- if ((rd + stride * (nregs - 1)) > 31) {
- /* Attempts to write off the end of the register file
- * are UNPREDICTABLE; we choose to UNDEF because otherwise
- * the neon_load_reg() would write off the end of the array.
- */
- return 1;
- }
- tmp = tcg_temp_new_i32();
- addr = tcg_temp_new_i32();
- load_reg_var(s, addr, rn);
- for (reg = 0; reg < nregs; reg++) {
- if (load) {
- gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- neon_store_element(rd, reg_idx, size, tmp);
- } else { /* Store */
- neon_load_element(tmp, rd, reg_idx, size);
- gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- }
- rd += stride;
- tcg_gen_addi_i32(addr, addr, 1 << size);
- }
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp);
- stride = nregs * (1 << size);
- }
- }
- if (rm != 15) {
- TCGv_i32 base;
-
- base = load_reg(s, rn);
- if (rm == 13) {
- tcg_gen_addi_i32(base, base, stride);
- } else {
- TCGv_i32 index;
- index = load_reg(s, rm);
- tcg_gen_add_i32(base, base, index);
- tcg_temp_free_i32(index);
- }
- store_reg(s, rn, base);
- }
- return 0;
-}
-
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
{
switch (size) {
@@ -5002,6 +4730,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
TCGv_ptr ptr1, ptr2, ptr3;
TCGv_i64 tmp64;
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return 1;
+ }
+
/* FIXME: this access check should not take precedence over UNDEF
* for invalid encodings; we will generate incorrect syndrome information
* for attempts to execute invalid vfp/neon encodings with FP disabled.
@@ -5116,128 +4848,20 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
return 1;
- case NEON_3R_LOGIC: /* Logic ops. */
- switch ((u << 2) | size) {
- case 0: /* VAND */
- tcg_gen_gvec_and(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 1: /* VBIC */
- tcg_gen_gvec_andc(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 2: /* VORR */
- tcg_gen_gvec_or(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 3: /* VORN */
- tcg_gen_gvec_orc(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 4: /* VEOR */
- tcg_gen_gvec_xor(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 5: /* VBSL */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 6: /* VBIT */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rn_ofs, rd_ofs,
- vec_size, vec_size);
- break;
- case 7: /* VBIF */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rd_ofs, rn_ofs,
- vec_size, vec_size);
- break;
- }
- return 0;
-
case NEON_3R_VADD_VSUB:
- if (u) {
- tcg_gen_gvec_sub(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_add(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
- case NEON_3R_VQADD:
- tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
- rn_ofs, rm_ofs, vec_size, vec_size,
- (u ? uqadd_op : sqadd_op) + size);
- return 0;
-
- case NEON_3R_VQSUB:
- tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
- rn_ofs, rm_ofs, vec_size, vec_size,
- (u ? uqsub_op : sqsub_op) + size);
- return 0;
-
- case NEON_3R_VMUL: /* VMUL */
- if (u) {
- /* Polynomial case allows only P8. */
- if (size != 0) {
- return 1;
- }
- tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size,
- 0, gen_helper_gvec_pmul_b);
- } else {
- tcg_gen_gvec_mul(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
- case NEON_3R_VML: /* VMLA, VMLS */
- tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size,
- u ? &mls_op[size] : &mla_op[size]);
- return 0;
-
+ case NEON_3R_LOGIC:
+ case NEON_3R_VMAX:
+ case NEON_3R_VMIN:
case NEON_3R_VTST_VCEQ:
- if (u) { /* VCEQ */
- tcg_gen_gvec_cmp(TCG_COND_EQ, size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else { /* VTST */
- tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size, &cmtst_op[size]);
- }
- return 0;
-
case NEON_3R_VCGT:
- tcg_gen_gvec_cmp(u ? TCG_COND_GTU : TCG_COND_GT, size,
- rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
- return 0;
-
case NEON_3R_VCGE:
- tcg_gen_gvec_cmp(u ? TCG_COND_GEU : TCG_COND_GE, size,
- rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
- return 0;
-
- case NEON_3R_VMAX:
- if (u) {
- tcg_gen_gvec_umax(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_smax(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
- case NEON_3R_VMIN:
- if (u) {
- tcg_gen_gvec_umin(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_smin(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
+ case NEON_3R_VQADD:
+ case NEON_3R_VQSUB:
+ case NEON_3R_VMUL:
+ case NEON_3R_VML:
case NEON_3R_VSHL:
- /* Note the operation is vshl vd,vm,vn */
- tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size,
- u ? &ushl_op[size] : &sshl_op[size]);
- return 0;
+ /* Already handled by decodetree */
+ return 1;
}
if (size == 3) {
@@ -6016,7 +5640,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
{0, 0, 0, 0}, /* VMLSL */
{0, 0, 0, 9}, /* VQDMLSL */
{0, 0, 0, 0}, /* Integer VMULL */
- {0, 0, 0, 1}, /* VQDMULL */
+ {0, 0, 0, 9}, /* VQDMULL */
{0, 0, 0, 0xa}, /* Polynomial VMULL */
{0, 0, 0, 7}, /* Reserved: always UNDEF */
};
@@ -7023,232 +6647,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
return 0;
}
-/* Advanced SIMD three registers of the same length extension.
- * 31 25 23 22 20 16 12 11 10 9 8 3 0
- * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+
- * | 1 1 1 1 1 1 0 | op1 | D | op2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm |
- * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+
- */
-static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
-{
- gen_helper_gvec_3 *fn_gvec = NULL;
- gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
- int rd, rn, rm, opr_sz;
- int data = 0;
- int off_rn, off_rm;
- bool is_long = false, q = extract32(insn, 6, 1);
- bool ptr_is_env = false;
-
- if ((insn & 0xfe200f10) == 0xfc200800) {
- /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */
- int size = extract32(insn, 20, 1);
- data = extract32(insn, 23, 2); /* rot */
- if (!dc_isar_feature(aa32_vcma, s)
- || (!size && !dc_isar_feature(aa32_fp16_arith, s))) {
- return 1;
- }
- fn_gvec_ptr = size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
- } else if ((insn & 0xfea00f10) == 0xfc800800) {
- /* VCADD -- 1111 110R 1.0S .... .... 1000 ...0 .... */
- int size = extract32(insn, 20, 1);
- data = extract32(insn, 24, 1); /* rot */
- if (!dc_isar_feature(aa32_vcma, s)
- || (!size && !dc_isar_feature(aa32_fp16_arith, s))) {
- return 1;
- }
- fn_gvec_ptr = size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
- } else if ((insn & 0xfeb00f00) == 0xfc200d00) {
- /* V[US]DOT -- 1111 1100 0.10 .... .... 1101 .Q.U .... */
- bool u = extract32(insn, 4, 1);
- if (!dc_isar_feature(aa32_dp, s)) {
- return 1;
- }
- fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
- } else if ((insn & 0xff300f10) == 0xfc200810) {
- /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */
- int is_s = extract32(insn, 23, 1);
- if (!dc_isar_feature(aa32_fhm, s)) {
- return 1;
- }
- is_long = true;
- data = is_s; /* is_2 == 0 */
- fn_gvec_ptr = gen_helper_gvec_fmlal_a32;
- ptr_is_env = true;
- } else {
- return 1;
- }
-
- VFP_DREG_D(rd, insn);
- if (rd & q) {
- return 1;
- }
- if (q || !is_long) {
- VFP_DREG_N(rn, insn);
- VFP_DREG_M(rm, insn);
- if ((rn | rm) & q & !is_long) {
- return 1;
- }
- off_rn = vfp_reg_offset(1, rn);
- off_rm = vfp_reg_offset(1, rm);
- } else {
- rn = VFP_SREG_N(insn);
- rm = VFP_SREG_M(insn);
- off_rn = vfp_reg_offset(0, rn);
- off_rm = vfp_reg_offset(0, rm);
- }
-
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
- if (!s->vfp_enabled) {
- return 1;
- }
-
- opr_sz = (1 + q) * 8;
- if (fn_gvec_ptr) {
- TCGv_ptr ptr;
- if (ptr_is_env) {
- ptr = cpu_env;
- } else {
- ptr = get_fpstatus_ptr(1);
- }
- tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
- opr_sz, opr_sz, data, fn_gvec_ptr);
- if (!ptr_is_env) {
- tcg_temp_free_ptr(ptr);
- }
- } else {
- tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
- opr_sz, opr_sz, data, fn_gvec);
- }
- return 0;
-}
-
-/* Advanced SIMD two registers and a scalar extension.
- * 31 24 23 22 20 16 12 11 10 9 8 3 0
- * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+
- * | 1 1 1 1 1 1 1 0 | o1 | D | o2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm |
- * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+
- *
- */
-
-static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
-{
- gen_helper_gvec_3 *fn_gvec = NULL;
- gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
- int rd, rn, rm, opr_sz, data;
- int off_rn, off_rm;
- bool is_long = false, q = extract32(insn, 6, 1);
- bool ptr_is_env = false;
-
- if ((insn & 0xff000f10) == 0xfe000800) {
- /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */
- int rot = extract32(insn, 20, 2);
- int size = extract32(insn, 23, 1);
- int index;
-
- if (!dc_isar_feature(aa32_vcma, s)) {
- return 1;
- }
- if (size == 0) {
- if (!dc_isar_feature(aa32_fp16_arith, s)) {
- return 1;
- }
- /* For fp16, rm is just Vm, and index is M. */
- rm = extract32(insn, 0, 4);
- index = extract32(insn, 5, 1);
- } else {
- /* For fp32, rm is the usual M:Vm, and index is 0. */
- VFP_DREG_M(rm, insn);
- index = 0;
- }
- data = (index << 2) | rot;
- fn_gvec_ptr = (size ? gen_helper_gvec_fcmlas_idx
- : gen_helper_gvec_fcmlah_idx);
- } else if ((insn & 0xffb00f00) == 0xfe200d00) {
- /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */
- int u = extract32(insn, 4, 1);
-
- if (!dc_isar_feature(aa32_dp, s)) {
- return 1;
- }
- fn_gvec = u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
- /* rm is just Vm, and index is M. */
- data = extract32(insn, 5, 1); /* index */
- rm = extract32(insn, 0, 4);
- } else if ((insn & 0xffa00f10) == 0xfe000810) {
- /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */
- int is_s = extract32(insn, 20, 1);
- int vm20 = extract32(insn, 0, 3);
- int vm3 = extract32(insn, 3, 1);
- int m = extract32(insn, 5, 1);
- int index;
-
- if (!dc_isar_feature(aa32_fhm, s)) {
- return 1;
- }
- if (q) {
- rm = vm20;
- index = m * 2 + vm3;
- } else {
- rm = vm20 * 2 + m;
- index = vm3;
- }
- is_long = true;
- data = (index << 2) | is_s; /* is_2 == 0 */
- fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32;
- ptr_is_env = true;
- } else {
- return 1;
- }
-
- VFP_DREG_D(rd, insn);
- if (rd & q) {
- return 1;
- }
- if (q || !is_long) {
- VFP_DREG_N(rn, insn);
- if (rn & q & !is_long) {
- return 1;
- }
- off_rn = vfp_reg_offset(1, rn);
- off_rm = vfp_reg_offset(1, rm);
- } else {
- rn = VFP_SREG_N(insn);
- off_rn = vfp_reg_offset(0, rn);
- off_rm = vfp_reg_offset(0, rm);
- }
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
- if (!s->vfp_enabled) {
- return 1;
- }
-
- opr_sz = (1 + q) * 8;
- if (fn_gvec_ptr) {
- TCGv_ptr ptr;
- if (ptr_is_env) {
- ptr = cpu_env;
- } else {
- ptr = get_fpstatus_ptr(1);
- }
- tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
- opr_sz, opr_sz, data, fn_gvec_ptr);
- if (!ptr_is_env) {
- tcg_temp_free_ptr(ptr);
- }
- } else {
- tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
- opr_sz, opr_sz, data, fn_gvec);
- }
- return 0;
-}
-
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
{
int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
@@ -10941,33 +10339,21 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* Unconditional instructions. */
/* TODO: Perhaps merge these into one decodetree output file. */
if (disas_a32_uncond(s, insn) ||
- disas_vfp_uncond(s, insn)) {
+ disas_vfp_uncond(s, insn) ||
+ disas_neon_dp(s, insn) ||
+ disas_neon_ls(s, insn) ||
+ disas_neon_shared(s, insn)) {
return;
}
/* fall back to legacy decoder */
if (((insn >> 25) & 7) == 1) {
/* NEON Data processing. */
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- goto illegal_op;
- }
-
if (disas_neon_data_insn(s, insn)) {
goto illegal_op;
}
return;
}
- if ((insn & 0x0f100000) == 0x04000000) {
- /* NEON load/store. */
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- goto illegal_op;
- }
-
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- return;
- }
if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
@@ -10977,18 +10363,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
}
}
- } else if ((insn & 0x0e000a00) == 0x0c000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- if (disas_neon_insn_3same_ext(s, insn)) {
- goto illegal_op;
- }
- return;
- } else if ((insn & 0x0f000a00) == 0x0e000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- if (disas_neon_insn_2reg_scalar_ext(s, insn)) {
- goto illegal_op;
- }
- return;
}
goto illegal_op;
}
@@ -11102,6 +10476,33 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
ARCH(6T2);
}
+ if ((insn & 0xef000000) == 0xef000000) {
+ /*
+ * T32 encodings 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+ * transform into
+ * A32 encodings 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+ */
+ uint32_t a32_insn = (insn & 0xe2ffffff) |
+ ((insn & (1 << 28)) >> 4) | (1 << 28);
+
+ if (disas_neon_dp(s, a32_insn)) {
+ return;
+ }
+ }
+
+ if ((insn & 0xff100000) == 0xf9000000) {
+ /*
+ * T32 encodings 0b1111_1001_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
+ * transform into
+ * A32 encodings 0b1111_0100_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
+ */
+ uint32_t a32_insn = (insn & 0x00ffffff) | 0xf4000000;
+
+ if (disas_neon_ls(s, a32_insn)) {
+ return;
+ }
+ }
+
/*
* TODO: Perhaps merge these into one decodetree output file.
* Note disas_vfp is written for a32 with cond field in the
@@ -11109,6 +10510,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
*/
if (disas_t32(s, insn) ||
disas_vfp_uncond(s, insn) ||
+ disas_neon_shared(s, insn) ||
((insn >> 28) == 0xe && disas_vfp(s, insn))) {
return;
}
@@ -11138,19 +10540,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
}
- if ((insn & 0xfe000a00) == 0xfc000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* The Thumb2 and ARM encodings are identical. */
- if (disas_neon_insn_3same_ext(s, insn)) {
- goto illegal_op;
- }
- } else if ((insn & 0xff000a00) == 0xfe000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* The Thumb2 and ARM encodings are identical. */
- if (disas_neon_insn_2reg_scalar_ext(s, insn)) {
- goto illegal_op;
- }
- } else if (((insn >> 24) & 3) == 3) {
+ if (((insn >> 24) & 3) == 3) {
/* Translate into the equivalent ARM encoding. */
insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
if (disas_neon_data_insn(s, insn)) {
@@ -11168,12 +10558,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
case 12:
- if ((insn & 0x01100000) == 0x01000000) {
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- break;
- }
goto illegal_op;
default:
illegal_op:
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 98b319f3f6..cb7925ea46 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -305,4 +305,30 @@ void gen_sshl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b);
#define dc_isar_feature(name, ctx) \
({ DisasContext *ctx_ = (ctx); isar_feature_##name(ctx_->isar); })
+/* Note that the gvec expanders operate on offsets + sizes. */
+typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
+ uint32_t, uint32_t);
+typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t);
+typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t);
+
+/* Function prototype for gen_ functions for calling Neon helpers */
+typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
+typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
+typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
+typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
+typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
+typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
+typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
+typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
+typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
+typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
+typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
+typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
+typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
+typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
+typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp);
+
#endif /* TARGET_ARM_TRANSLATE_H */
diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT
index c6adfe32d5..ad4b2d46cc 100644
--- a/tests/data/acpi/pc/DSDT
+++ b/tests/data/acpi/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat
index ad890e09aa..eff7aadfab 100644
--- a/tests/data/acpi/pc/DSDT.acpihmat
+++ b/tests/data/acpi/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge
index f01fa3ad4e..92ae808e2e 100644
--- a/tests/data/acpi/pc/DSDT.bridge
+++ b/tests/data/acpi/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp
index 3295d81c7f..f357235851 100644
--- a/tests/data/acpi/pc/DSDT.cphp
+++ b/tests/data/acpi/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm
index ad2800de67..7fa09463c1 100644
--- a/tests/data/acpi/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs
index 2633a8cecf..469d13e1f6 100644
--- a/tests/data/acpi/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp
index 9e75ac96e1..aee75bea27 100644
--- a/tests/data/acpi/pc/DSDT.memhp
+++ b/tests/data/acpi/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem
index 71a975b3e2..9a747f6f08 100644
--- a/tests/data/acpi/pc/DSDT.numamem
+++ b/tests/data/acpi/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/pc/SSDT.dimmpxm b/tests/data/acpi/pc/SSDT.dimmpxm
index 8ba0e67cb7..ac55387d57 100644
--- a/tests/data/acpi/pc/SSDT.dimmpxm
+++ b/tests/data/acpi/pc/SSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/WAET b/tests/data/acpi/pc/WAET
new file mode 100644
index 0000000000..c2240f58df
--- /dev/null
+++ b/tests/data/acpi/pc/WAET
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT
index 1f91888d7a..9fa4d5a405 100644
--- a/tests/data/acpi/q35/DSDT
+++ b/tests/data/acpi/q35/DSDT
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat
index 3586f6368a..2d834a854c 100644
--- a/tests/data/acpi/q35/DSDT.acpihmat
+++ b/tests/data/acpi/q35/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge
index eae3a2a865..b75122b24a 100644
--- a/tests/data/acpi/q35/DSDT.bridge
+++ b/tests/data/acpi/q35/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp
index 53d735a4de..c59c19ff46 100644
--- a/tests/data/acpi/q35/DSDT.cphp
+++ b/tests/data/acpi/q35/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm
index 02ccdd5f38..9edc104ee6 100644
--- a/tests/data/acpi/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt
index 9e2d4f785c..3910e9b767 100644
--- a/tests/data/acpi/q35/DSDT.ipmibt
+++ b/tests/data/acpi/q35/DSDT.ipmibt
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp
index baefa611ac..8461e984c9 100644
--- a/tests/data/acpi/q35/DSDT.memhp
+++ b/tests/data/acpi/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64
index aae0ea2110..fc0cc096ba 100644
--- a/tests/data/acpi/q35/DSDT.mmio64
+++ b/tests/data/acpi/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem
index 859a2e0871..498c843be1 100644
--- a/tests/data/acpi/q35/DSDT.numamem
+++ b/tests/data/acpi/q35/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm
index 2d5b721bcf..98e6f0e3f3 100644
--- a/tests/data/acpi/q35/SSDT.dimmpxm
+++ b/tests/data/acpi/q35/SSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/WAET b/tests/data/acpi/q35/WAET
new file mode 100644
index 0000000000..c2240f58df
--- /dev/null
+++ b/tests/data/acpi/q35/WAET
Binary files differ
diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp
index c527ac4739..730e95a46d 100644
--- a/tests/data/acpi/virt/DSDT.memhp
+++ b/tests/data/acpi/virt/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/virt/NFIT.memhp b/tests/data/acpi/virt/NFIT.memhp
new file mode 100644
index 0000000000..738c6f74c0
--- /dev/null
+++ b/tests/data/acpi/virt/NFIT.memhp
Binary files differ
diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp
new file mode 100644
index 0000000000..db61d67332
--- /dev/null
+++ b/tests/data/acpi/virt/SSDT.memhp
Binary files differ
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 0a597bbacf..c9843829b3 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -927,12 +927,17 @@ static void test_acpi_virt_tcg_memhp(void)
};
data.variant = ".memhp";
- test_acpi_one(" -cpu cortex-a57"
+ test_acpi_one(" -machine nvdimm=on"
+ " -cpu cortex-a57"
" -m 256M,slots=3,maxmem=1G"
" -object memory-backend-ram,id=ram0,size=128M"
" -object memory-backend-ram,id=ram1,size=128M"
" -numa node,memdev=ram0 -numa node,memdev=ram1"
- " -numa dist,src=0,dst=1,val=21",
+ " -numa dist,src=0,dst=1,val=21"
+ " -object memory-backend-ram,id=ram2,size=128M"
+ " -object memory-backend-ram,id=nvm0,size=128M"
+ " -device pc-dimm,id=dimm0,memdev=ram2,node=0"
+ " -device nvdimm,id=dimm1,memdev=nvm0,node=1",
&data);
free_test_data(&data);
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index 0d78ac8d36..f5c923852e 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -91,6 +91,7 @@ static void usage(char *path)
printf(" * %s : %s\n", tmp->target->name,
tmp->target->description);
}
+ printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n");
exit(0);
}
@@ -143,18 +144,20 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
module_call_init(MODULE_INIT_QOM);
module_call_init(MODULE_INIT_LIBQOS);
- if (*argc <= 1) {
+ target_name = strstr(**argv, "-target-");
+ if (target_name) { /* The binary name specifies the target */
+ target_name += strlen("-target-");
+ } else if (*argc > 1) { /* The target is specified as an argument */
+ target_name = (*argv)[1];
+ if (!strstr(target_name, "--fuzz-target=")) {
+ usage(**argv);
+ }
+ target_name += strlen("--fuzz-target=");
+ } else {
usage(**argv);
}
/* Identify the fuzz target */
- target_name = (*argv)[1];
- if (!strstr(target_name, "--fuzz-target=")) {
- usage(**argv);
- }
-
- target_name += strlen("--fuzz-target=");
-
fuzz_target = fuzz_get_target(target_name);
if (!fuzz_target) {
usage(**argv);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 6babe24909..19632fdf6c 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "ui/qemu-spice.h"
#include "qemu/timer.h"
+#include "qemu/lockable.h"
#include "qemu/main-loop.h"
#include "qemu/option.h"
#include "qemu/queue.h"
@@ -483,12 +484,12 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
{
graphic_hw_update(ssd->dcl.con);
- qemu_mutex_lock(&ssd->lock);
- if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
- qemu_spice_create_update(ssd);
- ssd->notify++;
+ WITH_QEMU_LOCK_GUARD(&ssd->lock) {
+ if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
+ qemu_spice_create_update(ssd);
+ ssd->notify++;
+ }
}
- qemu_mutex_unlock(&ssd->lock);
trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify);
if (ssd->notify) {
@@ -580,7 +581,7 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
int ret;
- qemu_mutex_lock(&ssd->lock);
+ QEMU_LOCK_GUARD(&ssd->lock);
if (ssd->ptr_define) {
*ext = ssd->ptr_define->ext;
ssd->ptr_define = NULL;
@@ -592,7 +593,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
} else {
ret = false;
}
- qemu_mutex_unlock(&ssd->lock);
return ret;
}
diff --git a/util/log.c b/util/log.c
index 2da6cb31dc..bdb3d712e8 100644
--- a/util/log.c
+++ b/util/log.c
@@ -25,6 +25,7 @@
#include "qemu/cutils.h"
#include "trace/control.h"
#include "qemu/thread.h"
+#include "qemu/lockable.h"
static char *logfilename;
static QemuMutex qemu_logfile_mutex;
@@ -94,7 +95,7 @@ void qemu_set_log(int log_flags)
if (qemu_loglevel && (!is_daemonized() || logfilename)) {
need_to_open_file = true;
}
- qemu_mutex_lock(&qemu_logfile_mutex);
+ QEMU_LOCK_GUARD(&qemu_logfile_mutex);
if (qemu_logfile && !need_to_open_file) {
logfile = qemu_logfile;
atomic_rcu_set(&qemu_logfile, NULL);
@@ -136,7 +137,6 @@ void qemu_set_log(int log_flags)
}
atomic_rcu_set(&qemu_logfile, logfile);
}
- qemu_mutex_unlock(&qemu_logfile_mutex);
}
void qemu_log_needs_buffers(void)
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index d548d3c1ad..b6575a2cd5 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -459,17 +459,16 @@ void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
QEMUTimerList *timer_list = ts->timer_list;
bool rearm;
- qemu_mutex_lock(&timer_list->active_timers_lock);
- if (ts->expire_time == -1 || ts->expire_time > expire_time) {
- if (ts->expire_time != -1) {
- timer_del_locked(timer_list, ts);
+ WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
+ if (ts->expire_time == -1 || ts->expire_time > expire_time) {
+ if (ts->expire_time != -1) {
+ timer_del_locked(timer_list, ts);
+ }
+ rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
+ } else {
+ rearm = false;
}
- rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
- } else {
- rearm = false;
}
- qemu_mutex_unlock(&timer_list->active_timers_lock);
-
if (rearm) {
timerlist_rearm(timer_list);
}
diff --git a/util/rcu.c b/util/rcu.c
index 177a675619..60a37f72c3 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -31,6 +31,7 @@
#include "qemu/atomic.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
+#include "qemu/lockable.h"
#if defined(CONFIG_MALLOC_TRIM)
#include <malloc.h>
#endif
@@ -141,14 +142,14 @@ static void wait_for_readers(void)
void synchronize_rcu(void)
{
- qemu_mutex_lock(&rcu_sync_lock);
+ QEMU_LOCK_GUARD(&rcu_sync_lock);
/* Write RCU-protected pointers before reading p_rcu_reader->ctr.
* Pairs with smp_mb_placeholder() in rcu_read_lock().
*/
smp_mb_global();
- qemu_mutex_lock(&rcu_registry_lock);
+ QEMU_LOCK_GUARD(&rcu_registry_lock);
if (!QLIST_EMPTY(&registry)) {
/* In either case, the atomic_mb_set below blocks stores that free
* old RCU-protected pointers.
@@ -169,9 +170,6 @@ void synchronize_rcu(void)
wait_for_readers();
}
-
- qemu_mutex_unlock(&rcu_registry_lock);
- qemu_mutex_unlock(&rcu_sync_lock);
}
diff --git a/util/thread-pool.c b/util/thread-pool.c
index 4ed9b89ab2..d763cea505 100644
--- a/util/thread-pool.c
+++ b/util/thread-pool.c
@@ -210,7 +210,7 @@ static void thread_pool_cancel(BlockAIOCB *acb)
trace_thread_pool_cancel(elem, elem->common.opaque);
- qemu_mutex_lock(&pool->lock);
+ QEMU_LOCK_GUARD(&pool->lock);
if (elem->state == THREAD_QUEUED &&
/* No thread has yet started working on elem. we can try to "steal"
* the item from the worker if we can get a signal from the
@@ -225,7 +225,6 @@ static void thread_pool_cancel(BlockAIOCB *acb)
elem->ret = -ECANCELED;
}
- qemu_mutex_unlock(&pool->lock);
}
static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb)
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
index ddd9a96e76..e399e330e2 100644
--- a/util/vfio-helpers.c
+++ b/util/vfio-helpers.c
@@ -21,6 +21,7 @@
#include "standard-headers/linux/pci_regs.h"
#include "qemu/event_notifier.h"
#include "qemu/vfio-helpers.h"
+#include "qemu/lockable.h"
#include "trace.h"
#define QEMU_VFIO_DEBUG 0
@@ -667,14 +668,12 @@ int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s)
.size = QEMU_VFIO_IOVA_MAX - s->high_water_mark,
};
trace_qemu_vfio_dma_reset_temporary(s);
- qemu_mutex_lock(&s->lock);
+ QEMU_LOCK_GUARD(&s->lock);
if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno));
- qemu_mutex_unlock(&s->lock);
return -errno;
}
s->high_water_mark = QEMU_VFIO_IOVA_MAX;
- qemu_mutex_unlock(&s->lock);
return 0;
}