mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210430' into staging
target-arm queue: * hw/pci-host/gpex: Don't fault for unmapped parts of MMIO and PIO windows * hw: add compat machines for 6.1 * Fault misaligned accesses where the architecture requires it * Fix some corner cases of MTE faults (notably with misaligned accesses) * Make Thumb store insns UNDEF for Rn==1111 * hw/arm/smmuv3: Support 16K translation granule # gpg: Signature made Fri 30 Apr 2021 11:33:45 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210430: (43 commits) hw/pci-host/gpex: Don't fault for unmapped parts of MMIO and PIO windows hw: add compat machines for 6.1 target/arm: Enforce alignment for sve LD1R target/arm: Enforce alignment for aa64 vector LDn/STn (single) target/arm: Enforce alignment for aa64 vector LDn/STn (multiple) target/arm: Use MemOp for size + endian in aa64 vector ld/st target/arm: Enforce alignment for aa64 load-acq/store-rel target/arm: Use finalize_memop for aa64 fpr load/store target/arm: Use finalize_memop for aa64 gpr load/store target/arm: Enforce alignment for VLDn/VSTn (single) target/arm: Enforce alignment for VLDn/VSTn (multiple) target/arm: Enforce alignment for VLDn (all lanes) target/arm: Enforce alignment for VLDR/VSTR target/arm: Enforce alignment for VLDM/VSTM target/arm: Enforce alignment for SRS target/arm: Enforce alignment for RFE target/arm: Enforce alignment for LDM/STM target/arm: Enforce alignment for LDA/LDAH/STL/STLH target/arm: Enforce word alignment for LDRD/STRD target/arm: Adjust gen_aa32_{ld, st}_i64 for align+endianness ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+4
-2
@@ -259,8 +259,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
|
||||
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
|
||||
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1);
|
||||
|
||||
/* 4K and 64K granule support */
|
||||
/* 4K, 16K and 64K granule support */
|
||||
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
|
||||
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1);
|
||||
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1);
|
||||
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
|
||||
|
||||
@@ -503,7 +504,8 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
|
||||
|
||||
tg = CD_TG(cd, i);
|
||||
tt->granule_sz = tg2granule(tg, i);
|
||||
if ((tt->granule_sz != 12 && tt->granule_sz != 16) || CD_ENDI(cd)) {
|
||||
if ((tt->granule_sz != 12 && tt->granule_sz != 14 &&
|
||||
tt->granule_sz != 16) || CD_ENDI(cd)) {
|
||||
goto bad_cd;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -2757,10 +2757,15 @@ static void machvirt_machine_init(void)
|
||||
}
|
||||
type_init(machvirt_machine_init);
|
||||
|
||||
static void virt_machine_6_1_options(MachineClass *mc)
|
||||
{
|
||||
}
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(6, 1)
|
||||
|
||||
static void virt_machine_6_0_options(MachineClass *mc)
|
||||
{
|
||||
}
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(6, 0)
|
||||
DEFINE_VIRT_MACHINE(6, 0)
|
||||
|
||||
static void virt_machine_5_2_options(MachineClass *mc)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
|
||||
GlobalProperty hw_compat_6_0[] = {
|
||||
{ "gpex-pcihost", "allow-unmapped-accesses", "false" },
|
||||
};
|
||||
const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0);
|
||||
|
||||
GlobalProperty hw_compat_5_2[] = {
|
||||
{ "ICH9-LPC", "smm-compat", "on"},
|
||||
{ "PIIX4_PM", "smm-compat", "on"},
|
||||
|
||||
@@ -96,6 +96,9 @@
|
||||
#include "trace.h"
|
||||
#include CONFIG_DEVICES
|
||||
|
||||
GlobalProperty pc_compat_6_0[] = {};
|
||||
const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0);
|
||||
|
||||
GlobalProperty pc_compat_5_2[] = {
|
||||
{ "ICH9-LPC", "x-smi-cpu-hotunplug", "off" },
|
||||
};
|
||||
|
||||
+13
-1
@@ -415,7 +415,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
|
||||
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
|
||||
}
|
||||
|
||||
static void pc_i440fx_6_0_machine_options(MachineClass *m)
|
||||
static void pc_i440fx_6_1_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_i440fx_machine_options(m);
|
||||
@@ -424,6 +424,18 @@ static void pc_i440fx_6_0_machine_options(MachineClass *m)
|
||||
pcmc->default_cpu_version = 1;
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v6_1, "pc-i440fx-6.1", NULL,
|
||||
pc_i440fx_6_1_machine_options);
|
||||
|
||||
static void pc_i440fx_6_0_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_i440fx_6_1_machine_options(m);
|
||||
m->alias = NULL;
|
||||
m->is_default = false;
|
||||
compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len);
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v6_0, "pc-i440fx-6.0", NULL,
|
||||
pc_i440fx_6_0_machine_options);
|
||||
|
||||
|
||||
+12
-1
@@ -345,7 +345,7 @@ static void pc_q35_machine_options(MachineClass *m)
|
||||
m->max_cpus = 288;
|
||||
}
|
||||
|
||||
static void pc_q35_6_0_machine_options(MachineClass *m)
|
||||
static void pc_q35_6_1_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_machine_options(m);
|
||||
@@ -353,6 +353,17 @@ static void pc_q35_6_0_machine_options(MachineClass *m)
|
||||
pcmc->default_cpu_version = 1;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v6_1, "pc-q35-6.1", NULL,
|
||||
pc_q35_6_1_machine_options);
|
||||
|
||||
static void pc_q35_6_0_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_q35_6_1_machine_options(m);
|
||||
m->alias = NULL;
|
||||
compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len);
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v6_0, "pc-q35-6.0", NULL,
|
||||
pc_q35_6_0_machine_options);
|
||||
|
||||
|
||||
+53
-3
@@ -83,12 +83,51 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
|
||||
int i;
|
||||
|
||||
pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
|
||||
sysbus_init_mmio(sbd, &pex->mmio);
|
||||
|
||||
/*
|
||||
* Note that the MemoryRegions io_mmio and io_ioport that we pass
|
||||
* to pci_register_root_bus() are not the same as the
|
||||
* MemoryRegions io_mmio_window and io_ioport_window that we
|
||||
* expose as SysBus MRs. The difference is in the behaviour of
|
||||
* accesses to addresses where no PCI device has been mapped.
|
||||
*
|
||||
* io_mmio and io_ioport are the underlying PCI view of the PCI
|
||||
* address space, and when a PCI device does a bus master access
|
||||
* to a bad address this is reported back to it as a transaction
|
||||
* failure.
|
||||
*
|
||||
* io_mmio_window and io_ioport_window implement "unmapped
|
||||
* addresses read as -1 and ignore writes"; this is traditional
|
||||
* x86 PC behaviour, which is not mandated by the PCI spec proper
|
||||
* but expected by much PCI-using guest software, including Linux.
|
||||
*
|
||||
* In the interests of not being unnecessarily surprising, we
|
||||
* implement it in the gpex PCI host controller, by providing the
|
||||
* _window MRs, which are containers with io ops that implement
|
||||
* the 'background' behaviour and which hold the real PCI MRs as
|
||||
* subregions.
|
||||
*/
|
||||
memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX);
|
||||
memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024);
|
||||
|
||||
sysbus_init_mmio(sbd, &pex->mmio);
|
||||
sysbus_init_mmio(sbd, &s->io_mmio);
|
||||
sysbus_init_mmio(sbd, &s->io_ioport);
|
||||
if (s->allow_unmapped_accesses) {
|
||||
memory_region_init_io(&s->io_mmio_window, OBJECT(s),
|
||||
&unassigned_io_ops, OBJECT(s),
|
||||
"gpex_mmio_window", UINT64_MAX);
|
||||
memory_region_init_io(&s->io_ioport_window, OBJECT(s),
|
||||
&unassigned_io_ops, OBJECT(s),
|
||||
"gpex_ioport_window", 64 * 1024);
|
||||
|
||||
memory_region_add_subregion(&s->io_mmio_window, 0, &s->io_mmio);
|
||||
memory_region_add_subregion(&s->io_ioport_window, 0, &s->io_ioport);
|
||||
sysbus_init_mmio(sbd, &s->io_mmio_window);
|
||||
sysbus_init_mmio(sbd, &s->io_ioport_window);
|
||||
} else {
|
||||
sysbus_init_mmio(sbd, &s->io_mmio);
|
||||
sysbus_init_mmio(sbd, &s->io_ioport);
|
||||
}
|
||||
|
||||
for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
||||
sysbus_init_irq(sbd, &s->irq[i]);
|
||||
s->irq_num[i] = -1;
|
||||
@@ -108,6 +147,16 @@ static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
|
||||
return "0000:00";
|
||||
}
|
||||
|
||||
static Property gpex_host_properties[] = {
|
||||
/*
|
||||
* Permit CPU accesses to unmapped areas of the PIO and MMIO windows
|
||||
* (discarding writes and returning -1 for reads) rather than aborting.
|
||||
*/
|
||||
DEFINE_PROP_BOOL("allow-unmapped-accesses", GPEXHost,
|
||||
allow_unmapped_accesses, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void gpex_host_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@@ -117,6 +166,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = gpex_host_realize;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->fw_name = "pci";
|
||||
device_class_set_props(dc, gpex_host_properties);
|
||||
}
|
||||
|
||||
static void gpex_host_initfn(Object *obj)
|
||||
|
||||
+14
-3
@@ -4605,14 +4605,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
|
||||
type_init(spapr_machine_register_##suffix)
|
||||
|
||||
/*
|
||||
* pseries-6.0
|
||||
* pseries-6.1
|
||||
*/
|
||||
static void spapr_machine_6_0_class_options(MachineClass *mc)
|
||||
static void spapr_machine_6_1_class_options(MachineClass *mc)
|
||||
{
|
||||
/* Defaults for the latest behaviour inherited from the base class */
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(6_0, "6.0", true);
|
||||
DEFINE_SPAPR_MACHINE(6_1, "6.1", true);
|
||||
|
||||
/*
|
||||
* pseries-6.0
|
||||
*/
|
||||
static void spapr_machine_6_0_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_6_1_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(6_0, "6.0", false);
|
||||
|
||||
/*
|
||||
* pseries-5.2
|
||||
|
||||
@@ -795,14 +795,26 @@ bool css_migration_enabled(void)
|
||||
} \
|
||||
type_init(ccw_machine_register_##suffix)
|
||||
|
||||
static void ccw_machine_6_1_instance_options(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void ccw_machine_6_1_class_options(MachineClass *mc)
|
||||
{
|
||||
}
|
||||
DEFINE_CCW_MACHINE(6_1, "6.1", true);
|
||||
|
||||
static void ccw_machine_6_0_instance_options(MachineState *machine)
|
||||
{
|
||||
ccw_machine_6_1_instance_options(machine);
|
||||
}
|
||||
|
||||
static void ccw_machine_6_0_class_options(MachineClass *mc)
|
||||
{
|
||||
ccw_machine_6_1_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
|
||||
}
|
||||
DEFINE_CCW_MACHINE(6_0, "6.0", true);
|
||||
DEFINE_CCW_MACHINE(6_0, "6.0", false);
|
||||
|
||||
static void ccw_machine_5_2_instance_options(MachineState *machine)
|
||||
{
|
||||
|
||||
@@ -353,6 +353,9 @@ struct MachineState {
|
||||
} \
|
||||
type_init(machine_initfn##_register_types)
|
||||
|
||||
extern GlobalProperty hw_compat_6_0[];
|
||||
extern const size_t hw_compat_6_0_len;
|
||||
|
||||
extern GlobalProperty hw_compat_5_2[];
|
||||
extern const size_t hw_compat_5_2_len;
|
||||
|
||||
|
||||
@@ -197,6 +197,9 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
|
||||
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
|
||||
const CPUArchIdList *apic_ids, GArray *entry);
|
||||
|
||||
extern GlobalProperty pc_compat_6_0[];
|
||||
extern const size_t pc_compat_6_0_len;
|
||||
|
||||
extern GlobalProperty pc_compat_5_2[];
|
||||
extern const size_t pc_compat_5_2_len;
|
||||
|
||||
|
||||
@@ -49,8 +49,12 @@ struct GPEXHost {
|
||||
|
||||
MemoryRegion io_ioport;
|
||||
MemoryRegion io_mmio;
|
||||
MemoryRegion io_ioport_window;
|
||||
MemoryRegion io_mmio_window;
|
||||
qemu_irq irq[GPEX_NUM_IRQS];
|
||||
int irq_num[GPEX_NUM_IRQS];
|
||||
|
||||
bool allow_unmapped_accesses;
|
||||
};
|
||||
|
||||
struct GPEXConfig {
|
||||
|
||||
+69
-36
@@ -225,6 +225,11 @@ typedef struct ARMPACKey {
|
||||
} ARMPACKey;
|
||||
#endif
|
||||
|
||||
/* See the commentary above the TBFLAG field definitions. */
|
||||
typedef struct CPUARMTBFlags {
|
||||
uint32_t flags;
|
||||
target_ulong flags2;
|
||||
} CPUARMTBFlags;
|
||||
|
||||
typedef struct CPUARMState {
|
||||
/* Regs for current mode. */
|
||||
@@ -253,7 +258,7 @@ typedef struct CPUARMState {
|
||||
uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */
|
||||
|
||||
/* Cached TBFLAGS state. See below for which bits are included. */
|
||||
uint32_t hflags;
|
||||
CPUARMTBFlags hflags;
|
||||
|
||||
/* Frequently accessed CPSR bits are stored separately for efficiency.
|
||||
This contains all the other bits. Use cpsr_{read,write} to access
|
||||
@@ -3377,74 +3382,82 @@ typedef ARMCPU ArchCPU;
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
/*
|
||||
* Bit usage in the TB flags field: bit 31 indicates whether we are
|
||||
* in 32 or 64 bit mode. The meaning of the other bits depends on that.
|
||||
* We put flags which are shared between 32 and 64 bit mode at the top
|
||||
* of the word, and flags which apply to only one mode at the bottom.
|
||||
* We have more than 32-bits worth of state per TB, so we split the data
|
||||
* between tb->flags and tb->cs_base, which is otherwise unused for ARM.
|
||||
* We collect these two parts in CPUARMTBFlags where they are named
|
||||
* flags and flags2 respectively.
|
||||
*
|
||||
* 31 20 18 14 9 0
|
||||
* +--------------+-----+-----+----------+--------------+
|
||||
* | | | TBFLAG_A32 | |
|
||||
* | | +-----+----------+ TBFLAG_AM32 |
|
||||
* | TBFLAG_ANY | |TBFLAG_M32| |
|
||||
* | +-----------+----------+--------------|
|
||||
* | | TBFLAG_A64 |
|
||||
* +--------------+-------------------------------------+
|
||||
* 31 20 0
|
||||
* The flags that are shared between all execution modes, TBFLAG_ANY,
|
||||
* are stored in flags. The flags that are specific to a given mode
|
||||
* are stores in flags2. Since cs_base is sized on the configured
|
||||
* address size, flags2 always has 64-bits for A64, and a minimum of
|
||||
* 32-bits for A32 and M32.
|
||||
*
|
||||
* The bits for 32-bit A-profile and M-profile partially overlap:
|
||||
*
|
||||
* 31 23 11 10 0
|
||||
* +-------------+----------+----------------+
|
||||
* | | | TBFLAG_A32 |
|
||||
* | TBFLAG_AM32 | +-----+----------+
|
||||
* | | |TBFLAG_M32|
|
||||
* +-------------+----------------+----------+
|
||||
* 31 23 5 4 0
|
||||
*
|
||||
* Unless otherwise noted, these bits are cached in env->hflags.
|
||||
*/
|
||||
FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
|
||||
FIELD(TBFLAG_ANY, SS_ACTIVE, 30, 1)
|
||||
FIELD(TBFLAG_ANY, PSTATE_SS, 29, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_ANY, BE_DATA, 28, 1)
|
||||
FIELD(TBFLAG_ANY, MMUIDX, 24, 4)
|
||||
FIELD(TBFLAG_ANY, AARCH64_STATE, 0, 1)
|
||||
FIELD(TBFLAG_ANY, SS_ACTIVE, 1, 1)
|
||||
FIELD(TBFLAG_ANY, PSTATE__SS, 2, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_ANY, BE_DATA, 3, 1)
|
||||
FIELD(TBFLAG_ANY, MMUIDX, 4, 4)
|
||||
/* Target EL if we take a floating-point-disabled exception */
|
||||
FIELD(TBFLAG_ANY, FPEXC_EL, 22, 2)
|
||||
FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2)
|
||||
/* For A-profile only, target EL for debug exceptions. */
|
||||
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 20, 2)
|
||||
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2)
|
||||
/* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */
|
||||
FIELD(TBFLAG_ANY, ALIGN_MEM, 12, 1)
|
||||
|
||||
/*
|
||||
* Bit usage when in AArch32 state, both A- and M-profile.
|
||||
*/
|
||||
FIELD(TBFLAG_AM32, CONDEXEC, 0, 8) /* Not cached. */
|
||||
FIELD(TBFLAG_AM32, THUMB, 8, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_AM32, CONDEXEC, 24, 8) /* Not cached. */
|
||||
FIELD(TBFLAG_AM32, THUMB, 23, 1) /* Not cached. */
|
||||
|
||||
/*
|
||||
* Bit usage when in AArch32 state, for A-profile only.
|
||||
*/
|
||||
FIELD(TBFLAG_A32, VECLEN, 9, 3) /* Not cached. */
|
||||
FIELD(TBFLAG_A32, VECSTRIDE, 12, 2) /* 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, 12, 2)
|
||||
FIELD(TBFLAG_A32, VFPEN, 14, 1) /* Partially cached, minus FPEXC. */
|
||||
FIELD(TBFLAG_A32, SCTLR_B, 15, 1)
|
||||
FIELD(TBFLAG_A32, HSTR_ACTIVE, 16, 1)
|
||||
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)
|
||||
/*
|
||||
* Indicates whether cp register reads and writes by guest code should access
|
||||
* the secure or nonsecure bank of banked registers; note that this is not
|
||||
* the same thing as the current security state of the processor!
|
||||
*/
|
||||
FIELD(TBFLAG_A32, NS, 17, 1)
|
||||
FIELD(TBFLAG_A32, NS, 10, 1)
|
||||
|
||||
/*
|
||||
* Bit usage when in AArch32 state, for M-profile only.
|
||||
*/
|
||||
/* Handler (ie not Thread) mode */
|
||||
FIELD(TBFLAG_M32, HANDLER, 9, 1)
|
||||
FIELD(TBFLAG_M32, HANDLER, 0, 1)
|
||||
/* Whether we should generate stack-limit checks */
|
||||
FIELD(TBFLAG_M32, STACKCHECK, 10, 1)
|
||||
FIELD(TBFLAG_M32, STACKCHECK, 1, 1)
|
||||
/* Set if FPCCR.LSPACT is set */
|
||||
FIELD(TBFLAG_M32, LSPACT, 11, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_M32, LSPACT, 2, 1) /* Not cached. */
|
||||
/* Set if we must create a new FP context */
|
||||
FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 12, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 3, 1) /* Not cached. */
|
||||
/* Set if FPCCR.S does not match current security state */
|
||||
FIELD(TBFLAG_M32, FPCCR_S_WRONG, 13, 1) /* Not cached. */
|
||||
FIELD(TBFLAG_M32, FPCCR_S_WRONG, 4, 1) /* Not cached. */
|
||||
|
||||
/*
|
||||
* Bit usage when in AArch64 state
|
||||
@@ -3462,6 +3475,26 @@ FIELD(TBFLAG_A64, TCMA, 16, 2)
|
||||
FIELD(TBFLAG_A64, MTE_ACTIVE, 18, 1)
|
||||
FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1)
|
||||
|
||||
/*
|
||||
* Helpers for using the above.
|
||||
*/
|
||||
#define DP_TBFLAG_ANY(DST, WHICH, VAL) \
|
||||
(DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL))
|
||||
#define DP_TBFLAG_A64(DST, WHICH, VAL) \
|
||||
(DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL))
|
||||
#define DP_TBFLAG_A32(DST, WHICH, VAL) \
|
||||
(DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL))
|
||||
#define DP_TBFLAG_M32(DST, WHICH, VAL) \
|
||||
(DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_M32, WHICH, VAL))
|
||||
#define DP_TBFLAG_AM32(DST, WHICH, VAL) \
|
||||
(DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL))
|
||||
|
||||
#define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH)
|
||||
#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH)
|
||||
#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH)
|
||||
#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH)
|
||||
#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH)
|
||||
|
||||
/**
|
||||
* cpu_mmu_index:
|
||||
* @env: The cpu environment
|
||||
@@ -3472,7 +3505,7 @@ FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1)
|
||||
*/
|
||||
static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
|
||||
{
|
||||
return FIELD_EX32(env->hflags, TBFLAG_ANY, MMUIDX);
|
||||
return EX_TBFLAG_ANY(env->hflags, MMUIDX);
|
||||
}
|
||||
|
||||
static inline bool bswap_code(bool sctlr_b)
|
||||
|
||||
@@ -1020,7 +1020,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
||||
* the hflags rebuild, since we can pull the composite TBII field
|
||||
* from there.
|
||||
*/
|
||||
tbii = FIELD_EX32(env->hflags, TBFLAG_A64, TBII);
|
||||
tbii = EX_TBFLAG_A64(env->hflags, TBII);
|
||||
if ((tbii >> extract64(new_pc, 55, 1)) & 1) {
|
||||
/* TBI is enabled. */
|
||||
int core_mmu_idx = cpu_mmu_index(env, false);
|
||||
|
||||
@@ -104,8 +104,7 @@ DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mte_check1, TCG_CALL_NO_WG, i64, env, i32, i64)
|
||||
DEF_HELPER_FLAGS_3(mte_checkN, TCG_CALL_NO_WG, i64, env, i32, i64)
|
||||
DEF_HELPER_FLAGS_3(mte_check, TCG_CALL_NO_WG, i64, env, i32, i64)
|
||||
DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64)
|
||||
DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32)
|
||||
|
||||
+88
-74
@@ -12984,42 +12984,49 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx, uint32_t flags)
|
||||
static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx,
|
||||
CPUARMTBFlags flags)
|
||||
{
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX,
|
||||
arm_to_core_mmu_idx(mmu_idx));
|
||||
DP_TBFLAG_ANY(flags, FPEXC_EL, fp_el);
|
||||
DP_TBFLAG_ANY(flags, MMUIDX, arm_to_core_mmu_idx(mmu_idx));
|
||||
|
||||
if (arm_singlestep_active(env)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);
|
||||
DP_TBFLAG_ANY(flags, SS_ACTIVE, 1);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx, uint32_t flags)
|
||||
static CPUARMTBFlags rebuild_hflags_common_32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx,
|
||||
CPUARMTBFlags flags)
|
||||
{
|
||||
bool sctlr_b = arm_sctlr_b(env);
|
||||
|
||||
if (sctlr_b) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, 1);
|
||||
DP_TBFLAG_A32(flags, SCTLR__B, 1);
|
||||
}
|
||||
if (arm_cpu_data_is_big_endian_a32(env, sctlr_b)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
|
||||
DP_TBFLAG_ANY(flags, BE_DATA, 1);
|
||||
}
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
|
||||
DP_TBFLAG_A32(flags, NS, !access_secure_reg(env));
|
||||
|
||||
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
CPUARMTBFlags flags = {};
|
||||
uint32_t ccr = env->v7m.ccr[env->v7m.secure];
|
||||
|
||||
/* Without HaveMainExt, CCR.UNALIGN_TRP is RES1. */
|
||||
if (ccr & R_V7M_CCR_UNALIGN_TRP_MASK) {
|
||||
DP_TBFLAG_ANY(flags, ALIGN_MEM, 1);
|
||||
}
|
||||
|
||||
if (arm_v7m_is_handler_mode(env)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_M32, HANDLER, 1);
|
||||
DP_TBFLAG_M32(flags, HANDLER, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -13029,56 +13036,60 @@ static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el,
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_V8) &&
|
||||
!((mmu_idx & ARM_MMU_IDX_M_NEGPRI) &&
|
||||
(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_M32, STACKCHECK, 1);
|
||||
(ccr & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
|
||||
DP_TBFLAG_M32(flags, STACKCHECK, 1);
|
||||
}
|
||||
|
||||
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_aprofile(CPUARMState *env)
|
||||
static CPUARMTBFlags rebuild_hflags_aprofile(CPUARMState *env)
|
||||
{
|
||||
int flags = 0;
|
||||
CPUARMTBFlags flags = {};
|
||||
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, DEBUG_TARGET_EL,
|
||||
arm_debug_target_el(env));
|
||||
DP_TBFLAG_ANY(flags, DEBUG_TARGET_EL, arm_debug_target_el(env));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
uint32_t flags = rebuild_hflags_aprofile(env);
|
||||
CPUARMTBFlags flags = rebuild_hflags_aprofile(env);
|
||||
int el = arm_current_el(env);
|
||||
|
||||
if (arm_el_is_aa64(env, 1)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
|
||||
if (arm_sctlr(env, el) & SCTLR_A) {
|
||||
DP_TBFLAG_ANY(flags, ALIGN_MEM, 1);
|
||||
}
|
||||
|
||||
if (arm_current_el(env) < 2 && env->cp15.hstr_el2 &&
|
||||
if (arm_el_is_aa64(env, 1)) {
|
||||
DP_TBFLAG_A32(flags, VFPEN, 1);
|
||||
}
|
||||
|
||||
if (el < 2 && env->cp15.hstr_el2 &&
|
||||
(arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, HSTR_ACTIVE, 1);
|
||||
DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1);
|
||||
}
|
||||
|
||||
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
uint32_t flags = rebuild_hflags_aprofile(env);
|
||||
CPUARMTBFlags flags = rebuild_hflags_aprofile(env);
|
||||
ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
|
||||
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
|
||||
uint64_t sctlr;
|
||||
int tbii, tbid;
|
||||
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
|
||||
DP_TBFLAG_ANY(flags, AARCH64_STATE, 1);
|
||||
|
||||
/* Get control bits for tagged addresses. */
|
||||
tbid = aa64_va_parameter_tbi(tcr, mmu_idx);
|
||||
tbii = tbid & ~aa64_va_parameter_tbid(tcr, mmu_idx);
|
||||
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);
|
||||
DP_TBFLAG_A64(flags, TBII, tbii);
|
||||
DP_TBFLAG_A64(flags, TBID, tbid);
|
||||
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
|
||||
int sve_el = sve_exception_el(env, el);
|
||||
@@ -13093,14 +13104,18 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
} else {
|
||||
zcr_len = sve_zcr_len_for_el(env, el);
|
||||
}
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
|
||||
DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el);
|
||||
DP_TBFLAG_A64(flags, ZCR_LEN, zcr_len);
|
||||
}
|
||||
|
||||
sctlr = regime_sctlr(env, stage1);
|
||||
|
||||
if (sctlr & SCTLR_A) {
|
||||
DP_TBFLAG_ANY(flags, ALIGN_MEM, 1);
|
||||
}
|
||||
|
||||
if (arm_cpu_data_is_big_endian_a64(el, sctlr)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
|
||||
DP_TBFLAG_ANY(flags, BE_DATA, 1);
|
||||
}
|
||||
|
||||
if (cpu_isar_feature(aa64_pauth, env_archcpu(env))) {
|
||||
@@ -13111,14 +13126,14 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
* The decision of which action to take is left to a helper.
|
||||
*/
|
||||
if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);
|
||||
DP_TBFLAG_A64(flags, PAUTH_ACTIVE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
|
||||
/* Note that SCTLR_EL[23].BT == SCTLR_BT1. */
|
||||
if (sctlr & (el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);
|
||||
DP_TBFLAG_A64(flags, BT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13130,7 +13145,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
case ARMMMUIdx_SE10_1:
|
||||
case ARMMMUIdx_SE10_1_PAN:
|
||||
/* TODO: ARMv8.3-NV */
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
||||
DP_TBFLAG_A64(flags, UNPRIV, 1);
|
||||
break;
|
||||
case ARMMMUIdx_E20_2:
|
||||
case ARMMMUIdx_E20_2_PAN:
|
||||
@@ -13141,7 +13156,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
* gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR.
|
||||
*/
|
||||
if (env->cp15.hcr_el2 & HCR_TGE) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
||||
DP_TBFLAG_A64(flags, UNPRIV, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -13159,30 +13174,29 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
||||
* 4) If no Allocation Tag Access, then all accesses are Unchecked.
|
||||
*/
|
||||
if (allocation_tag_access_enabled(env, el, sctlr)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, ATA, 1);
|
||||
DP_TBFLAG_A64(flags, ATA, 1);
|
||||
if (tbid
|
||||
&& !(env->pstate & PSTATE_TCO)
|
||||
&& (sctlr & (el == 0 ? SCTLR_TCF0 : SCTLR_TCF))) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, MTE_ACTIVE, 1);
|
||||
DP_TBFLAG_A64(flags, MTE_ACTIVE, 1);
|
||||
}
|
||||
}
|
||||
/* And again for unprivileged accesses, if required. */
|
||||
if (FIELD_EX32(flags, TBFLAG_A64, UNPRIV)
|
||||
if (EX_TBFLAG_A64(flags, UNPRIV)
|
||||
&& tbid
|
||||
&& !(env->pstate & PSTATE_TCO)
|
||||
&& (sctlr & SCTLR_TCF0)
|
||||
&& allocation_tag_access_enabled(env, 0, sctlr)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, MTE0_ACTIVE, 1);
|
||||
DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1);
|
||||
}
|
||||
/* Cache TCMA as well as TBI. */
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, TCMA,
|
||||
aa64_va_parameter_tcma(tcr, mmu_idx));
|
||||
DP_TBFLAG_A64(flags, TCMA, aa64_va_parameter_tcma(tcr, mmu_idx));
|
||||
}
|
||||
|
||||
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
|
||||
}
|
||||
|
||||
static uint32_t rebuild_hflags_internal(CPUARMState *env)
|
||||
static CPUARMTBFlags rebuild_hflags_internal(CPUARMState *env)
|
||||
{
|
||||
int el = arm_current_el(env);
|
||||
int fp_el = fp_exception_el(env, el);
|
||||
@@ -13211,6 +13225,7 @@ void HELPER(rebuild_hflags_m32_newel)(CPUARMState *env)
|
||||
int el = arm_current_el(env);
|
||||
int fp_el = fp_exception_el(env, el);
|
||||
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
|
||||
|
||||
env->hflags = rebuild_hflags_m32(env, fp_el, mmu_idx);
|
||||
}
|
||||
|
||||
@@ -13253,12 +13268,14 @@ void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el)
|
||||
static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
uint32_t env_flags_current = env->hflags;
|
||||
uint32_t env_flags_rebuilt = rebuild_hflags_internal(env);
|
||||
CPUARMTBFlags c = env->hflags;
|
||||
CPUARMTBFlags r = rebuild_hflags_internal(env);
|
||||
|
||||
if (unlikely(env_flags_current != env_flags_rebuilt)) {
|
||||
fprintf(stderr, "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n",
|
||||
env_flags_current, env_flags_rebuilt);
|
||||
if (unlikely(c.flags != r.flags || c.flags2 != r.flags2)) {
|
||||
fprintf(stderr, "TCG hflags mismatch "
|
||||
"(current:(0x%08x,0x" TARGET_FMT_lx ")"
|
||||
" rebuilt:(0x%08x,0x" TARGET_FMT_lx ")\n",
|
||||
c.flags, c.flags2, r.flags, r.flags2);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@@ -13267,15 +13284,15 @@ static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
|
||||
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *pflags)
|
||||
{
|
||||
uint32_t flags = env->hflags;
|
||||
CPUARMTBFlags flags;
|
||||
|
||||
*cs_base = 0;
|
||||
assert_hflags_rebuild_correctly(env);
|
||||
flags = env->hflags;
|
||||
|
||||
if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) {
|
||||
if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) {
|
||||
*pc = env->pc;
|
||||
if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype);
|
||||
DP_TBFLAG_A64(flags, BTYPE, env->btype);
|
||||
}
|
||||
} else {
|
||||
*pc = env->regs[15];
|
||||
@@ -13284,7 +13301,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
|
||||
FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S)
|
||||
!= env->v7m.secure) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_M32, FPCCR_S_WRONG, 1);
|
||||
DP_TBFLAG_M32(flags, FPCCR_S_WRONG, 1);
|
||||
}
|
||||
|
||||
if ((env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) &&
|
||||
@@ -13296,12 +13313,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
* active FP context; we must create a new FP context before
|
||||
* executing any FP insn.
|
||||
*/
|
||||
flags = FIELD_DP32(flags, TBFLAG_M32, NEW_FP_CTXT_NEEDED, 1);
|
||||
DP_TBFLAG_M32(flags, NEW_FP_CTXT_NEEDED, 1);
|
||||
}
|
||||
|
||||
bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
|
||||
if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_M32, LSPACT, 1);
|
||||
DP_TBFLAG_M32(flags, LSPACT, 1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@@ -13309,21 +13326,18 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
* Note that VECLEN+VECSTRIDE are RES0 for M-profile.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32,
|
||||
XSCALE_CPAR, env->cp15.c15_cpar);
|
||||
DP_TBFLAG_A32(flags, XSCALE_CPAR, env->cp15.c15_cpar);
|
||||
} else {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN,
|
||||
env->vfp.vec_len);
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE,
|
||||
env->vfp.vec_stride);
|
||||
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)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
|
||||
DP_TBFLAG_A32(flags, VFPEN, 1);
|
||||
}
|
||||
}
|
||||
|
||||
flags = FIELD_DP32(flags, TBFLAG_AM32, THUMB, env->thumb);
|
||||
flags = FIELD_DP32(flags, TBFLAG_AM32, CONDEXEC, env->condexec_bits);
|
||||
DP_TBFLAG_AM32(flags, THUMB, env->thumb);
|
||||
DP_TBFLAG_AM32(flags, CONDEXEC, env->condexec_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -13333,14 +13347,14 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
* 0 x Inactive (the TB flag for SS is always 0)
|
||||
* 1 0 Active-pending
|
||||
* 1 1 Active-not-pending
|
||||
* SS_ACTIVE is set in hflags; PSTATE_SS is computed every TB.
|
||||
* SS_ACTIVE is set in hflags; PSTATE__SS is computed every TB.
|
||||
*/
|
||||
if (FIELD_EX32(flags, TBFLAG_ANY, SS_ACTIVE) &&
|
||||
(env->pstate & PSTATE_SS)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
|
||||
if (EX_TBFLAG_ANY(flags, SS_ACTIVE) && (env->pstate & PSTATE_SS)) {
|
||||
DP_TBFLAG_ANY(flags, PSTATE__SS, 1);
|
||||
}
|
||||
|
||||
*pflags = flags;
|
||||
*pflags = flags.flags;
|
||||
*cs_base = flags.flags2;
|
||||
}
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define TARGET_ARM_INTERNALS_H
|
||||
|
||||
#include "hw/registerfields.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "syndrome.h"
|
||||
|
||||
/* register banks for CPU modes */
|
||||
@@ -1142,14 +1143,10 @@ FIELD(MTEDESC, MIDX, 0, 4)
|
||||
FIELD(MTEDESC, TBI, 4, 2)
|
||||
FIELD(MTEDESC, TCMA, 6, 2)
|
||||
FIELD(MTEDESC, WRITE, 8, 1)
|
||||
FIELD(MTEDESC, ESIZE, 9, 5)
|
||||
FIELD(MTEDESC, TSIZE, 14, 10) /* mte_checkN only */
|
||||
FIELD(MTEDESC, SIZEM1, 9, SIMD_DATA_BITS - 9) /* size - 1 */
|
||||
|
||||
bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr);
|
||||
uint64_t mte_check1(CPUARMState *env, uint32_t desc,
|
||||
uint64_t ptr, uintptr_t ra);
|
||||
uint64_t mte_checkN(CPUARMState *env, uint32_t desc,
|
||||
uint64_t ptr, uintptr_t ra);
|
||||
bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr);
|
||||
uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra);
|
||||
|
||||
static inline int allocation_tag_from_addr(uint64_t ptr)
|
||||
{
|
||||
|
||||
+74
-111
@@ -121,7 +121,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
|
||||
* exception for inaccessible pages, and resolves the virtual address
|
||||
* into the softmmu tlb.
|
||||
*
|
||||
* When RA == 0, this is for mte_probe1. The page is expected to be
|
||||
* When RA == 0, this is for mte_probe. The page is expected to be
|
||||
* valid. Indicate to probe_access_flags no-fault, then assert that
|
||||
* we received a valid page.
|
||||
*/
|
||||
@@ -617,80 +617,6 @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an MTE checked access for a single logical or atomic access.
|
||||
*/
|
||||
static bool mte_probe1_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
|
||||
uintptr_t ra, int bit55)
|
||||
{
|
||||
int mem_tag, mmu_idx, ptr_tag, size;
|
||||
MMUAccessType type;
|
||||
uint8_t *mem;
|
||||
|
||||
ptr_tag = allocation_tag_from_addr(ptr);
|
||||
|
||||
if (tcma_check(desc, bit55, ptr_tag)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX);
|
||||
type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
size = FIELD_EX32(desc, MTEDESC, ESIZE);
|
||||
|
||||
mem = allocation_tag_mem(env, mmu_idx, ptr, type, size,
|
||||
MMU_DATA_LOAD, 1, ra);
|
||||
if (!mem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mem_tag = load_tag1(ptr, mem);
|
||||
return ptr_tag == mem_tag;
|
||||
}
|
||||
|
||||
/*
|
||||
* No-fault version of mte_check1, to be used by SVE for MemSingleNF.
|
||||
* Returns false if the access is Checked and the check failed. This
|
||||
* is only intended to probe the tag -- the validity of the page must
|
||||
* be checked beforehand.
|
||||
*/
|
||||
bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr)
|
||||
{
|
||||
int bit55 = extract64(ptr, 55, 1);
|
||||
|
||||
/* If TBI is disabled, the access is unchecked. */
|
||||
if (unlikely(!tbi_check(desc, bit55))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mte_probe1_int(env, desc, ptr, 0, bit55);
|
||||
}
|
||||
|
||||
uint64_t mte_check1(CPUARMState *env, uint32_t desc,
|
||||
uint64_t ptr, uintptr_t ra)
|
||||
{
|
||||
int bit55 = extract64(ptr, 55, 1);
|
||||
|
||||
/* If TBI is disabled, the access is unchecked, and ptr is not dirty. */
|
||||
if (unlikely(!tbi_check(desc, bit55))) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
if (unlikely(!mte_probe1_int(env, desc, ptr, ra, bit55))) {
|
||||
mte_check_fail(env, desc, ptr, ra);
|
||||
}
|
||||
|
||||
return useronly_clean_ptr(ptr);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr)
|
||||
{
|
||||
return mte_check1(env, desc, ptr, GETPC());
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an MTE checked access for multiple logical accesses.
|
||||
*/
|
||||
|
||||
/**
|
||||
* checkN:
|
||||
* @tag: tag memory to test
|
||||
@@ -753,59 +679,70 @@ static int checkN(uint8_t *mem, int odd, int cmp, int count)
|
||||
return n;
|
||||
}
|
||||
|
||||
uint64_t mte_checkN(CPUARMState *env, uint32_t desc,
|
||||
uint64_t ptr, uintptr_t ra)
|
||||
/**
|
||||
* mte_probe_int() - helper for mte_probe and mte_check
|
||||
* @env: CPU environment
|
||||
* @desc: MTEDESC descriptor
|
||||
* @ptr: virtual address of the base of the access
|
||||
* @fault: return virtual address of the first check failure
|
||||
*
|
||||
* Internal routine for both mte_probe and mte_check.
|
||||
* Return zero on failure, filling in *fault.
|
||||
* Return negative on trivial success for tbi disabled.
|
||||
* Return positive on success with tbi enabled.
|
||||
*/
|
||||
static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
|
||||
uintptr_t ra, uint64_t *fault)
|
||||
{
|
||||
int mmu_idx, ptr_tag, bit55;
|
||||
uint64_t ptr_last, ptr_end, prev_page, next_page;
|
||||
uint64_t tag_first, tag_end;
|
||||
uint64_t tag_byte_first, tag_byte_end;
|
||||
uint32_t esize, total, tag_count, tag_size, n, c;
|
||||
uint64_t ptr_last, prev_page, next_page;
|
||||
uint64_t tag_first, tag_last;
|
||||
uint64_t tag_byte_first, tag_byte_last;
|
||||
uint32_t sizem1, tag_count, tag_size, n, c;
|
||||
uint8_t *mem1, *mem2;
|
||||
MMUAccessType type;
|
||||
|
||||
bit55 = extract64(ptr, 55, 1);
|
||||
*fault = ptr;
|
||||
|
||||
/* If TBI is disabled, the access is unchecked, and ptr is not dirty. */
|
||||
if (unlikely(!tbi_check(desc, bit55))) {
|
||||
return ptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr_tag = allocation_tag_from_addr(ptr);
|
||||
|
||||
if (tcma_check(desc, bit55, ptr_tag)) {
|
||||
goto done;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX);
|
||||
type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
esize = FIELD_EX32(desc, MTEDESC, ESIZE);
|
||||
total = FIELD_EX32(desc, MTEDESC, TSIZE);
|
||||
sizem1 = FIELD_EX32(desc, MTEDESC, SIZEM1);
|
||||
|
||||
/* Find the addr of the end of the access, and of the last element. */
|
||||
ptr_end = ptr + total;
|
||||
ptr_last = ptr_end - esize;
|
||||
/* Find the addr of the end of the access */
|
||||
ptr_last = ptr + sizem1;
|
||||
|
||||
/* Round the bounds to the tag granule, and compute the number of tags. */
|
||||
tag_first = QEMU_ALIGN_DOWN(ptr, TAG_GRANULE);
|
||||
tag_end = QEMU_ALIGN_UP(ptr_last, TAG_GRANULE);
|
||||
tag_count = (tag_end - tag_first) / TAG_GRANULE;
|
||||
tag_last = QEMU_ALIGN_DOWN(ptr_last, TAG_GRANULE);
|
||||
tag_count = ((tag_last - tag_first) / TAG_GRANULE) + 1;
|
||||
|
||||
/* Round the bounds to twice the tag granule, and compute the bytes. */
|
||||
tag_byte_first = QEMU_ALIGN_DOWN(ptr, 2 * TAG_GRANULE);
|
||||
tag_byte_end = QEMU_ALIGN_UP(ptr_last, 2 * TAG_GRANULE);
|
||||
tag_byte_last = QEMU_ALIGN_DOWN(ptr_last, 2 * TAG_GRANULE);
|
||||
|
||||
/* Locate the page boundaries. */
|
||||
prev_page = ptr & TARGET_PAGE_MASK;
|
||||
next_page = prev_page + TARGET_PAGE_SIZE;
|
||||
|
||||
if (likely(tag_end - prev_page <= TARGET_PAGE_SIZE)) {
|
||||
if (likely(tag_last - prev_page <= TARGET_PAGE_SIZE)) {
|
||||
/* Memory access stays on one page. */
|
||||
tag_size = (tag_byte_end - tag_byte_first) / (2 * TAG_GRANULE);
|
||||
mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, total,
|
||||
tag_size = ((tag_byte_last - tag_byte_first) / (2 * TAG_GRANULE)) + 1;
|
||||
mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1,
|
||||
MMU_DATA_LOAD, tag_size, ra);
|
||||
if (!mem1) {
|
||||
goto done;
|
||||
return 1;
|
||||
}
|
||||
/* Perform all of the comparisons. */
|
||||
n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, tag_count);
|
||||
@@ -815,9 +752,9 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc,
|
||||
mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, next_page - ptr,
|
||||
MMU_DATA_LOAD, tag_size, ra);
|
||||
|
||||
tag_size = (tag_byte_end - next_page) / (2 * TAG_GRANULE);
|
||||
tag_size = ((tag_byte_last - next_page) / (2 * TAG_GRANULE)) + 1;
|
||||
mem2 = allocation_tag_mem(env, mmu_idx, next_page, type,
|
||||
ptr_end - next_page,
|
||||
ptr_last - next_page + 1,
|
||||
MMU_DATA_LOAD, tag_size, ra);
|
||||
|
||||
/*
|
||||
@@ -831,31 +768,57 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc,
|
||||
}
|
||||
if (n == c) {
|
||||
if (!mem2) {
|
||||
goto done;
|
||||
return 1;
|
||||
}
|
||||
n += checkN(mem2, 0, ptr_tag, tag_count - c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we failed, we know which granule. Compute the element that
|
||||
* is first in that granule, and signal failure on that element.
|
||||
*/
|
||||
if (unlikely(n < tag_count)) {
|
||||
uint64_t fail_ofs;
|
||||
|
||||
fail_ofs = tag_first + n * TAG_GRANULE - ptr;
|
||||
fail_ofs = ROUND_UP(fail_ofs, esize);
|
||||
mte_check_fail(env, desc, ptr + fail_ofs, ra);
|
||||
if (likely(n == tag_count)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
done:
|
||||
/*
|
||||
* If we failed, we know which granule. For the first granule, the
|
||||
* failure address is @ptr, the first byte accessed. Otherwise the
|
||||
* failure address is the first byte of the nth granule.
|
||||
*/
|
||||
if (n > 0) {
|
||||
*fault = tag_first + n * TAG_GRANULE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra)
|
||||
{
|
||||
uint64_t fault;
|
||||
int ret = mte_probe_int(env, desc, ptr, ra, &fault);
|
||||
|
||||
if (unlikely(ret == 0)) {
|
||||
mte_check_fail(env, desc, fault, ra);
|
||||
} else if (ret < 0) {
|
||||
return ptr;
|
||||
}
|
||||
return useronly_clean_ptr(ptr);
|
||||
}
|
||||
|
||||
uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr)
|
||||
uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr)
|
||||
{
|
||||
return mte_checkN(env, desc, ptr, GETPC());
|
||||
return mte_check(env, desc, ptr, GETPC());
|
||||
}
|
||||
|
||||
/*
|
||||
* No-fault version of mte_check, to be used by SVE for MemSingleNF.
|
||||
* Returns false if the access is Checked and the check failed. This
|
||||
* is only intended to probe the tag -- the validity of the page must
|
||||
* be checked beforehand.
|
||||
*/
|
||||
bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr)
|
||||
{
|
||||
uint64_t fault;
|
||||
int ret = mte_probe_int(env, desc, ptr, 0, &fault);
|
||||
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -46,7 +46,7 @@ VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \
|
||||
|
||||
VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \
|
||||
vd=%vd_dp size=0 stride=1
|
||||
VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 align:2 rm:4 \
|
||||
VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 . align:1 rm:4 \
|
||||
vd=%vd_dp size=1 stride=%imm1_5_p1
|
||||
VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 align:3 rm:4 \
|
||||
VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 . align:2 rm:4 \
|
||||
vd=%vd_dp size=2 stride=%imm1_6_p1
|
||||
|
||||
+34
-66
@@ -4382,13 +4382,9 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef uint64_t mte_check_fn(CPUARMState *, uint32_t, uint64_t, uintptr_t);
|
||||
|
||||
static inline QEMU_ALWAYS_INLINE
|
||||
void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr, int esize,
|
||||
int msize, uint32_t mtedesc, uintptr_t ra,
|
||||
mte_check_fn *check)
|
||||
static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr, int esize,
|
||||
int msize, uint32_t mtedesc, uintptr_t ra)
|
||||
{
|
||||
intptr_t mem_off, reg_off, reg_last;
|
||||
|
||||
@@ -4405,7 +4401,7 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t pg = vg[reg_off >> 6];
|
||||
do {
|
||||
if ((pg >> (reg_off & 63)) & 1) {
|
||||
check(env, mtedesc, addr, ra);
|
||||
mte_check(env, mtedesc, addr, ra);
|
||||
}
|
||||
reg_off += esize;
|
||||
mem_off += msize;
|
||||
@@ -4422,7 +4418,7 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t pg = vg[reg_off >> 6];
|
||||
do {
|
||||
if ((pg >> (reg_off & 63)) & 1) {
|
||||
check(env, mtedesc, addr, ra);
|
||||
mte_check(env, mtedesc, addr, ra);
|
||||
}
|
||||
reg_off += esize;
|
||||
mem_off += msize;
|
||||
@@ -4431,30 +4427,6 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env,
|
||||
}
|
||||
}
|
||||
|
||||
typedef void sve_cont_ldst_mte_check_fn(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, uint32_t mtedesc,
|
||||
uintptr_t ra);
|
||||
|
||||
static void sve_cont_ldst_mte_check1(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, uint32_t mtedesc,
|
||||
uintptr_t ra)
|
||||
{
|
||||
sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize,
|
||||
mtedesc, ra, mte_check1);
|
||||
}
|
||||
|
||||
static void sve_cont_ldst_mte_checkN(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, uint32_t mtedesc,
|
||||
uintptr_t ra)
|
||||
{
|
||||
sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize,
|
||||
mtedesc, ra, mte_checkN);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Common helper for all contiguous 1,2,3,4-register predicated stores.
|
||||
*/
|
||||
@@ -4463,8 +4435,7 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
|
||||
uint32_t desc, const uintptr_t retaddr,
|
||||
const int esz, const int msz, const int N, uint32_t mtedesc,
|
||||
sve_ldst1_host_fn *host_fn,
|
||||
sve_ldst1_tlb_fn *tlb_fn,
|
||||
sve_cont_ldst_mte_check_fn *mte_check_fn)
|
||||
sve_ldst1_tlb_fn *tlb_fn)
|
||||
{
|
||||
const unsigned rd = simd_data(desc);
|
||||
const intptr_t reg_max = simd_oprsz(desc);
|
||||
@@ -4493,9 +4464,9 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
|
||||
* Handle mte checks for all active elements.
|
||||
* Since TBI must be set for MTE, !mtedesc => !mte_active.
|
||||
*/
|
||||
if (mte_check_fn && mtedesc) {
|
||||
mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz,
|
||||
mtedesc, retaddr);
|
||||
if (mtedesc) {
|
||||
sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz,
|
||||
mtedesc, retaddr);
|
||||
}
|
||||
|
||||
flags = info.page[0].flags | info.page[1].flags;
|
||||
@@ -4621,8 +4592,7 @@ void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr,
|
||||
mtedesc = 0;
|
||||
}
|
||||
|
||||
sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn,
|
||||
N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN);
|
||||
sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn);
|
||||
}
|
||||
|
||||
#define DO_LD1_1(NAME, ESZ) \
|
||||
@@ -4630,7 +4600,7 @@ void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, 0, \
|
||||
sve_##NAME##_host, sve_##NAME##_tlb, NULL); \
|
||||
sve_##NAME##_host, sve_##NAME##_tlb); \
|
||||
} \
|
||||
void HELPER(sve_##NAME##_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
@@ -4644,22 +4614,22 @@ void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \
|
||||
sve_##NAME##_le_host, sve_##NAME##_le_tlb, NULL); \
|
||||
sve_##NAME##_le_host, sve_##NAME##_le_tlb); \
|
||||
} \
|
||||
void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \
|
||||
sve_##NAME##_be_host, sve_##NAME##_be_tlb, NULL); \
|
||||
sve_##NAME##_be_host, sve_##NAME##_be_tlb); \
|
||||
} \
|
||||
void HELPER(sve_##NAME##_le_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \
|
||||
sve_##NAME##_le_host, sve_##NAME##_le_tlb); \
|
||||
} \
|
||||
void HELPER(sve_##NAME##_be_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \
|
||||
sve_##NAME##_be_host, sve_##NAME##_be_tlb); \
|
||||
@@ -4693,7 +4663,7 @@ void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, 0, \
|
||||
sve_ld1bb_host, sve_ld1bb_tlb, NULL); \
|
||||
sve_ld1bb_host, sve_ld1bb_tlb); \
|
||||
} \
|
||||
void HELPER(sve_ld##N##bb_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
@@ -4707,13 +4677,13 @@ void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \
|
||||
sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb, NULL); \
|
||||
sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \
|
||||
} \
|
||||
void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \
|
||||
sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb, NULL); \
|
||||
sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \
|
||||
} \
|
||||
void HELPER(sve_ld##N##SUFF##_le_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
@@ -4826,7 +4796,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
|
||||
if (fault == FAULT_FIRST) {
|
||||
/* Trapping mte check for the first-fault element. */
|
||||
if (mtedesc) {
|
||||
mte_check1(env, mtedesc, addr + mem_off, retaddr);
|
||||
mte_check(env, mtedesc, addr + mem_off, retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4869,7 +4839,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
|
||||
/* Watchpoint hit, see below. */
|
||||
goto do_fault;
|
||||
}
|
||||
if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) {
|
||||
if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) {
|
||||
goto do_fault;
|
||||
}
|
||||
/*
|
||||
@@ -4919,7 +4889,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
|
||||
& BP_MEM_READ)) {
|
||||
goto do_fault;
|
||||
}
|
||||
if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) {
|
||||
if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) {
|
||||
goto do_fault;
|
||||
}
|
||||
host_fn(vd, reg_off, host + mem_off);
|
||||
@@ -5090,8 +5060,7 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
|
||||
uint32_t desc, const uintptr_t retaddr,
|
||||
const int esz, const int msz, const int N, uint32_t mtedesc,
|
||||
sve_ldst1_host_fn *host_fn,
|
||||
sve_ldst1_tlb_fn *tlb_fn,
|
||||
sve_cont_ldst_mte_check_fn *mte_check_fn)
|
||||
sve_ldst1_tlb_fn *tlb_fn)
|
||||
{
|
||||
const unsigned rd = simd_data(desc);
|
||||
const intptr_t reg_max = simd_oprsz(desc);
|
||||
@@ -5117,9 +5086,9 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
|
||||
* Handle mte checks for all active elements.
|
||||
* Since TBI must be set for MTE, !mtedesc => !mte_active.
|
||||
*/
|
||||
if (mte_check_fn && mtedesc) {
|
||||
mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz,
|
||||
mtedesc, retaddr);
|
||||
if (mtedesc) {
|
||||
sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz,
|
||||
mtedesc, retaddr);
|
||||
}
|
||||
|
||||
flags = info.page[0].flags | info.page[1].flags;
|
||||
@@ -5233,8 +5202,7 @@ void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr,
|
||||
mtedesc = 0;
|
||||
}
|
||||
|
||||
sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn,
|
||||
N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN);
|
||||
sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn);
|
||||
}
|
||||
|
||||
#define DO_STN_1(N, NAME, ESZ) \
|
||||
@@ -5242,7 +5210,7 @@ void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, 0, \
|
||||
sve_st1##NAME##_host, sve_st1##NAME##_tlb, NULL); \
|
||||
sve_st1##NAME##_host, sve_st1##NAME##_tlb); \
|
||||
} \
|
||||
void HELPER(sve_st##N##NAME##_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
@@ -5256,13 +5224,13 @@ void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \
|
||||
sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb, NULL); \
|
||||
sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \
|
||||
} \
|
||||
void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
{ \
|
||||
sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \
|
||||
sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb, NULL); \
|
||||
sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \
|
||||
} \
|
||||
void HELPER(sve_st##N##NAME##_le_r_mte)(CPUARMState *env, void *vg, \
|
||||
target_ulong addr, uint32_t desc) \
|
||||
@@ -5373,7 +5341,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
info.attrs, BP_MEM_READ, retaddr);
|
||||
}
|
||||
if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
|
||||
mte_check1(env, mtedesc, addr, retaddr);
|
||||
mte_check(env, mtedesc, addr, retaddr);
|
||||
}
|
||||
host_fn(&scratch, reg_off, info.host);
|
||||
} else {
|
||||
@@ -5386,7 +5354,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
BP_MEM_READ, retaddr);
|
||||
}
|
||||
if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
|
||||
mte_check1(env, mtedesc, addr, retaddr);
|
||||
mte_check(env, mtedesc, addr, retaddr);
|
||||
}
|
||||
tlb_fn(env, &scratch, reg_off, addr, retaddr);
|
||||
}
|
||||
@@ -5552,7 +5520,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
*/
|
||||
addr = base + (off_fn(vm, reg_off) << scale);
|
||||
if (mtedesc) {
|
||||
mte_check1(env, mtedesc, addr, retaddr);
|
||||
mte_check(env, mtedesc, addr, retaddr);
|
||||
}
|
||||
tlb_fn(env, vd, reg_off, addr, retaddr);
|
||||
|
||||
@@ -5588,7 +5556,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
}
|
||||
if (mtedesc &&
|
||||
arm_tlb_mte_tagged(&info.attrs) &&
|
||||
!mte_probe1(env, mtedesc, addr)) {
|
||||
!mte_probe(env, mtedesc, addr)) {
|
||||
goto fault;
|
||||
}
|
||||
|
||||
@@ -5773,7 +5741,7 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
}
|
||||
|
||||
if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
|
||||
mte_check1(env, mtedesc, addr, retaddr);
|
||||
mte_check(env, mtedesc, addr, retaddr);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user