target-arm queue:

* tests, scripts: Don't import print_function from __future__
  * Implement FEAT_ATS1A
  * Remove deprecated pxa CPU family
  * arm/kvm: report registers we failed to set
  * Expose SME registers to GDB via gdbstub
  * linux-user/aarch64: Generate ESR signal records
  * hw/arm/raspi4b: remove redundant check in raspi_add_memory_node
  * hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation
  * system: drop the -old-param option
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmjJpt8ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vRGEACO3VrePiMIA9N7egqlUiGn
 aRQVqIKeuPVj6TRVG7BSNWlAX8qvnOWOKg1yGVHDZv/nLvRje9UyfUAw7pf6jXod
 bzxWBCPJ0J0eOB64Tz87WRCLltKB5pEN+uIG00PtpBcXT1ixYCDgBZXyD3mwuJ4Q
 5Yc5hEwQzpmh+EycLtfCHbmjKDw3x1ncpVlGceOG4h5fvzIvIhcNcZJXfAHhbhyO
 Y4c5PELrCkCLZaTtSSxd6VJ+vXQ9bNWyKaSZu2KRRnLcMeAqw2Ic7dLPlkzCVyxM
 PTOHy4TuDu+kqCbkxdnhpI6fvq5kcHyfTL6qX6tth8ZZS+qKGtvMEIXnYoy6q1kh
 4jV5vizK8avx31fSiuTKVpttRv4dC+Aq5QrcgYtIVMeOwtkWHv610D8gcFPmXoG+
 uHX9WdzOjrYOzXVKzJaCZF6b7L31ptSEfOrx7asBC9k2wPRwonFXg4JGNq16Yann
 aAO5TM7NAUvM2IPgqS+Tf1Bk0iQqORxGfqzCyL76OO/QMMgfBy9elKH0UR0G+ePJ
 yjpub1oWIELSXsQGMrdFo1W4/NIpFMTu3DP9W+6XRPu1AvrAx/AsrTuvSvXoeFY9
 d/U3yWAXm5XxRzbCIUg7ke8I8zLwRz924M5PA8vophvSnfDLS3V8CJHLwbz/PqYc
 0P2KCeI6d2NIhVik4mgEoQ==
 =5tK3
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20250916' of https://gitlab.com/pm215/qemu into staging

target-arm queue:
 * tests, scripts: Don't import print_function from __future__
 * Implement FEAT_ATS1A
 * Remove deprecated pxa CPU family
 * arm/kvm: report registers we failed to set
 * Expose SME registers to GDB via gdbstub
 * linux-user/aarch64: Generate ESR signal records
 * hw/arm/raspi4b: remove redundant check in raspi_add_memory_node
 * hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation
 * system: drop the -old-param option

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmjJpt8ZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vRGEACO3VrePiMIA9N7egqlUiGn
# aRQVqIKeuPVj6TRVG7BSNWlAX8qvnOWOKg1yGVHDZv/nLvRje9UyfUAw7pf6jXod
# bzxWBCPJ0J0eOB64Tz87WRCLltKB5pEN+uIG00PtpBcXT1ixYCDgBZXyD3mwuJ4Q
# 5Yc5hEwQzpmh+EycLtfCHbmjKDw3x1ncpVlGceOG4h5fvzIvIhcNcZJXfAHhbhyO
# Y4c5PELrCkCLZaTtSSxd6VJ+vXQ9bNWyKaSZu2KRRnLcMeAqw2Ic7dLPlkzCVyxM
# PTOHy4TuDu+kqCbkxdnhpI6fvq5kcHyfTL6qX6tth8ZZS+qKGtvMEIXnYoy6q1kh
# 4jV5vizK8avx31fSiuTKVpttRv4dC+Aq5QrcgYtIVMeOwtkWHv610D8gcFPmXoG+
# uHX9WdzOjrYOzXVKzJaCZF6b7L31ptSEfOrx7asBC9k2wPRwonFXg4JGNq16Yann
# aAO5TM7NAUvM2IPgqS+Tf1Bk0iQqORxGfqzCyL76OO/QMMgfBy9elKH0UR0G+ePJ
# yjpub1oWIELSXsQGMrdFo1W4/NIpFMTu3DP9W+6XRPu1AvrAx/AsrTuvSvXoeFY9
# d/U3yWAXm5XxRzbCIUg7ke8I8zLwRz924M5PA8vophvSnfDLS3V8CJHLwbz/PqYc
# 0P2KCeI6d2NIhVik4mgEoQ==
# =5tK3
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 16 Sep 2025 11:05:19 AM PDT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [unknown]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [unknown]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [unknown]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20250916' of https://gitlab.com/pm215/qemu: (36 commits)
  hw/usb/network: Remove hardcoded 0x40 prefix in STRING_ETHADDR response
  qtest/bios-tables-test: Update tables for smmuv3 tests
  qtest/bios-tables-test: Add tests for legacy smmuv3 and smmuv3 device
  bios-tables-test: Allow for smmuv3 test data.
  qemu-options.hx: Document the arm-smmuv3 device
  hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation
  hw/pci: Introduce pci_setup_iommu_per_bus() for per-bus IOMMU ops retrieval
  hw/arm/virt: Add an SMMU_IO_LEN macro
  hw/arm/virt: Factor out common SMMUV3 dt bindings code
  hw/arm/virt-acpi-build: Update IORT for multiple smmuv3 devices
  hw/arm/virt-acpi-build: Re-arrange SMMUv3 IORT build
  hw/arm/smmu-common: Check SMMU has PCIe Root Complex association
  target/arm: Added test case for SME register exposure to GDB
  target/arm: Added support for SME register exposure to GDB
  target/arm: Increase MAX_PACKET_LENGTH for SME ZA remote gdb debugging
  arm/kvm: report registers we failed to set
  system: drop the -old-param option
  target/arm: Drop ARM_FEATURE_IWMMXT handling
  target/arm: Drop ARM_FEATURE_XSCALE handling
  target/arm: Remove iwmmxt helper functions
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-09-17 11:10:55 -07:00
commit f0007b7f03
72 changed files with 1151 additions and 2794 deletions

View file

@ -86,7 +86,6 @@ static uint32_t get_elf_hwcap(void)
/* probe for the extra features */
/* EDSP is in v5TE and above */
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);

6
configure vendored
View file

@ -1839,6 +1839,12 @@ for target in $target_list; do
echo "GDB=$gdb_bin" >> $config_target_mak
fi
if test "${gdb_arches#*$arch}" != "$gdb_arches" && version_ge $gdb_version 14.1; then
echo "GDB_HAS_SME_TILES=y" >> $config_target_mak
else
echo "GDB_HAS_SME_TILES=n" >> $config_target_mak
fi
if test "${gdb_arches#*aarch64}" != "$gdb_arches" && version_ge $gdb_version 15.1; then
echo "GDB_HAS_MTE=y" >> $config_target_mak
fi

View file

@ -68,19 +68,6 @@ configurations (e.g. -smp drawers=1,books=1,clusters=1 for x86 PC machine) is
marked deprecated since 9.0, users have to ensure that all the topology members
described with -smp are supported by the target machine.
``-old-param`` option for booting Arm kernels via param_struct (since 10.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The ``-old-param`` command line option is specific to Arm targets:
it is used when directly booting a guest kernel to pass it the
command line and other information via the old ``param_struct`` ABI,
rather than the newer ATAGS or DTB mechanisms. This option was only
ever needed to support ancient kernels on some old board types
like the ``akita`` or ``terrier``; it has been deprecated in the
kernel since 2001. None of the board types QEMU supports need
``param_struct`` support, so this option has been deprecated and will
be removed in a future QEMU version.
QEMU Machine Protocol (QMP) commands
------------------------------------
@ -236,27 +223,6 @@ Keeping 32-bit host support alive is a substantial burden for the
QEMU project. Thus QEMU will in future drop the support for all
32-bit host systems.
linux-user mode CPUs
--------------------
iwMMXt emulation and the ``pxa`` CPUs (since 10.0)
''''''''''''''''''''''''''''''''''''''''''''''''''
The ``pxa`` CPU family (``pxa250``, ``pxa255``, ``pxa260``,
``pxa261``, ``pxa262``, ``pxa270-a0``, ``pxa270-a1``, ``pxa270``,
``pxa270-b0``, ``pxa270-b1``, ``pxa270-c0``, ``pxa270-c5``) are no
longer used in system emulation, because all the machine types which
used these CPUs were removed in the QEMU 9.2 release. These CPUs can
now only be used in linux-user mode, and to do that you would have to
explicitly select one of these CPUs with the ``-cpu`` command line
option or the ``QEMU_CPU`` environment variable.
We don't believe that anybody is using the iwMMXt emulation, and we do
not have any tests to validate it or any real hardware or similar
known-good implementation to test against. GCC is in the process of
dropping their support for iwMMXt codegen. These CPU types are
therefore deprecated in QEMU, and will be removed in a future release.
System emulator CPUs
--------------------

View file

@ -560,6 +560,18 @@ the options along with the machine models they were intended for.
Use ``-run-with user=..`` instead.
``-old-param`` option for booting Arm kernels via param_struct (removed in 10.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The ``-old-param`` command line option was specific to Arm targets:
it was used when directly booting a guest kernel to pass it the
command line and other information via the old ``param_struct`` ABI,
rather than the newer ATAGS or DTB mechanisms. This option was only
ever needed to support ancient kernels on some old board types
like the ``akita`` or ``terrier``; it has been deprecated in the
kernel since 2001. None of the board types QEMU supports need
``param_struct`` support, so this option has been removed.
User-mode emulator command line arguments
-----------------------------------------
@ -1138,6 +1150,20 @@ reason the maintainers strongly suspected no one actually used it.
QEMU Nios II architecture was orphan; Intel has EOL'ed the Nios II
processor IP (see `Intel discontinuance notification`_).
iwMMXt emulation and the ``pxa`` CPUs (removed in 10.2)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
The ``pxa`` CPU family (``pxa250``, ``pxa255``, ``pxa260``,
``pxa261``, ``pxa262``, ``pxa270-a0``, ``pxa270-a1``, ``pxa270``,
``pxa270-b0``, ``pxa270-b1``, ``pxa270-c0``, ``pxa270-c5``) were
not available in system emulation, because all the machine types which
used these CPUs were removed in the QEMU 9.2 release. We don't
believe that anybody was using the iwMMXt emulation (which you
would have to explicitly enable on the command line), and we did
not have any tests to validate it or any real hardware or similar
known-good implementation to test against. These CPUs have
therefore been removed in linux-user mode as well.
TCG introspection features
--------------------------

View file

@ -23,6 +23,7 @@ the following architecture extensions:
- FEAT_AFP (Alternate floating-point behavior)
- FEAT_Armv9_Crypto (Armv9 Cryptographic Extension)
- FEAT_ASID16 (16 bit ASID)
- FEAT_ATS1A (Address Translation operations that ignore stage 1 permissions)
- FEAT_BBM at level 2 (Translation table break-before-make levels)
- FEAT_BF16 (AArch64 BFloat16 instructions)
- FEAT_BTI (Branch Target Identification)

View file

@ -11,7 +11,27 @@
#include "exec/cpu-common.h"
#define MAX_PACKET_LENGTH 4096
/*
* Most "large" transfers (e.g. memory reads, feature XML
* transfer) have mechanisms in the gdb protocol for splitting
* them. However, register values in particular cannot currently
* be split. This packet size must therefore be at least big enough
* for the worst-case register size. Currently that is Arm SME
* ZA storage with a 256x256 byte value. We also must account
* for the conversion from raw data to hex in gdb_memtohex(),
* which writes 2 * size bytes, and for other protocol overhead
* including command, register number and checksum which add
* another 4 bytes of overhead. However, to be consistent with
* the changes made in gdbserver to address this same requirement,
* we add a total of 32 bytes to account for protocol overhead
* (unclear why specifically 32 bytes), bringing the value of
* MAX_PACKET_LENGTH to 2 * 256 * 256 + 32 = 131104.
*
* The commit making this change for gdbserver can be found here:
* https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=
* b816042e88583f280ad186ff124ab84d31fb592b
*/
#define MAX_PACKET_LENGTH 131104
/*
* Shared structures and definitions

View file

@ -337,81 +337,6 @@ static void set_kernel_args(const struct arm_boot_info *info, AddressSpace *as)
WRITE_WORD(p, 0);
}
static void set_kernel_args_old(const struct arm_boot_info *info,
AddressSpace *as)
{
hwaddr p;
const char *s;
int initrd_size = info->initrd_size;
hwaddr base = info->loader_start;
/* see linux/include/asm-arm/setup.h */
p = base + KERNEL_ARGS_ADDR;
/* page_size */
WRITE_WORD(p, 4096);
/* nr_pages */
WRITE_WORD(p, info->ram_size / 4096);
/* ramdisk_size */
WRITE_WORD(p, 0);
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
/* flags */
WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
/* rootdev */
WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */
/* video_num_cols */
WRITE_WORD(p, 0);
/* video_num_rows */
WRITE_WORD(p, 0);
/* video_x */
WRITE_WORD(p, 0);
/* video_y */
WRITE_WORD(p, 0);
/* memc_control_reg */
WRITE_WORD(p, 0);
/* unsigned char sounddefault */
/* unsigned char adfsdrives */
/* unsigned char bytes_per_char_h */
/* unsigned char bytes_per_char_v */
WRITE_WORD(p, 0);
/* pages_in_bank[4] */
WRITE_WORD(p, 0);
WRITE_WORD(p, 0);
WRITE_WORD(p, 0);
WRITE_WORD(p, 0);
/* pages_in_vram */
WRITE_WORD(p, 0);
/* initrd_start */
if (initrd_size) {
WRITE_WORD(p, info->initrd_start);
} else {
WRITE_WORD(p, 0);
}
/* initrd_size */
WRITE_WORD(p, initrd_size);
/* rd_start */
WRITE_WORD(p, 0);
/* system_rev */
WRITE_WORD(p, 0);
/* system_serial_low */
WRITE_WORD(p, 0);
/* system_serial_high */
WRITE_WORD(p, 0);
/* mem_fclk_21285 */
WRITE_WORD(p, 0);
/* zero unused fields */
while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
WRITE_WORD(p, 0);
}
s = info->kernel_cmdline;
if (s) {
address_space_write(as, p, MEMTXATTRS_UNSPECIFIED, s, strlen(s) + 1);
} else {
WRITE_WORD(p, 0);
}
}
static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base,
uint32_t scells, hwaddr mem_len,
int numa_node_id)
@ -802,11 +727,7 @@ static void do_cpu_reset(void *opaque)
cpu_set_pc(cs, info->loader_start);
if (!have_dtb(info)) {
if (old_param) {
set_kernel_args_old(info, as);
} else {
set_kernel_args(info, as);
}
set_kernel_args(info, as);
}
} else if (info->secondary_cpu_reset_hook) {
info->secondary_cpu_reset_hook(cpu, info);

View file

@ -36,9 +36,8 @@ struct Raspi4bMachineState {
* (see https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
* 1.2 Address Map)
*/
static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
static void raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
{
int ret;
uint32_t acells, scells;
char *nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
@ -46,19 +45,16 @@ static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
NULL, &error_fatal);
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
NULL, &error_fatal);
if (acells == 0 || scells == 0) {
fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
ret = -1;
} else {
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, mem_base,
scells, mem_len);
}
/* validated by arm_load_dtb */
g_assert(acells && scells);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, mem_base,
scells, mem_len);
g_free(nodename);
return ret;
}
static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt)

View file

@ -20,6 +20,7 @@
#include "trace.h"
#include "exec/target_page.h"
#include "hw/core/cpu.h"
#include "hw/pci/pci_bridge.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/jhash.h"
@ -925,6 +926,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
{
SMMUState *s = ARM_SMMU(dev);
SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(dev);
PCIBus *pci_bus = s->primary_bus;
Error *local_err = NULL;
sbc->parent_realize(dev, &local_err);
@ -937,11 +939,39 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
g_free, g_free);
s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL);
if (s->primary_bus) {
pci_setup_iommu(s->primary_bus, &smmu_ops, s);
} else {
if (!pci_bus) {
error_setg(errp, "SMMU is not attached to any PCI bus!");
return;
}
/*
* We only allow default PCIe Root Complex(pcie.0) or pxb-pcie based extra
* root complexes to be associated with SMMU.
*/
if (pci_bus_is_express(pci_bus) && pci_bus_is_root(pci_bus) &&
object_dynamic_cast(OBJECT(pci_bus)->parent, TYPE_PCI_HOST_BRIDGE)) {
/*
* This condition matches either the default pcie.0, pxb-pcie, or
* pxb-cxl. For both pxb-pcie and pxb-cxl, parent_dev will be set.
* Currently, we don't allow pxb-cxl as it requires further
* verification. Therefore, make sure this is indeed pxb-pcie.
*/
if (pci_bus->parent_dev) {
if (!object_dynamic_cast(OBJECT(pci_bus), TYPE_PXB_PCIE_BUS)) {
goto out_err;
}
}
if (s->smmu_per_bus) {
pci_setup_iommu_per_bus(pci_bus, &smmu_ops, s);
} else {
pci_setup_iommu(pci_bus, &smmu_ops, s);
}
return;
}
out_err:
error_setg(errp, "SMMU should be attached to a default PCIe root complex"
"(pcie.0) or a pxb-pcie based root complex");
}
/*
@ -961,6 +991,7 @@ static void smmu_base_reset_exit(Object *obj, ResetType type)
static const Property smmu_dev_properties[] = {
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false),
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
TYPE_PCI_BUS, PCIBus *),
};

View file

@ -1996,6 +1996,8 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
device_class_set_parent_realize(dc, smmu_realize,
&c->parent_realize);
device_class_set_props(dc, smmuv3_properties);
dc->hotpluggable = false;
dc->user_creatable = true;
}
static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,

View file

@ -45,6 +45,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/hmat.h"
#include "hw/arm/smmuv3.h"
#include "hw/cxl/cxl.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
@ -305,29 +306,126 @@ static int iort_idmap_compare(gconstpointer a, gconstpointer b)
return idmap_a->input_base - idmap_b->input_base;
}
typedef struct AcpiIortSMMUv3Dev {
int irq;
hwaddr base;
GArray *rc_smmu_idmaps;
/* Offset of the SMMUv3 IORT Node relative to the start of the IORT */
size_t offset;
} AcpiIortSMMUv3Dev;
/*
* Populate the struct AcpiIortSMMUv3Dev for the legacy SMMUv3 and
* return the total number of associated idmaps.
*/
static int populate_smmuv3_legacy_dev(GArray *sdev_blob)
{
VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
AcpiIortSMMUv3Dev sdev;
sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
object_child_foreach_recursive(object_get_root(), iort_host_bridges,
sdev.rc_smmu_idmaps);
/*
* There can be only one legacy SMMUv3("iommu=smmuv3") as it is a machine
* wide one. Since it may cover multiple PCIe RCs(based on "bypass_iommu"
* property), may have multiple SMMUv3 idmaps. Sort it by input_base.
*/
g_array_sort(sdev.rc_smmu_idmaps, iort_idmap_compare);
sdev.base = vms->memmap[VIRT_SMMU].base;
sdev.irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
g_array_append_val(sdev_blob, sdev);
return sdev.rc_smmu_idmaps->len;
}
static int smmuv3_dev_idmap_compare(gconstpointer a, gconstpointer b)
{
AcpiIortSMMUv3Dev *sdev_a = (AcpiIortSMMUv3Dev *)a;
AcpiIortSMMUv3Dev *sdev_b = (AcpiIortSMMUv3Dev *)b;
AcpiIortIdMapping *map_a = &g_array_index(sdev_a->rc_smmu_idmaps,
AcpiIortIdMapping, 0);
AcpiIortIdMapping *map_b = &g_array_index(sdev_b->rc_smmu_idmaps,
AcpiIortIdMapping, 0);
return map_a->input_base - map_b->input_base;
}
static int iort_smmuv3_devices(Object *obj, void *opaque)
{
VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
GArray *sdev_blob = opaque;
AcpiIortIdMapping idmap;
PlatformBusDevice *pbus;
AcpiIortSMMUv3Dev sdev;
int min_bus, max_bus;
SysBusDevice *sbdev;
PCIBus *bus;
if (!object_dynamic_cast(obj, TYPE_ARM_SMMUV3)) {
return 0;
}
bus = PCI_BUS(object_property_get_link(obj, "primary-bus", &error_abort));
pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
sbdev = SYS_BUS_DEVICE(obj);
sdev.base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
sdev.base += vms->memmap[VIRT_PLATFORM_BUS].base;
sdev.irq = platform_bus_get_irqn(pbus, sbdev, 0);
sdev.irq += vms->irqmap[VIRT_PLATFORM_BUS];
sdev.irq += ARM_SPI_BASE;
pci_bus_range(bus, &min_bus, &max_bus);
sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
idmap.input_base = min_bus << 8,
idmap.id_count = (max_bus - min_bus + 1) << 8,
g_array_append_val(sdev.rc_smmu_idmaps, idmap);
g_array_append_val(sdev_blob, sdev);
return 0;
}
/*
* Populate the struct AcpiIortSMMUv3Dev for all SMMUv3 devices and
* return the total number of idmaps.
*/
static int populate_smmuv3_dev(GArray *sdev_blob)
{
object_child_foreach_recursive(object_get_root(),
iort_smmuv3_devices, sdev_blob);
/* Sort the smmuv3 devices(if any) by smmu idmap input_base */
g_array_sort(sdev_blob, smmuv3_dev_idmap_compare);
/*
* Since each SMMUv3 dev is assocaited with specific host bridge,
* total number of idmaps equals to total number of smmuv3 devices.
*/
return sdev_blob->len;
}
/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmuv3_devs)
{
AcpiIortIdMapping *idmap;
AcpiIortIdMapping next_range = {0};
AcpiIortSMMUv3Dev *sdev;
/*
* Based on the RID ranges that are directed to the SMMU, determine the
* bypassed RID ranges, i.e., the ones that are directed to the ITS Group
* node and do not pass through the SMMU, by subtracting the SMMU-bound
* ranges from the full RID range (0x00000xFFFF).
*/
for (int i = 0; i < smmu_idmaps->len; i++) {
idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i);
for (int i = 0; i < smmuv3_devs->len; i++) {
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
/*
* Based on the RID ranges that are directed to the SMMU, determine the
* bypassed RID ranges, i.e., the ones that are directed to the ITS
* Group node and do not pass through the SMMU, by subtracting the
* SMMU-bound ranges from the full RID range (0x00000xFFFF).
*/
for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
idmap = &g_array_index(sdev->rc_smmu_idmaps, AcpiIortIdMapping, j);
if (next_range.input_base < idmap->input_base) {
next_range.id_count = idmap->input_base - next_range.input_base;
g_array_append_val(its_idmaps, next_range);
if (next_range.input_base < idmap->input_base) {
next_range.id_count = idmap->input_base - next_range.input_base;
g_array_append_val(its_idmaps, next_range);
}
next_range.input_base = idmap->input_base + idmap->id_count;
}
next_range.input_base = idmap->input_base + idmap->id_count;
}
/*
* Append the last RC -> ITS ID mapping.
*
@ -341,7 +439,6 @@ static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
}
}
/*
* Input Output Remapping Table (IORT)
* Conforms to "IO Remapping Table System Software on ARM Platforms",
@ -351,9 +448,12 @@ static void
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
int i, nb_nodes, rc_mapping_count;
size_t node_size, smmu_offset = 0;
AcpiIortSMMUv3Dev *sdev;
size_t node_size;
int num_smmus = 0;
uint32_t id = 0;
GArray *rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
int rc_smmu_idmaps_len = 0;
GArray *smmuv3_devs = g_array_new(false, true, sizeof(AcpiIortSMMUv3Dev));
GArray *rc_its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
AcpiTable table = { .sig = "IORT", .rev = 3, .oem_id = vms->oem_id,
@ -361,22 +461,23 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Table 2 The IORT */
acpi_table_begin(&table, table_data);
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
object_child_foreach_recursive(object_get_root(),
iort_host_bridges, rc_smmu_idmaps);
if (vms->legacy_smmuv3_present) {
rc_smmu_idmaps_len = populate_smmuv3_legacy_dev(smmuv3_devs);
} else {
rc_smmu_idmaps_len = populate_smmuv3_dev(smmuv3_devs);
}
/* Sort the smmu idmap by input_base */
g_array_sort(rc_smmu_idmaps, iort_idmap_compare);
nb_nodes = 2; /* RC and SMMUv3 */
rc_mapping_count = rc_smmu_idmaps->len;
num_smmus = smmuv3_devs->len;
if (num_smmus) {
nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
rc_mapping_count = rc_smmu_idmaps_len;
if (vms->its) {
/*
* Knowing the ID ranges from the RC to the SMMU, it's possible to
* determine the ID ranges from RC that go directly to ITS.
*/
create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps);
create_rc_its_idmaps(rc_its_idmaps, smmuv3_devs);
nb_nodes++; /* ITS */
rc_mapping_count += rc_its_idmaps->len;
@ -411,9 +512,10 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0 /* MADT translation_id */, 4);
}
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
int irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
for (i = 0; i < num_smmus; i++) {
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
int smmu_mapping_count, offset_to_id_array;
int irq = sdev->irq;
if (vms->its) {
smmu_mapping_count = 1; /* ITS Group node */
@ -422,7 +524,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
smmu_mapping_count = 0; /* No ID mappings */
offset_to_id_array = 0; /* No ID mappings array */
}
smmu_offset = table_data->len - table.table_offset;
sdev->offset = table_data->len - table.table_offset;
/* Table 9 SMMUv3 Format */
build_append_int_noprefix(table_data, 4 /* SMMUv3 */, 1); /* Type */
node_size = SMMU_V3_ENTRY_SIZE +
@ -435,7 +537,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Reference to ID Array */
build_append_int_noprefix(table_data, offset_to_id_array, 4);
/* Base address */
build_append_int_noprefix(table_data, vms->memmap[VIRT_SMMU].base, 8);
build_append_int_noprefix(table_data, sdev->base, 8);
/* Flags */
build_append_int_noprefix(table_data, 1 /* COHACC Override */, 4);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
@ -486,21 +588,26 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0, 3); /* Reserved */
/* Output Reference */
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
if (num_smmus) {
AcpiIortIdMapping *range;
/*
* Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
*
* N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS) is
* defined in the SMMUv3 table, where all SMMUv3 IDs are mapped to the
* ITS Group node, if ITS is available.
*/
for (i = 0; i < rc_smmu_idmaps->len; i++) {
range = &g_array_index(rc_smmu_idmaps, AcpiIortIdMapping, i);
/* Output IORT node is the SMMUv3 node. */
build_iort_id_mapping(table_data, range->input_base,
range->id_count, smmu_offset);
for (i = 0; i < num_smmus; i++) {
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
/*
* Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
*
* N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS)
* is defined in the SMMUv3 table, where all SMMUv3 IDs are mapped
* to the ITS Group node, if ITS is available.
*/
for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
range = &g_array_index(sdev->rc_smmu_idmaps,
AcpiIortIdMapping, j);
/* Output IORT node is the SMMUv3 node. */
build_iort_id_mapping(table_data, range->input_base,
range->id_count, sdev->offset);
}
}
if (vms->its) {
@ -525,8 +632,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
acpi_table_end(linker, &table);
g_array_free(rc_smmu_idmaps, true);
g_array_free(rc_its_idmaps, true);
for (i = 0; i < num_smmus; i++) {
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
g_array_free(sdev->rc_smmu_idmaps, true);
}
g_array_free(smmuv3_devs, true);
}
/*

View file

@ -55,6 +55,7 @@
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci-host/gpex.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/virtio/virtio-pci.h"
@ -149,6 +150,9 @@ static void arm_virt_compat_set(MachineClass *mc)
#define LEGACY_RAMLIMIT_GB 255
#define LEGACY_RAMLIMIT_BYTES (LEGACY_RAMLIMIT_GB * GiB)
/* MMIO region size for SMMUv3 */
#define SMMU_IO_LEN 0x20000
/* Addresses and sizes of our components.
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
* 128MB..256MB is used for miscellaneous device I/O.
@ -180,7 +184,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
[VIRT_UART1] = { 0x09040000, 0x00001000 },
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
[VIRT_SMMU] = { 0x09050000, SMMU_IO_LEN },
[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},
@ -1442,19 +1446,66 @@ static void create_pcie_irq_map(const MachineState *ms,
0x7 /* PCI irq */);
}
static void create_smmuv3_dt_bindings(const VirtMachineState *vms, hwaddr base,
hwaddr size, int irq)
{
char *node;
const char compat[] = "arm,smmu-v3";
const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
MachineState *ms = MACHINE(vms);
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
qemu_fdt_add_subnode(ms->fdt, node);
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
sizeof(irq_names));
qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
g_free(node);
}
static void create_smmuv3_dev_dtb(VirtMachineState *vms,
DeviceState *dev, PCIBus *bus)
{
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
int irq = platform_bus_get_irqn(pbus, sbdev, 0);
hwaddr base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
MachineState *ms = MACHINE(vms);
if (!(vms->bootinfo.firmware_loaded && virt_is_acpi_enabled(vms)) &&
strcmp("pcie.0", bus->qbus.name)) {
warn_report("SMMUv3 device only supported with pcie.0 for DT");
return;
}
base += vms->memmap[VIRT_PLATFORM_BUS].base;
irq += vms->irqmap[VIRT_PLATFORM_BUS];
vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
create_smmuv3_dt_bindings(vms, base, SMMU_IO_LEN, irq);
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
}
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
char *node;
const char compat[] = "arm,smmu-v3";
int irq = vms->irqmap[VIRT_SMMU];
int i;
hwaddr base = vms->memmap[VIRT_SMMU].base;
hwaddr size = vms->memmap[VIRT_SMMU].size;
const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
DeviceState *dev;
MachineState *ms = MACHINE(vms);
if (vms->iommu != VIRT_IOMMU_SMMUV3 || !vms->iommu_phandle) {
return;
@ -1473,27 +1524,7 @@ static void create_smmu(const VirtMachineState *vms,
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
}
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
qemu_fdt_add_subnode(ms->fdt, node);
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
sizeof(irq_names));
qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
g_free(node);
create_smmuv3_dt_bindings(vms, base, size, irq);
}
static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)
@ -1649,6 +1680,7 @@ static void create_pcie(VirtMachineState *vms)
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
}
vms->legacy_smmuv3_present = true;
break;
default:
g_assert_not_reached();
@ -2996,6 +3028,16 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
qlist_append_str(reserved_regions, resv_prop_str);
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
error_setg(errp, "virt machine already has %s set. "
"Doesn't support incompatible iommus",
(vms->legacy_smmuv3_present) ?
"iommu=smmuv3" : "virtio-iommu");
} else if (vms->iommu == VIRT_IOMMU_NONE) {
/* The new SMMUv3 device is specific to the PCI bus */
object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL);
}
}
}
@ -3019,6 +3061,22 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
}
if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
if (!vms->legacy_smmuv3_present && vms->platform_bus_dev) {
PCIBus *bus;
bus = PCI_BUS(object_property_get_link(OBJECT(dev), "primary-bus",
&error_abort));
if (pci_bus_bypass_iommu(bus)) {
error_setg(errp, "Bypass option cannot be set for SMMUv3 "
"associated PCIe RC");
return;
}
create_smmuv3_dev_dtb(vms, dev, bus);
}
}
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
PCIDevice *pdev = PCI_DEVICE(dev);
@ -3218,6 +3276,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->max_cpus = 512;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif

View file

@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "system/device_tree.h"
#include "system/tpm.h"
#include "hw/arm/smmuv3.h"
#include "hw/platform-bus.h"
#include "hw/display/ramfb.h"
#include "hw/uefi/var-service-api.h"
@ -135,6 +136,8 @@ static const BindingEntry bindings[] = {
#ifdef CONFIG_TPM
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
#endif
/* No generic DT support for smmuv3 dev. Support added for arm virt only */
TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
TYPE_BINDING("", NULL), /* last element */

View file

@ -34,7 +34,6 @@ typedef struct PXBBus PXBBus;
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
TYPE_PXB_BUS)
#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
TYPE_PXB_PCIE_BUS)

View file

@ -2912,6 +2912,19 @@ static void pci_device_get_iommu_bus_devfn(PCIDevice *dev,
}
}
/*
* When multiple PCI Express Root Buses are defined using pxb-pcie,
* the IOMMU configuration may be specific to each root bus. However,
* pxb-pcie acts as a special root complex whose parent is effectively
* the default root complex(pcie.0). Ensure that we retrieve the
* correct IOMMU ops(if any) in such cases.
*/
if (pci_bus_is_express(iommu_bus) && pci_bus_is_root(iommu_bus)) {
if (parent_bus->iommu_per_bus) {
break;
}
}
iommu_bus = parent_bus;
}
@ -3172,6 +3185,24 @@ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque)
bus->iommu_opaque = opaque;
}
/*
* Similar to pci_setup_iommu(), but sets iommu_per_bus to true,
* indicating that the IOMMU is specific to this bus. This is used by
* IOMMU implementations that are tied to a specific PCIe root complex.
*
* In QEMU, pxb-pcie behaves as a special root complex whose parent is
* effectively the default root complex (pcie.0). The iommu_per_bus
* is checked in pci_device_get_iommu_bus_devfn() to ensure the correct
* IOMMU ops are returned, avoiding the use of the parents IOMMU when
* it's not appropriate.
*/
void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops,
void *opaque)
{
pci_setup_iommu(bus, ops, opaque);
bus->iommu_per_bus = true;
}
static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
{
Range *range = opaque;

View file

@ -1383,7 +1383,7 @@ static void usb_net_realize(USBDevice *dev, Error **errp)
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
"%02x%02x%02x%02x%02x%02x",
0x40,
s->conf.macaddr.a[0],
s->conf.macaddr.a[1],
s->conf.macaddr.a[2],
s->conf.macaddr.a[3],

View file

@ -161,6 +161,7 @@ struct SMMUState {
QLIST_HEAD(, SMMUDevice) devices_with_notifiers;
uint8_t bus_num;
PCIBus *primary_bus;
bool smmu_per_bus; /* SMMU is specific to the primary_bus */
};
struct SMMUBaseClass {

View file

@ -179,6 +179,7 @@ struct VirtMachineState {
char *oem_table_id;
bool ns_el2_virt_timer_irq;
CXLState cxl_devices_state;
bool legacy_smmuv3_present;
};
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)

View file

@ -773,6 +773,8 @@ int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
*/
void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
pcibus_t pci_bar_address(PCIDevice *d,
int reg, uint8_t type, pcibus_t size);

View file

@ -104,6 +104,7 @@ typedef struct PXBPCIEDev {
PXBDev parent_obj;
} PXBPCIEDev;
#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
#define TYPE_PXB_DEV "pxb"
OBJECT_DECLARE_SIMPLE_TYPE(PXBDev, PXB_DEV)

View file

@ -35,6 +35,7 @@ struct PCIBus {
enum PCIBusFlags flags;
const PCIIOMMUOps *iommu_ops;
void *iommu_opaque;
bool iommu_per_bus;
uint8_t devfn_min;
uint32_t slot_reserved_mask;
pci_set_irq_fn set_irq;

View file

@ -42,7 +42,6 @@ extern int graphic_height;
extern int graphic_depth;
extern int display_opengl;
extern const char *keyboard_layout;
extern int old_param;
extern uint8_t *boot_splash_filedata;
extern bool enable_cpu_pm;
extern QEMUClockType rtc_clock;

View file

@ -27,11 +27,132 @@
#include "target/arm/syndrome.h"
#include "target/arm/cpu-features.h"
/* Use the exception syndrome to map a cpu exception to a signal. */
static void signal_for_exception(CPUARMState *env, vaddr addr)
{
uint32_t syn = env->exception.syndrome;
int si_code, si_signo;
/* Let signal delivery see that ESR is live. */
env->cp15.esr_el[1] = syn;
switch (syn_get_ec(syn)) {
case EC_DATAABORT:
case EC_INSNABORT:
/* Both EC have the same format for FSC, or close enough. */
switch (extract32(syn, 0, 6)) {
case 0x04 ... 0x07: /* Translation fault, level {0-3} */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MAPERR;
break;
case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_ACCERR;
break;
case 0x11: /* Synchronous Tag Check Fault */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MTESERR;
break;
case 0x21: /* Alignment fault */
si_signo = TARGET_SIGBUS;
si_code = TARGET_BUS_ADRALN;
break;
default:
g_assert_not_reached();
}
break;
case EC_PCALIGNMENT:
si_signo = TARGET_SIGBUS;
si_code = TARGET_BUS_ADRALN;
break;
case EC_UNCATEGORIZED: /* E.g. undefined instruction */
case EC_SYSTEMREGISTERTRAP: /* E.g. inaccessible register */
case EC_SMETRAP: /* E.g. invalid insn in streaming state */
case EC_BTITRAP: /* E.g. invalid guarded branch target */
case EC_ILLEGALSTATE:
/*
* Illegal state happens via an ERET from a privileged mode,
* so is not normally possible from user-only. However, gdbstub
* is not prevented from writing CPSR_IL, aka PSTATE.IL, which
* would generate a trap from the next translated block.
* In the kernel, default case -> el0_inv -> bad_el0_sync.
*/
si_signo = TARGET_SIGILL;
si_code = TARGET_ILL_ILLOPC;
break;
case EC_PACFAIL:
si_signo = TARGET_SIGILL;
si_code = TARGET_ILL_ILLOPN;
break;
case EC_MOP:
/*
* FIXME: The kernel fixes up wrong-option exceptions.
* For QEMU linux-user mode, you can only get these if
* the process is doing something silly (not executing
* the MOPS instructions in the required P/M/E sequence),
* so it is not a problem in practice that we do not.
*
* We ought ideally to implement the same "rewind to the
* start of the sequence" logic that the kernel does in
* arm64_mops_reset_regs(). In the meantime, deliver
* the guest a SIGILL, with the same ILLOPN si_code
* we've always used for this.
*/
si_signo = TARGET_SIGILL;
si_code = TARGET_ILL_ILLOPN;
break;
case EC_WFX_TRAP: /* user-only WFI implemented as NOP */
case EC_CP15RTTRAP: /* AArch32 */
case EC_CP15RRTTRAP: /* AArch32 */
case EC_CP14RTTRAP: /* AArch32 */
case EC_CP14DTTRAP: /* AArch32 */
case EC_ADVSIMDFPACCESSTRAP: /* user-only does not disable fpu */
case EC_FPIDTRAP: /* AArch32 */
case EC_PACTRAP: /* user-only does not disable pac regs */
case EC_BXJTRAP: /* AArch32 */
case EC_CP14RRTTRAP: /* AArch32 */
case EC_AA32_SVC: /* AArch32 */
case EC_AA32_HVC: /* AArch32 */
case EC_AA32_SMC: /* AArch32 */
case EC_AA64_SVC: /* generates EXCP_SWI */
case EC_AA64_HVC: /* user-only generates EC_UNCATEGORIZED */
case EC_AA64_SMC: /* user-only generates EC_UNCATEGORIZED */
case EC_SVEACCESSTRAP: /* user-only does not disable sve */
case EC_ERETTRAP: /* user-only generates EC_UNCATEGORIZED */
case EC_GPC: /* user-only has no EL3 gpc tables */
case EC_INSNABORT_SAME_EL: /* el0 cannot trap to el0 */
case EC_DATAABORT_SAME_EL: /* el0 cannot trap to el0 */
case EC_SPALIGNMENT: /* sp alignment checks not implemented */
case EC_AA32_FPTRAP: /* fp exceptions not implemented */
case EC_AA64_FPTRAP: /* fp exceptions not implemented */
case EC_SERROR: /* user-only does not have hw faults */
case EC_BREAKPOINT: /* user-only does not have hw debug */
case EC_BREAKPOINT_SAME_EL: /* user-only does not have hw debug */
case EC_SOFTWARESTEP: /* user-only does not have hw debug */
case EC_SOFTWARESTEP_SAME_EL: /* user-only does not have hw debug */
case EC_WATCHPOINT: /* user-only does not have hw debug */
case EC_WATCHPOINT_SAME_EL: /* user-only does not have hw debug */
case EC_AA32_BKPT: /* AArch32 */
case EC_VECTORCATCH: /* AArch32 */
case EC_AA64_BKPT: /* generates EXCP_BKPT */
default:
g_assert_not_reached();
}
force_sig_fault(si_signo, si_code, addr);
}
/* AArch64 main loop */
void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
int trapnr, ec, fsc, si_code, si_signo;
int trapnr;
abi_long ret;
for (;;) {
@ -63,46 +184,11 @@ void cpu_loop(CPUARMState *env)
/* just indicate that signals should be handled asap */
break;
case EXCP_UDEF:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
signal_for_exception(env, env->pc);
break;
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
ec = syn_get_ec(env->exception.syndrome);
switch (ec) {
case EC_DATAABORT:
case EC_INSNABORT:
/* Both EC have the same format for FSC, or close enough. */
fsc = extract32(env->exception.syndrome, 0, 6);
switch (fsc) {
case 0x04 ... 0x07: /* Translation fault, level {0-3} */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MAPERR;
break;
case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_ACCERR;
break;
case 0x11: /* Synchronous Tag Check Fault */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MTESERR;
break;
case 0x21: /* Alignment fault */
si_signo = TARGET_SIGBUS;
si_code = TARGET_BUS_ADRALN;
break;
default:
g_assert_not_reached();
}
break;
case EC_PCALIGNMENT:
si_signo = TARGET_SIGBUS;
si_code = TARGET_BUS_ADRALN;
break;
default:
g_assert_not_reached();
}
force_sig_fault(si_signo, si_code, env->exception.vaddress);
signal_for_exception(env, env->exception.vaddress);
break;
case EXCP_DEBUG:
case EXCP_BKPT:

View file

@ -65,6 +65,13 @@ struct target_fpsimd_context {
uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
};
#define TARGET_ESR_MAGIC 0x45535201
struct target_esr_context {
struct target_aarch64_ctx head;
uint64_t esr;
};
#define TARGET_EXTRA_MAGIC 0x45585401
struct target_extra_context {
@ -201,6 +208,14 @@ static void target_setup_fpsimd_record(struct target_fpsimd_context *fpsimd,
}
}
static void target_setup_esr_record(struct target_esr_context *ctx,
CPUARMState *env)
{
__put_user(TARGET_ESR_MAGIC, &ctx->head.magic);
__put_user(sizeof(*ctx), &ctx->head.size);
__put_user(env->cp15.esr_el[1], &ctx->esr);
}
static void target_setup_extra_record(struct target_extra_context *extra,
uint64_t datap, uint32_t extra_size)
{
@ -531,6 +546,9 @@ static int target_restore_sigframe(CPUARMState *env,
fpsimd = (struct target_fpsimd_context *)ctx;
break;
case TARGET_ESR_MAGIC:
break; /* ignore */
case TARGET_SVE_MAGIC:
if (sve || size < sizeof(struct target_sve_context)) {
goto err;
@ -683,7 +701,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
uc.tuc_mcontext.__reserved),
};
int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
int zt_ofs = 0;
int zt_ofs = 0, esr_ofs = 0;
int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
struct target_rt_sigframe *frame;
struct target_rt_frame_record *fr;
@ -693,6 +711,15 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
fpsimd_ofs = alloc_sigframe_space(sizeof(struct target_fpsimd_context),
&layout);
/*
* In user mode, ESR_EL1 is only set by cpu_loop while queueing the
* signal, and it's only valid for the one sync insn.
*/
if (env->cp15.esr_el[1]) {
esr_ofs = alloc_sigframe_space(sizeof(struct target_esr_context),
&layout);
}
/* SVE state needs saving only if it exists. */
if (cpu_isar_feature(aa64_sve, env_archcpu(env)) ||
cpu_isar_feature(aa64_sme, env_archcpu(env))) {
@ -754,6 +781,11 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
target_setup_general_frame(frame, env, set);
target_setup_fpsimd_record((void *)frame + fpsimd_ofs, env);
if (esr_ofs) {
target_setup_esr_record((void *)frame + esr_ofs, env);
/* Leave ESR_EL1 clear while it's not relevant. */
env->cp15.esr_el[1] = 0;
}
target_setup_end_record((void *)frame + layout.std_end_ofs);
if (layout.extra_ofs) {
target_setup_extra_record((void *)frame + layout.extra_ofs,

View file

@ -76,7 +76,6 @@ abi_ulong get_elf_hwcap(CPUState *cs)
/* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);

View file

@ -76,21 +76,7 @@ struct target_vfp_sigframe {
struct target_user_vfp_exc ufp_exc;
} __attribute__((__aligned__(8)));
struct target_iwmmxt_sigframe {
abi_ulong magic;
abi_ulong size;
uint64_t regs[16];
/* Note that not all the coprocessor control registers are stored here */
uint32_t wcssf;
uint32_t wcasf;
uint32_t wcgr0;
uint32_t wcgr1;
uint32_t wcgr2;
uint32_t wcgr3;
} __attribute__((__aligned__(8)));
#define TARGET_VFP_MAGIC 0x56465001
#define TARGET_IWMMXT_MAGIC 0x12ef842a
struct sigframe
{
@ -267,25 +253,6 @@ static abi_ulong *setup_sigframe_vfp(abi_ulong *regspace, CPUARMState *env)
return (abi_ulong*)(vfpframe+1);
}
static abi_ulong *setup_sigframe_iwmmxt(abi_ulong *regspace, CPUARMState *env)
{
int i;
struct target_iwmmxt_sigframe *iwmmxtframe;
iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
__put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
__put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
for (i = 0; i < 16; i++) {
__put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
}
__put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
__put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
__put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
__put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
__put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
__put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
return (abi_ulong*)(iwmmxtframe+1);
}
static void setup_sigframe(struct target_ucontext *uc,
target_sigset_t *set, CPUARMState *env)
{
@ -306,9 +273,6 @@ static void setup_sigframe(struct target_ucontext *uc,
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
regspace = setup_sigframe_vfp(regspace, env);
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
regspace = setup_sigframe_iwmmxt(regspace, env);
}
/* Write terminating magic word */
__put_user(0, regspace);
@ -435,31 +399,6 @@ static abi_ulong *restore_sigframe_vfp(CPUARMState *env, abi_ulong *regspace)
return (abi_ulong*)(vfpframe + 1);
}
static abi_ulong *restore_sigframe_iwmmxt(CPUARMState *env,
abi_ulong *regspace)
{
int i;
abi_ulong magic, sz;
struct target_iwmmxt_sigframe *iwmmxtframe;
iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
__get_user(magic, &iwmmxtframe->magic);
__get_user(sz, &iwmmxtframe->size);
if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
return 0;
}
for (i = 0; i < 16; i++) {
__get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
}
__get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
__get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
__get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
__get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
__get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
__get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
return (abi_ulong*)(iwmmxtframe + 1);
}
static int do_sigframe_return(CPUARMState *env,
target_ulong context_addr,
struct target_ucontext *uc)
@ -482,12 +421,6 @@ static int do_sigframe_return(CPUARMState *env,
return 1;
}
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
regspace = restore_sigframe_iwmmxt(env, regspace);
if (!regspace) {
return 1;
}
}
target_restore_altstack(&uc->tuc_stack, env);

View file

@ -1231,6 +1231,13 @@ SRST
``aw-bits=val`` (val between 32 and 64, default depends on machine)
This decides the address width of the IOVA address space.
``-device arm-smmuv3,primary-bus=id``
This is only supported by ``-machine virt`` (ARM).
``primary-bus=id``
Accepts either the default root complex (pcie.0) or a
pxb-pcie based root complex.
ERST
DEF("name", HAS_ARG, QEMU_OPTION_name,
@ -5347,13 +5354,6 @@ SRST
specified, the former is passed to semihosting as it always
takes precedence.
ERST
DEF("old-param", 0, QEMU_OPTION_old_param,
"-old-param old param mode\n", QEMU_ARCH_ARM)
SRST
``-old-param``
Old param mode (ARM only).
ERST
DEF("sandbox", HAS_ARG, QEMU_OPTION_sandbox, \
"-sandbox on[,obsolete=allow|deny][,elevateprivileges=allow|deny|children]\n" \
" [,spawn=allow|deny][,resourcecontrol=allow|deny]\n" \

View file

@ -17,7 +17,6 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
from __future__ import print_function
from bcc import BPF
from ctypes import c_ushort, c_int, c_ulonglong
from time import sleep

View file

@ -52,7 +52,6 @@ bool vga_interface_created;
Chardev *parallel_hds[MAX_PARALLEL_PORTS];
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int old_param;
const char *qemu_name;
unsigned int nb_prom_envs;
const char *prom_envs[MAX_PROM_ENVS];

View file

@ -3524,10 +3524,6 @@ void qemu_init(int argc, char **argv)
prom_envs[nb_prom_envs] = optarg;
nb_prom_envs++;
break;
case QEMU_OPTION_old_param:
warn_report("-old-param is deprecated");
old_param = 1;
break;
case QEMU_OPTION_rtc:
opts = qemu_opts_parse_noisily(qemu_find_opts("rtc"), optarg,
false);

View file

@ -408,10 +408,19 @@ FIELD(HFGRTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGRTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGRTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGRTR_EL2, NACCDATA_EL1, 50, 1)
/* 51-53: RES0 */
/* 51: RES0 */
FIELD(HFGRTR_EL2, NGCS_EL0, 52, 1)
FIELD(HFGRTR_EL2, NGCS_EL1, 53, 1)
FIELD(HFGRTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGRTR_EL2, NTPIDR2_EL0, 55, 1)
/* 56-63: RES0 */
FIELD(HFGRTR_EL2, NRCWMASK_EL1, 56, 1)
FIELD(HFGRTR_EL2, NPIRE0_EL1, 57, 1)
FIELD(HFGRTR_EL2, NPIR_EL1, 58, 1)
FIELD(HFGRTR_EL2, NPOR_EL0, 59, 1)
FIELD(HFGRTR_EL2, NPOR_EL1, 60, 1)
FIELD(HFGRTR_EL2, NS2POR_EL1, 61, 1)
FIELD(HFGRTR_EL2, NMAIR2_EL1, 62, 1)
FIELD(HFGRTR_EL2, NAMAIR2_EL1, 63, 1)
/* These match HFGRTR but bits for RO registers are RES0 */
FIELD(HFGWTR_EL2, AFSR0_EL1, 0, 1)
@ -452,8 +461,18 @@ FIELD(HFGWTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGWTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGWTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGWTR_EL2, NACCDATA_EL1, 50, 1)
FIELD(HFGWTR_EL2, NGCS_EL0, 52, 1)
FIELD(HFGWTR_EL2, NGCS_EL1, 53, 1)
FIELD(HFGWTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGWTR_EL2, NTPIDR2_EL0, 55, 1)
FIELD(HFGWTR_EL2, NRCWMASK_EL1, 56, 1)
FIELD(HFGWTR_EL2, NPIRE0_EL1, 57, 1)
FIELD(HFGWTR_EL2, NPIR_EL1, 58, 1)
FIELD(HFGWTR_EL2, NPOR_EL0, 59, 1)
FIELD(HFGWTR_EL2, NPOR_EL1, 60, 1)
FIELD(HFGWTR_EL2, NS2POR_EL1, 61, 1)
FIELD(HFGWTR_EL2, NMAIR2_EL1, 62, 1)
FIELD(HFGWTR_EL2, NAMAIR2_EL1, 63, 1)
FIELD(HFGITR_EL2, ICIALLUIS, 0, 1)
FIELD(HFGITR_EL2, ICIALLU, 1, 1)
@ -512,6 +531,11 @@ FIELD(HFGITR_EL2, SVC_EL1, 53, 1)
FIELD(HFGITR_EL2, DCCVAC, 54, 1)
FIELD(HFGITR_EL2, NBRBINJ, 55, 1)
FIELD(HFGITR_EL2, NBRBIALL, 56, 1)
FIELD(HFGITR_EL2, NGCSPUSHM_EL1, 57, 1)
FIELD(HFGITR_EL2, NGCSSTR_EL1, 58, 1)
FIELD(HFGITR_EL2, NGCSEPP, 59, 1)
FIELD(HFGITR_EL2, COSPRCTX, 60, 1)
FIELD(HFGITR_EL2, ATS1E1A, 62, 1)
FIELD(HDFGRTR_EL2, DBGBCRN_EL1, 0, 1)
FIELD(HDFGRTR_EL2, DBGBVRN_EL1, 1, 1)
@ -830,6 +854,7 @@ typedef enum FGTBit {
DO_BIT(HFGITR, DVPRCTX),
DO_BIT(HFGITR, CPPRCTX),
DO_BIT(HFGITR, DCCVAC),
DO_BIT(HFGITR, ATS1E1A),
} FGTBit;
#undef DO_BIT

View file

@ -619,6 +619,11 @@ static inline bool isar_feature_aa64_lut(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64ISAR2, LUT);
}
static inline bool isar_feature_aa64_ats1a(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64ISAR2, ATS1A);
}
static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically. */

View file

@ -247,10 +247,6 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
cpu->power_state = cs->start_powered_off ? PSCI_OFF : PSCI_ON;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
}
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
/* 64 bit CPUs always start in 64 bit mode */
env->aarch64 = true;
@ -349,11 +345,6 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->cp15.c15_cpar = 3;
} else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
env->cp15.c15_cpar = 1;
}
#else
/*
@ -2259,14 +2250,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
}
/*
* We rely on no XScale CPU having VFP so we can use the same bits in the
* TB flags field for VECSTRIDE and XSCALE_CPAR.
*/
assert(arm_feature(env, ARM_FEATURE_AARCH64) ||
!cpu_isar_feature(aa32_vfp_simd, cpu) ||
!arm_feature(env, ARM_FEATURE_XSCALE));
#ifndef CONFIG_USER_ONLY
{
int pagebits;
@ -2623,14 +2606,10 @@ static const Property arm_cpu_properties[] = {
static const gchar *arm_gdb_arch_name(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
if (arm_gdbstub_is_aarch64(cpu)) {
return "aarch64";
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
return "iwmmxt";
}
return "arm";
}

View file

@ -341,7 +341,6 @@ typedef struct CPUArchState {
uint64_t vsctlr; /* Virtualization System control register. */
uint64_t cpacr_el1; /* Architectural feature access control register */
uint64_t cptr_el[4]; /* ARMv8 feature trap registers */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint64_t sder; /* Secure debug enable register. */
uint32_t nsacr; /* Non-secure access control register. */
union { /* MMU translation table base 0. */
@ -513,7 +512,6 @@ typedef struct CPUArchState {
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
uint64_t cntpoff_el2; /* Counter Physical Offset register */
ARMGenericTimer c14_timer[NUM_GTIMERS];
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
uint32_t c15_ticonfig; /* TI925T configuration byte. */
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
@ -699,14 +697,6 @@ typedef struct CPUArchState {
*/
uint64_t exclusive_high;
/* iwMMXt coprocessor state. */
struct {
uint64_t regs[16];
uint64_t val;
uint32_t cregs[16];
} iwmmxt;
struct {
ARMPACKey apia;
ARMPACKey apib;
@ -935,6 +925,7 @@ struct ArchCPU {
DynamicGDBFeatureInfo dyn_sysreg_feature;
DynamicGDBFeatureInfo dyn_svereg_feature;
DynamicGDBFeatureInfo dyn_smereg_feature;
DynamicGDBFeatureInfo dyn_m_systemreg_feature;
DynamicGDBFeatureInfo dyn_m_secextreg_feature;
@ -1865,16 +1856,6 @@ enum arm_cpu_mode {
/* QEMU-internal value meaning "FPSCR, but we care only about NZCV" */
#define QEMU_VFP_FPSCR_NZCV 0xffff
/* iwMMXt coprocessor control registers. */
#define ARM_IWMMXT_wCID 0
#define ARM_IWMMXT_wCon 1
#define ARM_IWMMXT_wCSSF 2
#define ARM_IWMMXT_wCASF 3
#define ARM_IWMMXT_wCGR0 8
#define ARM_IWMMXT_wCGR1 9
#define ARM_IWMMXT_wCGR2 10
#define ARM_IWMMXT_wCGR3 11
/* V7M CCR bits */
FIELD(V7M_CCR, NONBASETHRDENA, 0, 1)
FIELD(V7M_CCR, USERSETMPEND, 1, 1)
@ -2444,8 +2425,6 @@ QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK);
*/
enum arm_features {
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
ARM_FEATURE_V6,
ARM_FEATURE_V6K,
ARM_FEATURE_V7,
@ -3025,13 +3004,6 @@ FIELD(TBFLAG_AM32, THUMB, 23, 1) /* Not cached. */
*/
FIELD(TBFLAG_A32, VECLEN, 0, 3) /* Not cached. */
FIELD(TBFLAG_A32, VECSTRIDE, 3, 2) /* Not cached. */
/*
* We store the bottom two bits of the CPAR as TB flags and handle
* checks on the other bits at runtime. This shares the same bits as
* VECSTRIDE, which is OK as no XScale CPU has VFP.
* Not cached, because VECLEN+VECSTRIDE are not cached.
*/
FIELD(TBFLAG_A32, XSCALE_CPAR, 5, 2)
FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Partially cached, minus FPEXC. */
FIELD(TBFLAG_A32, SCTLR__B, 8, 1) /* Cannot overlap with SCTLR_B */
FIELD(TBFLAG_A32, HSTR_ACTIVE, 9, 1)

View file

@ -527,7 +527,8 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
* registers so we don't need to include both.
*/
#ifdef TARGET_AARCH64
if (isar_feature_aa64_sve(&cpu->isar)) {
if (isar_feature_aa64_sve(&cpu->isar) ||
isar_feature_aa64_sme(&cpu->isar)) {
GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs);
gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
aarch64_gdb_set_sve_reg, feature, 0);
@ -537,6 +538,13 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
gdb_find_static_feature("aarch64-fpu.xml"),
0);
}
if (isar_feature_aa64_sme(&cpu->isar)) {
GDBFeature *sme_feature =
arm_gen_dynamic_smereg_feature(cs, cs->gdb_num_regs);
gdb_register_coprocessor(cs, aarch64_gdb_get_sme_reg,
aarch64_gdb_set_sme_reg, sme_feature, 0);
}
/*
* Note that we report pauth information via the feature name
* org.gnu.gdb.aarch64.pauth_v2, not org.gnu.gdb.aarch64.pauth.

View file

@ -249,6 +249,90 @@ int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
return 0;
}
int aarch64_gdb_get_sme_reg(CPUState *cs, GByteArray *buf, int reg)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
switch (reg) {
case 0: /* svg register */
{
int vq = 0;
if (FIELD_EX64(env->svcr, SVCR, SM)) {
vq = sve_vqm1_for_el_sm(env, arm_current_el(env),
FIELD_EX64(env->svcr, SVCR, SM)) + 1;
}
/* svg = vector granules (2 * vector quardwords) in streaming mode */
return gdb_get_reg64(buf, vq * 2);
}
case 1: /* svcr register */
return gdb_get_reg64(buf, env->svcr);
case 2: /* za register */
{
int len = 0;
int vq = cpu->sme_max_vq;
int svl = vq * 16;
for (int i = 0; i < svl; i++) {
for (int q = 0; q < vq; q++) {
len += gdb_get_reg128(buf,
env->za_state.za[i].d[q * 2 + 1],
env->za_state.za[i].d[q * 2]);
}
}
return len;
}
default:
/* gdbstub asked for something out of range */
qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
break;
}
return 0;
}
int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
switch (reg) {
case 0: /* svg register */
/* cannot set svg via gdbstub */
return 8;
case 1: /* svcr register */
aarch64_set_svcr(env, ldq_le_p(buf),
R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
return 8;
case 2: /* za register */
{
int len = 0;
int vq = cpu->sme_max_vq;
int svl = vq * 16;
for (int i = 0; i < svl; i++) {
for (int q = 0; q < vq; q++) {
if (target_big_endian()) {
env->za_state.za[i].d[q * 2 + 1] = ldq_p(buf);
buf += 8;
env->za_state.za[i].d[q * 2] = ldq_p(buf);
} else{
env->za_state.za[i].d[q * 2] = ldq_p(buf);
buf += 8;
env->za_state.za[i].d[q * 2 + 1] = ldq_p(buf);
}
buf += 8;
len += 16;
}
}
return len;
}
default:
/* gdbstub asked for something out of range */
break;
}
return 0;
}
int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
{
ARMCPU *cpu = ARM_CPU(cs);
@ -413,6 +497,41 @@ GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cs, int base_reg)
return &cpu->dyn_svereg_feature.desc;
}
GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cs, int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
int vq = cpu->sme_max_vq;
int svl = vq * 16;
GDBFeatureBuilder builder;
int reg = 0;
gdb_feature_builder_init(&builder, &cpu->dyn_smereg_feature.desc,
"org.gnu.gdb.aarch64.sme", "sme-registers.xml",
base_reg);
/* Create the sme_bv vector type. */
gdb_feature_builder_append_tag(
&builder, "<vector id=\"sme_bv\" type=\"uint8\" count=\"%d\"/>",
svl);
/* Create the sme_bvv vector type. */
gdb_feature_builder_append_tag(
&builder, "<vector id=\"sme_bvv\" type=\"sme_bv\" count=\"%d\"/>",
svl);
/* Define the svg, svcr, and za registers. */
gdb_feature_builder_append_reg(&builder, "svg", 64, reg++, "int", NULL);
gdb_feature_builder_append_reg(&builder, "svcr", 64, reg++, "int", NULL);
gdb_feature_builder_append_reg(&builder, "za", svl * svl * 8, reg++,
"sme_bvv", NULL);
gdb_feature_builder_end(&builder);
return &cpu->dyn_smereg_feature.desc;
}
#ifdef CONFIG_USER_ONLY
int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
{

View file

@ -2923,39 +2923,6 @@ static const ARMCPRegInfo omap_cp_reginfo[] = {
.type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 },
};
static void xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
env->cp15.c15_cpar = value & 0x3fff;
}
static const ARMCPRegInfo xscale_cp_reginfo[] = {
{ .name = "XSCALE_CPAR",
.cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c15_cpar), .resetvalue = 0,
.writefn = xscale_cpar_write, },
{ .name = "XSCALE_AUXCR",
.cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c1_xscaleauxcr),
.resetvalue = 0, },
/*
* XScale specific cache-lockdown: since we have no cache we NOP these
* and hope the guest does not really rely on cache behaviour.
*/
{ .name = "XSCALE_LOCK_ICACHE_LINE",
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
.access = PL1_W, .type = ARM_CP_NOP },
{ .name = "XSCALE_UNLOCK_ICACHE",
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1,
.access = PL1_W, .type = ARM_CP_NOP },
{ .name = "XSCALE_DCACHE_LOCK",
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "XSCALE_UNLOCK_DCACHE",
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1,
.access = PL1_W, .type = ARM_CP_NOP },
};
static const ARMCPRegInfo dummy_c15_cp_reginfo[] = {
/*
* RAZ/WI the whole crn=15 space, when we don't have a more specific
@ -3346,16 +3313,6 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu));
if (tcg_enabled() && ri->type & ARM_CP_SUPPRESS_TB_END) {
/*
* Normally we would always end the TB on an SCTLR write; see the
* comment in ARMCPRegInfo sctlr initialization below for why Xscale
* is special. Setting ARM_CP_SUPPRESS_TB_END also stops the rebuild
* of hflags from the translator, so do it here.
*/
arm_rebuild_hflags(env);
}
}
static void mdcr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -4563,11 +4520,6 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
{ K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0),
"CNTKCTL", "CNTHCTL_EL2", "CNTKCTL_EL12" },
/*
* Note that redirection of ZCR is mentioned in the description
* of ZCR_EL2, and aliasing in the description of ZCR_EL1, but
* not in the summary table.
*/
{ K(3, 0, 1, 2, 0), K(3, 4, 1, 2, 0), K(3, 5, 1, 2, 0),
"ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve },
{ K(3, 0, 1, 2, 6), K(3, 4, 1, 2, 6), K(3, 5, 1, 2, 6),
@ -6899,9 +6851,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_STRONGARM)) {
define_arm_cp_regs(cpu, strongarm_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
define_arm_cp_regs(cpu, xscale_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) {
define_arm_cp_regs(cpu, dummy_c15_cp_reginfo);
}
@ -7250,14 +7199,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
.raw_writefn = raw_write,
};
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
/*
* Normally we would always end the TB on an SCTLR write, but Linux
* arch/arm/mach-pxa/sleep.S expects two instructions following
* an MMU enable to execute from cache. Imitate this behaviour.
*/
sctlr.type |= ARM_CP_SUPPRESS_TB_END;
}
define_one_arm_cp_reg(cpu, &sctlr);
if (arm_feature(env, ARM_FEATURE_PMSA) &&

View file

@ -1602,30 +1602,27 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
__attribute__((nonnull));
/**
* get_phys_addr_with_space_nogpc: get the physical address for a virtual
* address
* get_phys_addr_for_at:
* @env: CPUARMState
* @address: virtual address to get physical address for
* @access_type: 0 for read, 1 for write, 2 for execute
* @memop: memory operation feeding this access, or 0 for none
* @prot_check: PAGE_{READ,WRITE,EXEC}, or 0
* @mmu_idx: MMU index indicating required translation regime
* @space: security space for the access
* @result: set on translation success.
* @fi: set to fault info if the translation fails
*
* Similar to get_phys_addr, but use the given security space and don't perform
* a Granule Protection Check on the resulting address.
* Similar to get_phys_addr, but for use by AccessType_AT, i.e.
* system instructions for address translation.
*/
bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
MMUAccessType access_type, MemOp memop,
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
bool get_phys_addr_for_at(CPUARMState *env, vaddr address, unsigned prot_check,
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
__attribute__((nonnull));
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
bool is_secure, GetPhysAddrResult *result,
MMUAccessType access_type, unsigned prot_check,
ARMMMUIdx mmu_idx, bool is_secure,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi, uint32_t *mregion);
void arm_log_exception(CPUState *cs);
@ -1820,8 +1817,11 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
}
GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cpu, int base_reg);
GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cpu, int base_reg);
int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg);
int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg);
int aarch64_gdb_get_sme_reg(CPUState *cs, GByteArray *buf, int reg);
int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg);
int aarch64_gdb_get_fpu_reg(CPUState *cs, GByteArray *buf, int reg);
int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg);
int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg);

View file

@ -900,6 +900,58 @@ bool write_kvmstate_to_list(ARMCPU *cpu)
return ok;
}
/* pretty-print a KVM register */
#define CP_REG_ARM64_SYSREG_OP(_reg, _op) \
((uint8_t)((_reg & CP_REG_ARM64_SYSREG_ ## _op ## _MASK) >> \
CP_REG_ARM64_SYSREG_ ## _op ## _SHIFT))
static gchar *kvm_print_sve_register_name(uint64_t regidx)
{
uint16_t sve_reg = regidx & 0x000000000000ffff;
if (regidx == KVM_REG_ARM64_SVE_VLS) {
return g_strdup_printf("SVE VLS");
}
/* zreg, preg, ffr */
switch (sve_reg & 0xfc00) {
case 0:
return g_strdup_printf("SVE zreg n:%d slice:%d",
(sve_reg & 0x03e0) >> 5, sve_reg & 0x001f);
case 0x04:
return g_strdup_printf("SVE preg n:%d slice:%d",
(sve_reg & 0x01e0) >> 5, sve_reg & 0x001f);
case 0x06:
return g_strdup_printf("SVE ffr slice:%d", sve_reg & 0x001f);
default:
return g_strdup_printf("SVE ???");
}
}
static gchar *kvm_print_register_name(uint64_t regidx)
{
switch ((regidx & KVM_REG_ARM_COPROC_MASK)) {
case KVM_REG_ARM_CORE:
return g_strdup_printf("core reg %"PRIx64, regidx);
case KVM_REG_ARM_DEMUX:
return g_strdup_printf("demuxed reg %"PRIx64, regidx);
case KVM_REG_ARM64_SYSREG:
return g_strdup_printf("op0:%d op1:%d crn:%d crm:%d op2:%d",
CP_REG_ARM64_SYSREG_OP(regidx, OP0),
CP_REG_ARM64_SYSREG_OP(regidx, OP1),
CP_REG_ARM64_SYSREG_OP(regidx, CRN),
CP_REG_ARM64_SYSREG_OP(regidx, CRM),
CP_REG_ARM64_SYSREG_OP(regidx, OP2));
case KVM_REG_ARM_FW:
return g_strdup_printf("fw reg %d", (int)(regidx & 0xffff));
case KVM_REG_ARM64_SVE:
return kvm_print_sve_register_name(regidx);
case KVM_REG_ARM_FW_FEAT_BMAP:
return g_strdup_printf("fw feat reg %d", (int)(regidx & 0xffff));
default:
return g_strdup_printf("%"PRIx64, regidx);
}
}
bool write_list_to_kvmstate(ARMCPU *cpu, int level)
{
CPUState *cs = CPU(cpu);
@ -927,11 +979,45 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level)
g_assert_not_reached();
}
if (ret) {
gchar *reg_str = kvm_print_register_name(regidx);
/* We might fail for "unknown register" and also for
* "you tried to set a register which is constant with
* a different value from what it actually contains".
*/
ok = false;
switch (ret) {
case -ENOENT:
error_report("Could not set register %s: unknown to KVM",
reg_str);
break;
case -EINVAL:
if ((regidx & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) {
if (!kvm_get_one_reg(cs, regidx, &v32)) {
error_report("Could not set register %s to %x (is %x)",
reg_str, (uint32_t)cpu->cpreg_values[i],
v32);
} else {
error_report("Could not set register %s to %x",
reg_str, (uint32_t)cpu->cpreg_values[i]);
}
} else /* U64 */ {
uint64_t v64;
if (!kvm_get_one_reg(cs, regidx, &v64)) {
error_report("Could not set register %s to %"PRIx64" (is %"PRIx64")",
reg_str, cpu->cpreg_values[i], v64);
} else {
error_report("Could not set register %s to %"PRIx64,
reg_str, cpu->cpreg_values[i]);
}
}
break;
default:
error_report("Could not set register %s: %s",
reg_str, strerror(-ret));
}
g_free(reg_str);
}
}
return ok;

View file

@ -221,26 +221,6 @@ static const VMStateDescription vmstate_vfp = {
}
};
static bool iwmmxt_needed(void *opaque)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_IWMMXT);
}
static const VMStateDescription vmstate_iwmmxt = {
.name = "cpu/iwmmxt",
.version_id = 1,
.minimum_version_id = 1,
.needed = iwmmxt_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16),
VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16),
VMSTATE_END_OF_LIST()
}
};
/* The expression ARM_MAX_VQ - 2 is 0 for pure AArch32 build,
* and ARMPredicateReg is actively empty. This triggers errors
* in the expansion of the VMSTATE macros.
@ -1102,7 +1082,6 @@ const VMStateDescription vmstate_arm_cpu = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_vfp,
&vmstate_iwmmxt,
&vmstate_m,
&vmstate_thumb2ee,
/* pmsav7_rnr must come before pmsav7 so that we have the

View file

@ -58,12 +58,24 @@ typedef struct S1Translate {
* and will not change the state of the softmmu TLBs.
*/
bool in_debug;
/*
* in_at: is this AccessType_AT?
* This is also set for debug, because at heart that is also
* an address translation, and simplifies a test.
*/
bool in_at;
/*
* If this is stage 2 of a stage 1+2 page table walk, then this must
* be true if stage 1 is an EL0 access; otherwise this is ignored.
* Stage 2 is indicated by in_mmu_idx set to ARMMMUIdx_Stage2{,_S}.
*/
bool in_s1_is_el0;
/*
* The set of PAGE_* bits to be use in the permission check.
* This is normally directly related to the access_type, but
* may be suppressed for debug or AT insns.
*/
uint8_t in_prot_check;
bool out_rw;
bool out_be;
ARMSecuritySpace out_space;
@ -581,6 +593,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
.in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx),
.in_space = s2_space,
.in_debug = true,
.in_prot_check = PAGE_READ,
};
GetPhysAddrResult s2 = { };
@ -1061,11 +1074,10 @@ static bool get_phys_addr_v5(CPUARMState *env, S1Translate *ptw,
ap = (desc >> (4 + ((address >> 9) & 6))) & 3;
result->f.lg_page_size = 12;
break;
case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */
case 3: /* 1k page, or ARMv6 "extended small (4k) page" */
if (type == 1) {
/* ARMv6/XScale extended small page format */
if (arm_feature(env, ARM_FEATURE_XSCALE)
|| arm_feature(env, ARM_FEATURE_V6)) {
/* ARMv6 extended small page format */
if (arm_feature(env, ARM_FEATURE_V6)) {
phys_addr = (desc & 0xfffff000) | (address & 0xfff);
result->f.lg_page_size = 12;
} else {
@ -1089,7 +1101,7 @@ static bool get_phys_addr_v5(CPUARMState *env, S1Translate *ptw,
}
result->f.prot = ap_to_rw_prot(env, ptw->in_mmu_idx, ap, domain_prot);
result->f.prot |= result->f.prot ? PAGE_EXEC : 0;
if (!(result->f.prot & (1 << access_type))) {
if (ptw->in_prot_check & ~result->f.prot) {
/* Access permission fault. */
fi->type = ARMFault_Permission;
goto do_fault;
@ -1243,7 +1255,7 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw,
result->f.prot = get_S1prot(env, mmu_idx, false, user_rw, prot_rw,
xn, pxn, result->f.attrs.space, out_space);
if (!(result->f.prot & (1 << access_type))) {
if (ptw->in_prot_check & ~result->f.prot) {
/* Access permission fault. */
fi->type = ARMFault_Permission;
goto do_fault;
@ -1922,7 +1934,12 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
descaddr &= ~(hwaddr)(page_size - 1);
descaddr |= (address & (page_size - 1));
if (likely(!ptw->in_debug)) {
/*
* For AccessType_AT, DB is not updated (AArch64.SetDirtyFlag),
* and it is IMPLEMENTATION DEFINED whether AF is updated
* (AArch64.SetAccessFlag; qemu chooses to not update).
*/
if (likely(!ptw->in_at)) {
/*
* Access flag.
* If HA is enabled, prepare to update the descriptor below.
@ -2123,7 +2140,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
result->f.tlb_fill_flags = 0;
}
if (!(result->f.prot & (1 << access_type))) {
if (ptw->in_prot_check & ~result->f.prot) {
fi->type = ARMFault_Permission;
goto do_fault;
}
@ -2537,7 +2554,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env,
fi->type = ARMFault_Permission;
fi->level = 1;
return !(result->f.prot & (1 << access_type));
return (ptw->in_prot_check & ~result->f.prot) != 0;
}
static uint32_t *regime_rbar(CPUARMState *env, ARMMMUIdx mmu_idx,
@ -2561,8 +2578,9 @@ static uint32_t *regime_rlar(CPUARMState *env, ARMMMUIdx mmu_idx,
}
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
bool secure, GetPhysAddrResult *result,
MMUAccessType access_type, unsigned prot_check,
ARMMMUIdx mmu_idx, bool secure,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi, uint32_t *mregion)
{
/*
@ -2750,7 +2768,7 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
if (arm_feature(env, ARM_FEATURE_M)) {
fi->level = 1;
}
return !(result->f.prot & (1 << access_type));
return (prot_check & ~result->f.prot) != 0;
}
static bool v8m_is_sau_exempt(CPUARMState *env,
@ -2952,8 +2970,8 @@ static bool get_phys_addr_pmsav8(CPUARMState *env,
}
}
ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, secure,
result, fi, NULL);
ret = pmsav8_mpu_lookup(env, address, access_type, ptw->in_prot_check,
mmu_idx, secure, result, fi, NULL);
if (sattrs.subpage) {
result->f.lg_page_size = 0;
}
@ -3537,18 +3555,26 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
return false;
}
bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
MMUAccessType access_type, MemOp memop,
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
bool get_phys_addr_for_at(CPUARMState *env, vaddr address,
unsigned prot_check, ARMMMUIdx mmu_idx,
ARMSecuritySpace space, GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
{
S1Translate ptw = {
.in_mmu_idx = mmu_idx,
.in_space = space,
.in_at = true,
.in_prot_check = prot_check,
};
return get_phys_addr_nogpc(env, &ptw, address, access_type,
memop, result, fi);
/*
* I_MXTJT: Granule protection checks are not performed on the final
* address of a successful translation. This is a translation not a
* memory reference, so MMU_DATA_LOAD is arbitrary (the exact protection
* check is handled or bypassed by .in_prot_check) and "memop = MO_8"
* bypasses any alignment check.
*/
return get_phys_addr_nogpc(env, &ptw, address,
MMU_DATA_LOAD, MO_8, result, fi);
}
static ARMSecuritySpace
@ -3624,6 +3650,7 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
S1Translate ptw = {
.in_mmu_idx = mmu_idx,
.in_space = arm_mmu_idx_to_security_space(env, mmu_idx),
.in_prot_check = 1 << access_type,
};
return get_phys_addr_gpc(env, &ptw, address, access_type,
@ -3637,6 +3664,8 @@ static hwaddr arm_cpu_get_phys_page(CPUARMState *env, vaddr addr,
.in_mmu_idx = mmu_idx,
.in_space = arm_mmu_idx_to_security_space(env, mmu_idx),
.in_debug = true,
.in_at = true,
.in_prot_check = 0,
};
GetPhysAddrResult res = {};
ARMMMUFaultInfo fi = {};

View file

@ -24,22 +24,15 @@ static int par_el1_shareability(GetPhysAddrResult *res)
}
static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
unsigned prot_check, ARMMMUIdx mmu_idx,
ARMSecuritySpace ss)
{
bool ret;
uint64_t par64;
bool format64 = false;
ARMMMUFaultInfo fi = {};
GetPhysAddrResult res = {};
/*
* I_MXTJT: Granule protection checks are not performed on the final
* address of a successful translation. This is a translation not a
* memory reference, so "memop = none = 0".
*/
ret = get_phys_addr_with_space_nogpc(env, value, access_type, 0,
mmu_idx, ss, &res, &fi);
bool ret = get_phys_addr_for_at(env, value, prot_check,
mmu_idx, ss, &res, &fi);
/*
* ATS operations only do S1 or S1+S2 translations, so we never
@ -198,7 +191,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
unsigned access_perm = ri->opc2 & 1 ? PAGE_WRITE : PAGE_READ;
uint64_t par64;
ARMMMUIdx mmu_idx;
int el = arm_current_el(env);
@ -260,7 +253,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
g_assert_not_reached();
}
par64 = do_ats_write(env, value, access_type, mmu_idx, ss);
par64 = do_ats_write(env, value, access_perm, mmu_idx, ss);
A32_BANKED_CURRENT_REG_SET(env, par, par64);
}
@ -268,11 +261,11 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
unsigned access_perm = ri->opc2 & 1 ? PAGE_WRITE : PAGE_READ;
uint64_t par64;
/* There is no SecureEL2 for AArch32. */
par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2,
par64 = do_ats_write(env, value, access_perm, ARMMMUIdx_E2,
ARMSS_NonSecure);
A32_BANKED_CURRENT_REG_SET(env, par, par64);
@ -316,7 +309,7 @@ static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo *ri,
static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
unsigned access_perm = ri->opc2 & 1 ? PAGE_WRITE : PAGE_READ;
ARMMMUIdx mmu_idx;
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
@ -359,7 +352,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
}
ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env);
env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss);
env->cp15.par_el[1] = do_ats_write(env, value, access_perm, mmu_idx, ss);
}
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
@ -495,6 +488,47 @@ static const ARMCPRegInfo ats1cp_reginfo[] = {
.writefn = ats_write },
};
static void ats_s1e1a(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
ARMMMUIdx mmu_idx = regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_Stage1_E1;
ARMSecuritySpace ss = arm_security_space_below_el3(env);
env->cp15.par_el[1] = do_ats_write(env, value, 0, mmu_idx, ss);
}
static void ats_s1e2a(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
ARMMMUIdx mmu_idx = hcr_el2 & HCR_E2H ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2;
ARMSecuritySpace ss = arm_security_space_below_el3(env);
env->cp15.par_el[1] = do_ats_write(env, value, 0, mmu_idx, ss);
}
static void ats_s1e3a(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
env->cp15.par_el[1] = do_ats_write(env, value, 0, ARMMMUIdx_E3,
arm_security_space(env));
}
static const ARMCPRegInfo ats1a_reginfo[] = {
{ .name = "AT_S1E1A", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 2,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E1A,
.accessfn = at_s1e01_access, .writefn = ats_s1e1a },
{ .name = "AT_S1E2A", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 9, .opc2 = 2,
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.accessfn = at_s1e2_access, .writefn = ats_s1e2a },
{ .name = "AT_S1E3A", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 9, .opc2 = 2,
.access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.writefn = ats_s1e3a },
};
void define_at_insn_regs(ARMCPU *cpu)
{
CPUARMState *env = &cpu->env;
@ -516,4 +550,7 @@ void define_at_insn_regs(ARMCPU *cpu)
if (cpu_isar_feature(aa32_ats1e1, cpu)) {
define_arm_cp_regs(cpu, ats1cp_reginfo);
}
if (cpu_isar_feature(aa64_ats1a, cpu)) {
define_arm_cp_regs(cpu, ats1a_reginfo);
}
}

View file

@ -807,144 +807,6 @@ static void sa1110_initfn(Object *obj)
cpu->reset_sctlr = 0x00000070;
}
static void pxa250_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = 0x69052100;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa255_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = 0x69052d00;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa260_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = 0x69052903;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa261_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = 0x69052d05;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa262_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = 0x69052d06;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270a0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054110;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270a1_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054111;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270b0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054112;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270b1_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054113;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270c0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054114;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
static void pxa270c5_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "marvell,xscale";
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = 0x69054117;
cpu->ctr = 0xd172172;
cpu->reset_sctlr = 0x00000078;
}
#ifndef TARGET_AARCH64
/*
* -cpu max: a CPU with as many features enabled as our emulation supports.
@ -1032,31 +894,6 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
{ .name = "ti925t", .initfn = ti925t_initfn },
{ .name = "sa1100", .initfn = sa1100_initfn },
{ .name = "sa1110", .initfn = sa1110_initfn },
{ .name = "pxa250", .initfn = pxa250_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa255", .initfn = pxa255_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa260", .initfn = pxa260_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa261", .initfn = pxa261_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa262", .initfn = pxa262_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
/* "pxa270" is an alias for "pxa270-a0" */
{ .name = "pxa270", .initfn = pxa270a0_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-a0", .initfn = pxa270a0_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-a1", .initfn = pxa270a1_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-b0", .initfn = pxa270b0_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-b1", .initfn = pxa270b1_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-c0", .initfn = pxa270c0_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
{ .name = "pxa270-c5", .initfn = pxa270c5_initfn,
.deprecation_note = "iwMMXt CPUs are no longer supported", },
#ifndef TARGET_AARCH64
{ .name = "max", .initfn = arm_max_initfn },
#endif

View file

@ -1179,6 +1179,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */
t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* FEAT_WFxT */
t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 1); /* FEAT_CSSC */
t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* FEAT_ATS1A */
SET_IDREG(isar, ID_AA64ISAR2, t);
t = GET_IDREG(isar, ID_AA64PFR0);

View file

@ -444,101 +444,6 @@ DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, fpst)
DEF_HELPER_3(neon_acge_f64, i64, i64, i64, fpst)
DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, fpst)
/* iwmmxt_helper.c */
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64)
DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64)
DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64)
DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64)
DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64)
#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \
DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \
DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \
DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \
DEF_IWMMXT_HELPER_SIZE_ENV(unpackl)
DEF_IWMMXT_HELPER_SIZE_ENV(unpackh)
DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64)
DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64)
DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq)
DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu)
DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts)
DEF_IWMMXT_HELPER_SIZE_ENV(mins)
DEF_IWMMXT_HELPER_SIZE_ENV(minu)
DEF_IWMMXT_HELPER_SIZE_ENV(maxs)
DEF_IWMMXT_HELPER_SIZE_ENV(maxu)
DEF_IWMMXT_HELPER_SIZE_ENV(subn)
DEF_IWMMXT_HELPER_SIZE_ENV(addn)
DEF_IWMMXT_HELPER_SIZE_ENV(subu)
DEF_IWMMXT_HELPER_SIZE_ENV(addu)
DEF_IWMMXT_HELPER_SIZE_ENV(subs)
DEF_IWMMXT_HELPER_SIZE_ENV(adds)
DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32)
DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32)
DEF_HELPER_1(iwmmxt_bcstb, i64, i32)
DEF_HELPER_1(iwmmxt_bcstw, i64, i32)
DEF_HELPER_1(iwmmxt_bcstl, i64, i32)
DEF_HELPER_1(iwmmxt_addcb, i64, i64)
DEF_HELPER_1(iwmmxt_addcw, i64, i64)
DEF_HELPER_1(iwmmxt_addcl, i64, i64)
DEF_HELPER_1(iwmmxt_msbb, i32, i64)
DEF_HELPER_1(iwmmxt_msbw, i32, i64)
DEF_HELPER_1(iwmmxt_msbl, i32, i64)
DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32)
DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64)
DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
DEF_HELPER_FLAGS_2(neon_unzip8, TCG_CALL_NO_RWG, void, ptr, ptr)
DEF_HELPER_FLAGS_2(neon_unzip16, TCG_CALL_NO_RWG, void, ptr, ptr)
DEF_HELPER_FLAGS_2(neon_qunzip8, TCG_CALL_NO_RWG, void, ptr, ptr)

View file

@ -624,16 +624,9 @@ TCGTBCPUState arm_get_tb_cpu_state(CPUState *cs)
DP_TBFLAG_M32(flags, MVE_NO_PRED, 1);
}
} else {
/*
* Note that XSCALE_CPAR shares bits with VECSTRIDE.
* Note that VECLEN+VECSTRIDE are RES0 for M-profile.
*/
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
DP_TBFLAG_A32(flags, XSCALE_CPAR, env->cp15.c15_cpar);
} else {
DP_TBFLAG_A32(flags, VECLEN, env->vfp.vec_len);
DP_TBFLAG_A32(flags, VECSTRIDE, env->vfp.vec_stride);
}
/* Note that VECLEN+VECSTRIDE are RES0 for M-profile. */
DP_TBFLAG_A32(flags, VECLEN, env->vfp.vec_len);
DP_TBFLAG_A32(flags, VECSTRIDE, env->vfp.vec_stride);
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
DP_TBFLAG_A32(flags, VFPEN, 1);
}

View file

@ -1,672 +0,0 @@
/*
* iwMMXt micro operations for XScale.
*
* Copyright (c) 2007 OpenedHand, Ltd.
* Written by Andrzej Zaborowski <andrew@openedhand.com>
* Copyright (c) 2008 CodeSourcery
*
* 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.1 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/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#define HELPER_H "tcg/helper.h"
#include "exec/helper-proto.h.inc"
/* iwMMXt macros extracted from GNU gdb. */
/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */
#define SIMD8_SET(v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n)))
#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n)))
#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n)))
#define SIMD64_SET(v, n) ((v != 0) << (32 + (n)))
/* Flags to pass as "n" above. */
#define SIMD_NBIT -1
#define SIMD_ZBIT -2
#define SIMD_CBIT -3
#define SIMD_VBIT -4
/* Various status bit macros. */
#define NBIT8(x) ((x) & 0x80)
#define NBIT16(x) ((x) & 0x8000)
#define NBIT32(x) ((x) & 0x80000000)
#define NBIT64(x) ((x) & 0x8000000000000000ULL)
#define ZBIT8(x) (((x) & 0xff) == 0)
#define ZBIT16(x) (((x) & 0xffff) == 0)
#define ZBIT32(x) (((x) & 0xffffffff) == 0)
#define ZBIT64(x) (x == 0)
/* Sign extension macros. */
#define EXTEND8H(a) ((uint16_t) (int8_t) (a))
#define EXTEND8(a) ((uint32_t) (int8_t) (a))
#define EXTEND16(a) ((uint32_t) (int16_t) (a))
#define EXTEND16S(a) ((int32_t) (int16_t) (a))
#define EXTEND32(a) ((uint64_t) (int32_t) (a))
uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b)
{
a = ((
EXTEND16S((a >> 0) & 0xffff) * EXTEND16S((b >> 0) & 0xffff) +
EXTEND16S((a >> 16) & 0xffff) * EXTEND16S((b >> 16) & 0xffff)
) & 0xffffffff) | ((uint64_t) (
EXTEND16S((a >> 32) & 0xffff) * EXTEND16S((b >> 32) & 0xffff) +
EXTEND16S((a >> 48) & 0xffff) * EXTEND16S((b >> 48) & 0xffff)
) << 32);
return a;
}
uint64_t HELPER(iwmmxt_madduq)(uint64_t a, uint64_t b)
{
a = ((
((a >> 0) & 0xffff) * ((b >> 0) & 0xffff) +
((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)
) & 0xffffffff) | ((
((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) +
((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)
) << 32);
return a;
}
uint64_t HELPER(iwmmxt_sadb)(uint64_t a, uint64_t b)
{
#define abs(x) (((x) >= 0) ? x : -x)
#define SADB(SHR) abs((int) ((a >> SHR) & 0xff) - (int) ((b >> SHR) & 0xff))
return
SADB(0) + SADB(8) + SADB(16) + SADB(24) +
SADB(32) + SADB(40) + SADB(48) + SADB(56);
#undef SADB
}
uint64_t HELPER(iwmmxt_sadw)(uint64_t a, uint64_t b)
{
#define SADW(SHR) \
abs((int) ((a >> SHR) & 0xffff) - (int) ((b >> SHR) & 0xffff))
return SADW(0) + SADW(16) + SADW(32) + SADW(48);
#undef SADW
}
uint64_t HELPER(iwmmxt_mulslw)(uint64_t a, uint64_t b)
{
#define MULS(SHR) ((uint64_t) ((( \
EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \
) >> 0) & 0xffff) << SHR)
return MULS(0) | MULS(16) | MULS(32) | MULS(48);
#undef MULS
}
uint64_t HELPER(iwmmxt_mulshw)(uint64_t a, uint64_t b)
{
#define MULS(SHR) ((uint64_t) ((( \
EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \
) >> 16) & 0xffff) << SHR)
return MULS(0) | MULS(16) | MULS(32) | MULS(48);
#undef MULS
}
uint64_t HELPER(iwmmxt_mululw)(uint64_t a, uint64_t b)
{
#define MULU(SHR) ((uint64_t) ((( \
((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \
) >> 0) & 0xffff) << SHR)
return MULU(0) | MULU(16) | MULU(32) | MULU(48);
#undef MULU
}
uint64_t HELPER(iwmmxt_muluhw)(uint64_t a, uint64_t b)
{
#define MULU(SHR) ((uint64_t) ((( \
((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \
) >> 16) & 0xffff) << SHR)
return MULU(0) | MULU(16) | MULU(32) | MULU(48);
#undef MULU
}
uint64_t HELPER(iwmmxt_macsw)(uint64_t a, uint64_t b)
{
#define MACS(SHR) ( \
EXTEND16((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff))
return (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48));
#undef MACS
}
uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b)
{
#define MACU(SHR) ( \
(uint32_t) ((a >> SHR) & 0xffff) * \
(uint32_t) ((b >> SHR) & 0xffff))
return MACU(0) + MACU(16) + MACU(32) + MACU(48);
#undef MACU
}
#define NZBIT8(x, i) \
SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \
SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i)
#define NZBIT16(x, i) \
SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \
SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i)
#define NZBIT32(x, i) \
SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \
SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i)
#define NZBIT64(x) \
SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = \
(((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \
(((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \
(((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \
(((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
return a; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = \
(((a >> SH0) & 0xffff) << 0) | \
(((b >> SH0) & 0xffff) << 16) | \
(((a >> SH2) & 0xffff) << 32) | \
(((b >> SH2) & 0xffff) << 48); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \
NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \
return a; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = \
(((a >> SH0) & 0xffffffff) << 0) | \
(((b >> SH0) & 0xffffffff) << 32); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
return a; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUARMState *env, \
uint64_t x) \
{ \
x = \
(((x >> SH0) & 0xff) << 0) | \
(((x >> SH1) & 0xff) << 16) | \
(((x >> SH2) & 0xff) << 32) | \
(((x >> SH3) & 0xff) << 48); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
return x; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUARMState *env, \
uint64_t x) \
{ \
x = \
(((x >> SH0) & 0xffff) << 0) | \
(((x >> SH2) & 0xffff) << 32); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
return x; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUARMState *env, \
uint64_t x) \
{ \
x = (((x >> SH0) & 0xffffffff) << 0); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
return x; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUARMState *env, \
uint64_t x) \
{ \
x = \
((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \
((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \
((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \
((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
return x; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUARMState *env, \
uint64_t x) \
{ \
x = \
((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \
((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
return x; \
} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUARMState *env, \
uint64_t x) \
{ \
x = EXTEND32((x >> SH0) & 0xffffffff); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
return x; \
}
IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = \
CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \
CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \
CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \
CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
return a; \
} \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \
CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \
NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \
return a; \
} \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
{ \
a = CMP(0, Tl, O, 0xffffffff) | \
CMP(32, Tl, O, 0xffffffff); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
return a; \
}
#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
(TYPE) ((b >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR)
IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==)
IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >)
IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >)
#undef CMP
#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
(TYPE) ((b >> SHR) & MASK)) ? a : b) & ((uint64_t) MASK << SHR))
IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <)
IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <)
IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >)
IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >)
#undef CMP
#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \
OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR)
IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -)
IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +)
#undef CMP
/* TODO Signed- and Unsigned-Saturation */
#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \
OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR)
IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -)
IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +)
IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -)
IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +)
#undef CMP
#undef IWMMXT_OP_CMP
#define AVGB(SHR) ((( \
((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR)
#define IWMMXT_OP_AVGB(r) \
uint64_t HELPER(iwmmxt_avgb##r)(CPUARMState *env, uint64_t a, uint64_t b) \
{ \
const int round = r; \
a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | \
AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
SIMD8_SET(ZBIT8((a >> 0) & 0xff), SIMD_ZBIT, 0) | \
SIMD8_SET(ZBIT8((a >> 8) & 0xff), SIMD_ZBIT, 1) | \
SIMD8_SET(ZBIT8((a >> 16) & 0xff), SIMD_ZBIT, 2) | \
SIMD8_SET(ZBIT8((a >> 24) & 0xff), SIMD_ZBIT, 3) | \
SIMD8_SET(ZBIT8((a >> 32) & 0xff), SIMD_ZBIT, 4) | \
SIMD8_SET(ZBIT8((a >> 40) & 0xff), SIMD_ZBIT, 5) | \
SIMD8_SET(ZBIT8((a >> 48) & 0xff), SIMD_ZBIT, 6) | \
SIMD8_SET(ZBIT8((a >> 56) & 0xff), SIMD_ZBIT, 7); \
return a; \
}
IWMMXT_OP_AVGB(0)
IWMMXT_OP_AVGB(1)
#undef IWMMXT_OP_AVGB
#undef AVGB
#define AVGW(SHR) ((( \
((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR)
#define IWMMXT_OP_AVGW(r) \
uint64_t HELPER(iwmmxt_avgw##r)(CPUARMState *env, uint64_t a, uint64_t b) \
{ \
const int round = r; \
a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); \
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
SIMD16_SET(ZBIT16((a >> 0) & 0xffff), SIMD_ZBIT, 0) | \
SIMD16_SET(ZBIT16((a >> 16) & 0xffff), SIMD_ZBIT, 1) | \
SIMD16_SET(ZBIT16((a >> 32) & 0xffff), SIMD_ZBIT, 2) | \
SIMD16_SET(ZBIT16((a >> 48) & 0xffff), SIMD_ZBIT, 3); \
return a; \
}
IWMMXT_OP_AVGW(0)
IWMMXT_OP_AVGW(1)
#undef IWMMXT_OP_AVGW
#undef AVGW
uint64_t HELPER(iwmmxt_align)(uint64_t a, uint64_t b, uint32_t n)
{
a >>= n << 3;
a |= b << (64 - (n << 3));
return a;
}
uint64_t HELPER(iwmmxt_insr)(uint64_t x, uint32_t a, uint32_t b, uint32_t n)
{
x &= ~((uint64_t) b << n);
x |= (uint64_t) (a & b) << n;
return x;
}
uint32_t HELPER(iwmmxt_setpsr_nz)(uint64_t x)
{
return SIMD64_SET((x == 0), SIMD_ZBIT) |
SIMD64_SET((x & (1ULL << 63)), SIMD_NBIT);
}
uint64_t HELPER(iwmmxt_bcstb)(uint32_t arg)
{
arg &= 0xff;
return
((uint64_t) arg << 0 ) | ((uint64_t) arg << 8 ) |
((uint64_t) arg << 16) | ((uint64_t) arg << 24) |
((uint64_t) arg << 32) | ((uint64_t) arg << 40) |
((uint64_t) arg << 48) | ((uint64_t) arg << 56);
}
uint64_t HELPER(iwmmxt_bcstw)(uint32_t arg)
{
arg &= 0xffff;
return
((uint64_t) arg << 0 ) | ((uint64_t) arg << 16) |
((uint64_t) arg << 32) | ((uint64_t) arg << 48);
}
uint64_t HELPER(iwmmxt_bcstl)(uint32_t arg)
{
return arg | ((uint64_t) arg << 32);
}
uint64_t HELPER(iwmmxt_addcb)(uint64_t x)
{
return
((x >> 0) & 0xff) + ((x >> 8) & 0xff) +
((x >> 16) & 0xff) + ((x >> 24) & 0xff) +
((x >> 32) & 0xff) + ((x >> 40) & 0xff) +
((x >> 48) & 0xff) + ((x >> 56) & 0xff);
}
uint64_t HELPER(iwmmxt_addcw)(uint64_t x)
{
return
((x >> 0) & 0xffff) + ((x >> 16) & 0xffff) +
((x >> 32) & 0xffff) + ((x >> 48) & 0xffff);
}
uint64_t HELPER(iwmmxt_addcl)(uint64_t x)
{
return (x & 0xffffffff) + (x >> 32);
}
uint32_t HELPER(iwmmxt_msbb)(uint64_t x)
{
return
((x >> 7) & 0x01) | ((x >> 14) & 0x02) |
((x >> 21) & 0x04) | ((x >> 28) & 0x08) |
((x >> 35) & 0x10) | ((x >> 42) & 0x20) |
((x >> 49) & 0x40) | ((x >> 56) & 0x80);
}
uint32_t HELPER(iwmmxt_msbw)(uint64_t x)
{
return
((x >> 15) & 0x01) | ((x >> 30) & 0x02) |
((x >> 45) & 0x04) | ((x >> 52) & 0x08);
}
uint32_t HELPER(iwmmxt_msbl)(uint64_t x)
{
return ((x >> 31) & 0x01) | ((x >> 62) & 0x02);
}
/* FIXME: Split wCASF setting into a separate op to avoid env use. */
uint64_t HELPER(iwmmxt_srlw)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) |
(((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) |
(((x & (0xffffll << 32)) >> n) & (0xffffll << 32)) |
(((x & (0xffffll << 48)) >> n) & (0xffffll << 48));
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
return x;
}
uint64_t HELPER(iwmmxt_srll)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ((x & (0xffffffffll << 0)) >> n) |
((x >> n) & (0xffffffffll << 32));
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
return x;
}
uint64_t HELPER(iwmmxt_srlq)(CPUARMState *env, uint64_t x, uint32_t n)
{
x >>= n;
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
return x;
}
uint64_t HELPER(iwmmxt_sllw)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) |
(((x & (0xffffll << 16)) << n) & (0xffffll << 16)) |
(((x & (0xffffll << 32)) << n) & (0xffffll << 32)) |
(((x & (0xffffll << 48)) << n) & (0xffffll << 48));
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
return x;
}
uint64_t HELPER(iwmmxt_slll)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ((x << n) & (0xffffffffll << 0)) |
((x & (0xffffffffll << 32)) << n);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
return x;
}
uint64_t HELPER(iwmmxt_sllq)(CPUARMState *env, uint64_t x, uint32_t n)
{
x <<= n;
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
return x;
}
uint64_t HELPER(iwmmxt_sraw)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) |
((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) |
((uint64_t) ((EXTEND16(x >> 32) >> n) & 0xffff) << 32) |
((uint64_t) ((EXTEND16(x >> 48) >> n) & 0xffff) << 48);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
return x;
}
uint64_t HELPER(iwmmxt_sral)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) |
(((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
return x;
}
uint64_t HELPER(iwmmxt_sraq)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = (int64_t) x >> n;
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
return x;
}
uint64_t HELPER(iwmmxt_rorw)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ((((x & (0xffffll << 0)) >> n) |
((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) |
((((x & (0xffffll << 16)) >> n) |
((x & (0xffffll << 16)) << (16 - n))) & (0xffffll << 16)) |
((((x & (0xffffll << 32)) >> n) |
((x & (0xffffll << 32)) << (16 - n))) & (0xffffll << 32)) |
((((x & (0xffffll << 48)) >> n) |
((x & (0xffffll << 48)) << (16 - n))) & (0xffffll << 48));
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
return x;
}
uint64_t HELPER(iwmmxt_rorl)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ((x & (0xffffffffll << 0)) >> n) |
((x >> n) & (0xffffffffll << 32)) |
((x << (32 - n)) & (0xffffffffll << 0)) |
((x & (0xffffffffll << 32)) << (32 - n));
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
return x;
}
uint64_t HELPER(iwmmxt_rorq)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = ror64(x, n);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
return x;
}
uint64_t HELPER(iwmmxt_shufh)(CPUARMState *env, uint64_t x, uint32_t n)
{
x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) |
(((x >> ((n << 2) & 0x30)) & 0xffff) << 16) |
(((x >> ((n << 0) & 0x30)) & 0xffff) << 32) |
(((x >> ((n >> 2) & 0x30)) & 0xffff) << 48);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
return x;
}
/* TODO: Unsigned-Saturation */
uint64_t HELPER(iwmmxt_packuw)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
(((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
(((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) |
(((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |
NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |
NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |
NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);
return a;
}
uint64_t HELPER(iwmmxt_packul)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
(((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |
NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);
return a;
}
uint64_t HELPER(iwmmxt_packuq)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);
return a;
}
/* TODO: Signed-Saturation */
uint64_t HELPER(iwmmxt_packsw)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
(((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
(((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) |
(((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |
NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |
NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |
NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);
return a;
}
uint64_t HELPER(iwmmxt_packsl)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
(((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |
NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);
return a;
}
uint64_t HELPER(iwmmxt_packsq)(CPUARMState *env, uint64_t a, uint64_t b)
{
a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);
return a;
}
uint64_t HELPER(iwmmxt_muladdsl)(uint64_t c, uint32_t a, uint32_t b)
{
return c + ((int32_t) EXTEND32(a) * (int32_t) EXTEND32(b));
}
uint64_t HELPER(iwmmxt_muladdsw)(uint64_t c, uint32_t a, uint32_t b)
{
c += EXTEND32(EXTEND16S((a >> 0) & 0xffff) *
EXTEND16S((b >> 0) & 0xffff));
c += EXTEND32(EXTEND16S((a >> 16) & 0xffff) *
EXTEND16S((b >> 16) & 0xffff));
return c;
}
uint64_t HELPER(iwmmxt_muladdswl)(uint64_t c, uint32_t a, uint32_t b)
{
return c + (EXTEND32(EXTEND16S(a & 0xffff) *
EXTEND16S(b & 0xffff)));
}

View file

@ -2829,8 +2829,8 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
ARMMMUFaultInfo fi = {};
/* We can ignore the return value as prot is always set */
pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, targetsec,
&res, &fi, &mregion);
pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, PAGE_READ, mmu_idx,
targetsec, &res, &fi, &mregion);
if (mregion == -1) {
mrvalid = false;
mregion = 0;

View file

@ -66,7 +66,6 @@ arm_common_ss.add(files(
arm_common_system_ss.add(files(
'cpregs-at.c',
'hflags.c',
'iwmmxt_helper.c',
'neon_helper.c',
'tlb_helper.c',
'tlb-insns.c',
@ -74,7 +73,6 @@ arm_common_system_ss.add(files(
))
arm_user_ss.add(files(
'hflags.c',
'iwmmxt_helper.c',
'neon_helper.c',
'tlb_helper.c',
'vfp_helper.c',

View file

@ -768,12 +768,6 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
assert(ri != NULL);
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
res = CP_ACCESS_UNDEFINED;
goto fail;
}
if (ri->accessfn) {
res = ri->accessfn(env, ri, isread);
}

File diff suppressed because it is too large Load diff

View file

@ -175,8 +175,6 @@ typedef struct DisasContext {
uint8_t gm_blocksize;
/* True if the current insn_start has been updated. */
bool insn_start_updated;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar;
/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
uint32_t nv2_redirect_offset;
} DisasContext;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,7 +1,6 @@
"""Helper functions for gdbstub testing
"""
from __future__ import print_function
import argparse
import gdb
import os

View file

@ -2337,6 +2337,86 @@ static void test_acpi_aarch64_virt_viot(void)
free_test_data(&data);
}
static void test_acpi_aarch64_virt_smmuv3_legacy(void)
{
test_data data = {
.machine = "virt",
.arch = "aarch64",
.tcg_only = true,
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
.ram_start = 0x40000000ULL,
.scan_len = 128ULL * MiB,
};
/*
* cdrom is plugged into scsi controller to avoid conflict
* with pxb-pcie. See comments in test_acpi_aarch64_virt_tcg_pxb() for
* details.
*
* The setup includes three PCIe root complexes, one of which has
* bypass_iommu enabled. The generated IORT table contains a single
* SMMUv3 node and a Root Complex node with three ID mappings. Two
* of the ID mappings have output references pointing to the SMMUv3
* node and the remaining one points to ITS.
*/
data.variant = ".smmuv3-legacy";
test_acpi_one(" -device pcie-root-port,chassis=1,id=pci.1"
" -device virtio-scsi-pci,id=scsi0,bus=pci.1"
" -drive file="
"tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2,"
"if=none,media=cdrom,id=drive-scsi0-0-0-1,readonly=on"
" -device scsi-cd,bus=scsi0.0,scsi-id=0,"
"drive=drive-scsi0-0-0-1,id=scsi0-0-0-1,bootindex=1"
" -cpu cortex-a57"
" -M iommu=smmuv3"
" -device pxb-pcie,id=pcie.1,bus=pcie.0,bus_nr=0x10"
" -device pxb-pcie,id=pcie.2,bus=pcie.0,bus_nr=0x20,bypass_iommu=on",
&data);
free_test_data(&data);
}
static void test_acpi_aarch64_virt_smmuv3_dev(void)
{
test_data data = {
.machine = "virt",
.arch = "aarch64",
.tcg_only = true,
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
.ram_start = 0x40000000ULL,
.scan_len = 128ULL * MiB,
};
/*
* cdrom is plugged into scsi controller to avoid conflict
* with pxb-pcie. See comments in test_acpi_aarch64_virt_tcg_pxb()
* for details.
*
* The setup includes three PCie root complexes, two of which are
* connected to separate SMMUv3 devices. The resulting IORT table
* contains two SMMUv3 nodes and a Root Complex node with ID mappings
* of which two of the ID mappings have output references pointing
* to two different SMMUv3 nodes and the remaining ones pointing to
* ITS.
*/
data.variant = ".smmuv3-dev";
test_acpi_one(" -device pcie-root-port,chassis=1,id=pci.1"
" -device virtio-scsi-pci,id=scsi0,bus=pci.1"
" -drive file="
"tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2,"
"if=none,media=cdrom,id=drive-scsi0-0-0-1,readonly=on"
" -device scsi-cd,bus=scsi0.0,scsi-id=0,"
"drive=drive-scsi0-0-0-1,id=scsi0-0-0-1,bootindex=1"
" -cpu cortex-a57"
" -device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0"
" -device pxb-pcie,id=pcie.1,bus=pcie.0,bus_nr=0x10"
" -device arm-smmuv3,primary-bus=pcie.1,id=smmuv3.1"
" -device pxb-pcie,id=pcie.2,bus=pcie.0,bus_nr=0x20",
&data);
free_test_data(&data);
}
#ifndef _WIN32
# define DEV_NULL "/dev/null"
#else
@ -2768,6 +2848,12 @@ int main(int argc, char *argv[])
if (qtest_has_device("virtio-iommu-pci")) {
qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot);
}
qtest_add_func("acpi/virt/smmuv3-legacy",
test_acpi_aarch64_virt_smmuv3_legacy);
if (qtest_has_device("arm-smmuv3")) {
qtest_add_func("acpi/virt/smmuv3-dev",
test_acpi_aarch64_virt_smmuv3_dev);
}
}
} else if (strcmp(arch, "riscv64") == 0) {
if (has_tcg && qtest_has_device("virtio-blk-pci")) {

View file

@ -134,6 +134,35 @@ run-gdbstub-sve-ioctls: sve-ioctls
EXTRA_RUNS += run-gdbstub-sysregs run-gdbstub-sve-ioctls
ifneq ($(CROSS_AS_HAS_ARMV9_SME),)
# SME gdbstub tests
run-gdbstub-sysregs-sme: sysregs
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(GDB) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
--bin $< --test $(AARCH64_SRC)/gdbstub/test-sme.py \
-- test_sme --gdb_basic_za_test, \
basic gdbstub SME support)
ifeq ($(GDB_HAS_SME_TILES),y)
run-gdbstub-sysregs-sme-tile-slice: sysregs
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(GDB) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
--bin $< --test $(AARCH64_SRC)/gdbstub/test-sme.py \
-- test_sme --gdb_tile_slice_test, \
gdbstub SME ZA tile slice support)
else
run-gdbstub-sysregs-sme-tile-slice: sysregs
$(call skip-test,"gdbstub SME ZA tile slice support", \
"selected gdb ($(GDB)) does not support SME ZA tile slices")
endif
EXTRA_RUNS += run-gdbstub-sysregs-sme run-gdbstub-sysregs-sme-tile-slice
endif
ifeq ($(GDB_HAS_MTE),y)
run-gdbstub-mte: mte-8
$(call run-test, $@, $(GDB_SCRIPT) \

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test GDB memory-tag commands that exercise the stubs for the qIsAddressTagged,
# qMemTag, and QMemTag packets, which are used for manipulating allocation tags.

View file

@ -0,0 +1,117 @@
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Test the SME registers are visible and changeable via gdbstub
#
# This is launched via tests/guest-debug/run-test.py
#
import argparse
import gdb
from test_gdbstub import main, report
MAGIC = 0x01020304
BASIC_ZA_TEST = 0
TILE_SLICE_TEST = 0
def run_test():
"""Run the requested test(s) for SME ZA gdbstub support"""
if BASIC_ZA_TEST:
run_basic_sme_za_gdbstub_support_test()
if TILE_SLICE_TEST:
run_basic_sme_za_tile_slice_gdbstub_support_test()
def run_basic_sme_za_gdbstub_support_test():
"""Test reads and writes to the SME ZA register at the byte level"""
frame = gdb.selected_frame()
rname = "za"
za = frame.read_register(rname)
report(True, "Reading %s" % rname)
# Writing to the ZA register, byte by byte.
for i in range(0, 16):
for j in range(0, 16):
cmd = "set $za[%d][%d] = 0x01" % (i, j)
gdb.execute(cmd)
report(True, "%s" % cmd)
# Reading from the ZA register, byte by byte.
for i in range(0, 16):
for j in range(0, 16):
reg = "$za[%d][%d]" % (i, j)
v = gdb.parse_and_eval(reg)
report(str(v.type) == "uint8_t", "size of %s" % (reg))
report(v == 0x1, "%s is 0x%x" % (reg, 0x1))
def run_basic_sme_za_tile_slice_gdbstub_support_test():
"""Test reads and writes of SME ZA horizontal and vertical tile slices
Test if SME ZA tile slices, both horizontal and vertical,
can be correctly read and written to. The sizes to test
are quadwords and doublewords.
"""
sizes = {}
sizes["q"] = "uint128_t"
sizes["d"] = "uint64_t"
# Accessing requested sizes of elements of ZA
for size in sizes:
# Accessing various ZA tiles
for i in range(0, 4):
# Accessing various horizontal slices for each ZA tile
for j in range(0, 4):
# Writing to various elements in each tile slice
for k in range(0, 4):
cmd = "set $za%dh%c%d[%d] = 0x%x" % (i, size, j, k, MAGIC)
gdb.execute(cmd)
report(True, "%s" % cmd)
# Reading from the written elements in each tile slice
for k in range(0, 4):
reg = "$za%dh%c%d[%d]" % (i, size, j, k)
v = gdb.parse_and_eval(reg)
report(str(v.type) == sizes[size], "size of %s" % (reg))
report(v == MAGIC, "%s is 0x%x" % (reg, MAGIC))
# Accessing various vertical slices for each ZA tile
for j in range(0, 4):
# Writing to various elements in each tile slice
for k in range(0, 4):
cmd = "set $za%dv%c%d[%d] = 0x%x" % (i, size, j, k, MAGIC)
gdb.execute(cmd)
report(True, "%s" % cmd)
# Reading from the written elements in each tile slice
for k in range(0, 4):
reg = "$za%dv%c%d[%d]" % (i, size, j, k)
v = gdb.parse_and_eval(reg)
report(str(v.type) == sizes[size], "size of %s" % (reg))
report(v == MAGIC, "%s is 0x%x" % (reg, MAGIC))
parser = argparse.ArgumentParser(description="A gdbstub test for SME support")
parser.add_argument("--gdb_basic_za_test",
help="Enable test for basic SME ZA support",
action="store_true")
parser.add_argument("--gdb_tile_slice_test",
help="Enable test for ZA tile slice support",
action="store_true")
args = parser.parse_args()
if args.gdb_basic_za_test:
BASIC_ZA_TEST = 1
if args.gdb_tile_slice_test:
TILE_SLICE_TEST = 1
main(run_test, expected_arch="aarch64")

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test the SVE ZReg reports the right amount of data. It uses the
# sve-ioctl test and examines the register data each time the

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test the SVE registers are visible and changeable via gdbstub
#

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test some of the system debug features with the multiarch memory
# test. It is a port of the original vmlinux focused test case but

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test some of the system debug features with the multiarch memory
# test. It is a port of the original vmlinux focused test case but

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# A very simple smoke test for debugging the SHA1 userspace test on
# each target.

View file

@ -1,7 +1,6 @@
"""Test that gdbstub has access to proc mappings.
This runs as a sourced script (via -x, via run-test.py)."""
from __future__ import print_function
import gdb
from test_gdbstub import gdb_exit, main, report

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test auxiliary vector is loaded via gdbstub
#

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test gdbstub Xfer:siginfo:read stub.
#

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test auxiliary vector is loaded via gdbstub
#

View file

@ -1,4 +1,3 @@
from __future__ import print_function
#
# Test that signals and debugging mix well together on s390x.

View file

@ -1,7 +1,6 @@
"""Test single-stepping SVC.
This runs as a sourced script (via -x, via run-test.py)."""
from __future__ import print_function
import gdb
from test_gdbstub import main, report