target-arm queue:
* target/arm: Declare support for FEAT_RASv1p1 * target/arm: Implement FEAT_DoubleFault * Fix 'writeable' typos * xlnx_dp: Implement vblank interrupt * target/arm: Move page-table-walk code to ptw.c * target/arm: Preparatory patches for SME support -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmKht40ZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3p/hEACkUlUhKStyMCimLZJQ2wfG rBO6zHPNVDWtWqUy/1e5HgeU6HXqk0TXLGIbk+6/2y1wos2KGHPOIjIw0miPuZF9 tsVvwjKlnOPecJc5tm3vxPswBK29Rp7BtNTIXSlGOcByOK1L94ern5pi29QK1ltm rZ8vbzJTJ58vCTUkYjcnIeLWAWzgiEgVdEWwl7+3dGIr0x9uawfku/eFd0zFb5+v TtBUz0d92te7SehtiGI9CbdQnxvSOLV/3LbAhPhG8G4tG5YwxW7aQbT/YnBVLqek CiLuN9/Wib7UYkYpeP1dAGhqMmPmIxrwCuxFMXhzARiiyLSKZhBHRCOv5WF8wkL5 F7j+Cx8v+A6wUQBx09Oxb9mK6EDcjiaaSqlDSoq4WvvUWVphugFyoypKTa8XZM8H qrs+jOyODFeRz6QOiei2FG0eswvSDIFMZt8mtFC5vutSSzIaGmD/yCDU/oMfoFwC r7O85dVhhDnyagmp1wnQaePSehoekcnN87A4Zego/LM6sGua+3GYMR5qnKnMsKgr wSJ8nPHGK30et4qfCqdYH0FK2EoRwTc/17C5FXV5FiMXQuEPuyMRqrUFj8Iv4AZc MqvNfJvDHS6ZXrZv4a9rFY/LkOfupC/Zsd+p3QoT3CTicebaxEr/6TTOR9vFvw3k InzNe4cc9Be4TtyamRA1mA== =a85M -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20220609' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * target/arm: Declare support for FEAT_RASv1p1 * target/arm: Implement FEAT_DoubleFault * Fix 'writeable' typos * xlnx_dp: Implement vblank interrupt * target/arm: Move page-table-walk code to ptw.c * target/arm: Preparatory patches for SME support # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmKht40ZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3p/hEACkUlUhKStyMCimLZJQ2wfG # rBO6zHPNVDWtWqUy/1e5HgeU6HXqk0TXLGIbk+6/2y1wos2KGHPOIjIw0miPuZF9 # tsVvwjKlnOPecJc5tm3vxPswBK29Rp7BtNTIXSlGOcByOK1L94ern5pi29QK1ltm # rZ8vbzJTJ58vCTUkYjcnIeLWAWzgiEgVdEWwl7+3dGIr0x9uawfku/eFd0zFb5+v # TtBUz0d92te7SehtiGI9CbdQnxvSOLV/3LbAhPhG8G4tG5YwxW7aQbT/YnBVLqek # CiLuN9/Wib7UYkYpeP1dAGhqMmPmIxrwCuxFMXhzARiiyLSKZhBHRCOv5WF8wkL5 # F7j+Cx8v+A6wUQBx09Oxb9mK6EDcjiaaSqlDSoq4WvvUWVphugFyoypKTa8XZM8H # qrs+jOyODFeRz6QOiei2FG0eswvSDIFMZt8mtFC5vutSSzIaGmD/yCDU/oMfoFwC # r7O85dVhhDnyagmp1wnQaePSehoekcnN87A4Zego/LM6sGua+3GYMR5qnKnMsKgr # wSJ8nPHGK30et4qfCqdYH0FK2EoRwTc/17C5FXV5FiMXQuEPuyMRqrUFj8Iv4AZc # MqvNfJvDHS6ZXrZv4a9rFY/LkOfupC/Zsd+p3QoT3CTicebaxEr/6TTOR9vFvw3k # InzNe4cc9Be4TtyamRA1mA== # =a85M # -----END PGP SIGNATURE----- # gpg: Signature made Thu 09 Jun 2022 02:04:13 AM PDT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] * tag 'pull-target-arm-20220609' of https://git.linaro.org/people/pmaydell/qemu-arm: (55 commits) target/arm: Add ID_AA64SMFR0_EL1 target/arm: Add isar_feature_aa64_sme target/arm: Export bfdotadd from vec_helper.c target/arm: Move expand_pred_h to vec_internal.h target/arm: Use expand_pred_b in mve_helper.c target/arm: Move expand_pred_b to vec_internal.h target/arm: Export sve contiguous ldst support functions target/arm: Split out load/store primitives to sve_ldst_internal.h target/arm: Rename sve_zcr_len_for_el to sve_vqm1_for_el target/arm: Use uint32_t instead of bitmap for sve vq's target/arm: Merge aarch64_sve_zcr_get_valid_len into caller target/arm: Do not use aarch64_sve_zcr_get_valid_len in reset target/arm: Hoist arm_is_el2_enabled check in sve_exception_el target/arm: Use el_is_in_host for sve_exception_el target/arm: Use el_is_in_host for sve_zcr_len_for_el target/arm: Add el_is_in_host target/arm: Remove fp checks from sve_exception_el target/arm: Remove route_to_el2 check from sve_exception_el linux-user/aarch64: Introduce sve_vq target/arm: Rename TBFLAG_A64 ZCR_LEN to VL ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
028f2361d0
@ -120,12 +120,12 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
||||
{
|
||||
hvf_slot *mem;
|
||||
MemoryRegion *area = section->mr;
|
||||
bool writeable = !area->readonly && !area->rom_device;
|
||||
bool writable = !area->readonly && !area->rom_device;
|
||||
hv_memory_flags_t flags;
|
||||
uint64_t page_size = qemu_real_host_page_size();
|
||||
|
||||
if (!memory_region_is_ram(area)) {
|
||||
if (writeable) {
|
||||
if (writable) {
|
||||
return;
|
||||
} else if (!memory_region_is_romd(area)) {
|
||||
/*
|
||||
|
@ -1346,13 +1346,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
KVMSlot *mem;
|
||||
int err;
|
||||
MemoryRegion *mr = section->mr;
|
||||
bool writeable = !mr->readonly && !mr->rom_device;
|
||||
bool writable = !mr->readonly && !mr->rom_device;
|
||||
hwaddr start_addr, size, slot_size, mr_offset;
|
||||
ram_addr_t ram_start_offset;
|
||||
void *ram;
|
||||
|
||||
if (!memory_region_is_ram(mr)) {
|
||||
if (writeable || !kvm_readonly_mem_allowed) {
|
||||
if (writable || !kvm_readonly_mem_allowed) {
|
||||
return;
|
||||
} else if (!mr->romd_mode) {
|
||||
/* If the memory device is not in romd_mode, then we actually want
|
||||
|
@ -101,10 +101,10 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write)
|
||||
* Return true if the write fault has been handled, and should be re-tried.
|
||||
*
|
||||
* Note that it is important that we don't call page_unprotect() unless
|
||||
* this is really a "write to nonwriteable page" fault, because
|
||||
* this is really a "write to nonwritable page" fault, because
|
||||
* page_unprotect() assumes that if it is called for an access to
|
||||
* a page that's writeable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writeable;
|
||||
* a page that's writable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writable;
|
||||
* so we will retry the access. If we were to call page_unprotect()
|
||||
* for some other kind of fault that should really be passed to the
|
||||
* guest, we'd end up in an infinite loop of retrying the faulting access.
|
||||
|
@ -222,7 +222,7 @@ Virtio device config space
|
||||
:size: a 32-bit configuration space access size in bytes
|
||||
|
||||
:flags: a 32-bit value:
|
||||
- 0: Vhost front-end messages used for writeable fields
|
||||
- 0: Vhost front-end messages used for writable fields
|
||||
- 1: Vhost front-end messages used for live migration
|
||||
|
||||
:payload: Size bytes array holding the contents of the virtio
|
||||
|
@ -153,7 +153,7 @@ change the contents of the memory at runtime, specifically when starting a
|
||||
backed-up or snapshotted image. In order to do this, QEMU must know the
|
||||
address that has been allocated.
|
||||
|
||||
The mechanism chosen for this memory sharing is writeable fw_cfg blobs.
|
||||
The mechanism chosen for this memory sharing is writable fw_cfg blobs.
|
||||
These are data object that are visible to both QEMU and guests, and are
|
||||
addressable as sequential files.
|
||||
|
||||
@ -164,7 +164,7 @@ Two fw_cfg blobs are used in this case:
|
||||
/etc/vmgenid_guid - contains the actual VM Generation ID GUID
|
||||
- read-only to the guest
|
||||
/etc/vmgenid_addr - contains the address of the downloaded vmgenid blob
|
||||
- writeable by the guest
|
||||
- writable by the guest
|
||||
|
||||
|
||||
QEMU sends the following commands to the guest at startup:
|
||||
|
@ -23,6 +23,7 @@ the following architecture extensions:
|
||||
- FEAT_Debugv8p2 (Debug changes for v8.2)
|
||||
- FEAT_Debugv8p4 (Debug changes for v8.4)
|
||||
- FEAT_DotProd (Advanced SIMD dot product instructions)
|
||||
- FEAT_DoubleFault (Double Fault Extension)
|
||||
- FEAT_FCMA (Floating-point complex number instructions)
|
||||
- FEAT_FHM (Floating-point half-precision multiplication instructions)
|
||||
- FEAT_FP16 (Half-precision floating-point data processing)
|
||||
@ -52,6 +53,7 @@ the following architecture extensions:
|
||||
- FEAT_PMUv3p1 (PMU Extensions v3.1)
|
||||
- FEAT_PMUv3p4 (PMU Extensions v3.4)
|
||||
- FEAT_RAS (Reliability, availability, and serviceability)
|
||||
- FEAT_RASv1p1 (RAS Extension v1.1)
|
||||
- FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions)
|
||||
- FEAT_RNG (Random number generator)
|
||||
- FEAT_S2FWB (Stage 2 forced Write-Back)
|
||||
|
@ -249,7 +249,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
|
||||
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
|
||||
/*
|
||||
* Initialize the value of read_ack_register to 1, so GHES can be
|
||||
* writeable after (re)boot.
|
||||
* writable after (re)boot.
|
||||
* ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2
|
||||
* (GHESv2 - Type 10)
|
||||
*/
|
||||
|
@ -60,10 +60,10 @@
|
||||
#define SERDES_SIZE 0x20000
|
||||
|
||||
#define DP_ADDR 0xfd4a0000
|
||||
#define DP_IRQ 113
|
||||
#define DP_IRQ 0x77
|
||||
|
||||
#define DPDMA_ADDR 0xfd4c0000
|
||||
#define DPDMA_IRQ 116
|
||||
#define DPDMA_IRQ 0x7a
|
||||
|
||||
#define APU_ADDR 0xfd5c0000
|
||||
#define APU_IRQ 153
|
||||
|
@ -114,6 +114,7 @@
|
||||
#define DP_TX_N_AUD (0x032C >> 2)
|
||||
#define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2)
|
||||
#define DP_INT_STATUS (0x03A0 >> 2)
|
||||
#define DP_INT_VBLNK_START (1 << 13)
|
||||
#define DP_INT_MASK (0x03A4 >> 2)
|
||||
#define DP_INT_EN (0x03A8 >> 2)
|
||||
#define DP_INT_DS (0x03AC >> 2)
|
||||
@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt;
|
||||
|
||||
static const VMStateDescription vmstate_dp = {
|
||||
.name = TYPE_XLNX_DP,
|
||||
.version_id = 1,
|
||||
.version_id = 2,
|
||||
.fields = (VMStateField[]){
|
||||
VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState,
|
||||
DP_CORE_REG_ARRAY_SIZE),
|
||||
@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = {
|
||||
DP_VBLEND_REG_ARRAY_SIZE),
|
||||
VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState,
|
||||
DP_AUDIO_REG_ARRAY_SIZE),
|
||||
VMSTATE_PTIMER(vblank, XlnxDPState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define DP_VBLANK_PTIMER_POLICY (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \
|
||||
PTIMER_POLICY_CONTINUOUS_TRIGGER | \
|
||||
PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
|
||||
|
||||
static void xlnx_dp_update_irq(XlnxDPState *s);
|
||||
|
||||
static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size)
|
||||
@ -773,6 +779,13 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
break;
|
||||
case DP_TRANSMITTER_ENABLE:
|
||||
s->core_registers[offset] = value & 0x01;
|
||||
ptimer_transaction_begin(s->vblank);
|
||||
if (value & 0x1) {
|
||||
ptimer_run(s->vblank, 0);
|
||||
} else {
|
||||
ptimer_stop(s->vblank);
|
||||
}
|
||||
ptimer_transaction_commit(s->vblank);
|
||||
break;
|
||||
case DP_FORCE_SCRAMBLER_RESET:
|
||||
/*
|
||||
@ -876,7 +889,7 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
xlnx_dp_update_irq(s);
|
||||
break;
|
||||
case DP_INT_DS:
|
||||
s->core_registers[DP_INT_MASK] |= ~value;
|
||||
s->core_registers[DP_INT_MASK] |= value;
|
||||
xlnx_dp_update_irq(s);
|
||||
break;
|
||||
default:
|
||||
@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
s->core_registers[DP_INT_STATUS] |= (1 << 13);
|
||||
xlnx_dp_update_irq(s);
|
||||
|
||||
xlnx_dpdma_trigger_vsync_irq(s->dpdma);
|
||||
|
||||
/*
|
||||
@ -1219,19 +1229,22 @@ static void xlnx_dp_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
XlnxDPState *s = XLNX_DP(obj);
|
||||
|
||||
memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050);
|
||||
memory_region_init(&s->container, obj, TYPE_XLNX_DP, DP_CONTAINER_SIZE);
|
||||
|
||||
memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP
|
||||
".core", 0x3AF);
|
||||
memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem);
|
||||
".core", sizeof(s->core_registers));
|
||||
memory_region_add_subregion(&s->container, DP_CORE_REG_OFFSET,
|
||||
&s->core_iomem);
|
||||
|
||||
memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP
|
||||
".v_blend", 0x1DF);
|
||||
memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem);
|
||||
".v_blend", sizeof(s->vblend_registers));
|
||||
memory_region_add_subregion(&s->container, DP_VBLEND_REG_OFFSET,
|
||||
&s->vblend_iomem);
|
||||
|
||||
memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP
|
||||
".av_buffer_manager", 0x238);
|
||||
memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem);
|
||||
".av_buffer_manager", sizeof(s->avbufm_registers));
|
||||
memory_region_add_subregion(&s->container, DP_AVBUF_REG_OFFSET,
|
||||
&s->avbufm_iomem);
|
||||
|
||||
memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP
|
||||
".audio", sizeof(s->audio_registers));
|
||||
@ -1272,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj)
|
||||
fifo8_destroy(&s->rx_fifo);
|
||||
}
|
||||
|
||||
static void vblank_hit(void *opaque)
|
||||
{
|
||||
XlnxDPState *s = XLNX_DP(opaque);
|
||||
|
||||
s->core_registers[DP_INT_STATUS] |= DP_INT_VBLNK_START;
|
||||
xlnx_dp_update_irq(s);
|
||||
}
|
||||
|
||||
static void xlnx_dp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
XlnxDPState *s = XLNX_DP(dev);
|
||||
@ -1306,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
|
||||
&as);
|
||||
AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
|
||||
xlnx_dp_audio_activate(s);
|
||||
s->vblank = ptimer_init(vblank_hit, s, DP_VBLANK_PTIMER_POLICY);
|
||||
ptimer_transaction_begin(s->vblank);
|
||||
ptimer_set_freq(s->vblank, 30);
|
||||
ptimer_transaction_commit(s->vblank);
|
||||
}
|
||||
|
||||
static void xlnx_dp_reset(DeviceState *dev)
|
||||
|
@ -2047,7 +2047,7 @@ static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR;
|
||||
}
|
||||
|
||||
/* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */
|
||||
/* The only bit stored in icc_ctlr_el3 which is writable is EOIMODE_EL3: */
|
||||
mask = ICC_CTLR_EL3_EOIMODE_EL3;
|
||||
|
||||
cs->icc_ctlr_el3 &= ~mask;
|
||||
|
@ -611,7 +611,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset,
|
||||
if (value & mask & GICD_CTLR_DS) {
|
||||
/* We just set DS, so the ARE_NS and EnG1S bits are now RES0.
|
||||
* Note that this is a one-way transition because if DS is set
|
||||
* then it's not writeable, so it can only go back to 0 with a
|
||||
* then it's not writable, so it can only go back to 0 with a
|
||||
* hardware reset.
|
||||
*/
|
||||
s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS);
|
||||
|
@ -257,7 +257,7 @@ static void gicr_write_vpendbaser(GICv3CPUState *cs, uint64_t newval)
|
||||
|
||||
/*
|
||||
* The DIRTY bit is read-only and for us is always zero;
|
||||
* other fields are writeable.
|
||||
* other fields are writable.
|
||||
*/
|
||||
newval &= R_GICR_VPENDBASER_INNERCACHE_MASK |
|
||||
R_GICR_VPENDBASER_SHAREABILITY_MASK |
|
||||
@ -491,7 +491,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
|
||||
/* RAZ/WI for our implementation */
|
||||
return MEMTX_OK;
|
||||
case GICR_WAKER:
|
||||
/* Only the ProcessorSleep bit is writeable. When the guest sets
|
||||
/* Only the ProcessorSleep bit is writable. When the guest sets
|
||||
* it it requests that we transition the channel between the
|
||||
* redistributor and the cpu interface to quiescent, and that
|
||||
* we set the ChildrenAsleep bit once the inteface has reached the
|
||||
|
@ -463,7 +463,7 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
|
||||
/* Claim software interrupt bits */
|
||||
for (i = 0; i < swi->num_harts; i++) {
|
||||
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i));
|
||||
/* We don't claim mip.SSIP because it is writeable by software */
|
||||
/* We don't claim mip.SSIP because it is writable by software */
|
||||
if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) {
|
||||
error_report("MSIP already claimed");
|
||||
exit(1);
|
||||
|
@ -646,7 +646,7 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
}
|
||||
|
||||
if (addr == APLIC_DOMAINCFG) {
|
||||
/* Only IE bit writeable at the moment */
|
||||
/* Only IE bit writable at the moment */
|
||||
value &= APLIC_DOMAINCFG_IE;
|
||||
aplic->domaincfg = value;
|
||||
} else if ((APLIC_SOURCECFG_BASE <= addr) &&
|
||||
|
@ -456,7 +456,7 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp)
|
||||
pci_set_byte(config + SHPC_CAP_CxP, 0);
|
||||
pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
|
||||
d->shpc->cap = config_offset;
|
||||
/* Make dword select and data writeable. */
|
||||
/* Make dword select and data writable. */
|
||||
pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
|
||||
pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
|
||||
return 0;
|
||||
|
@ -633,7 +633,7 @@ struct mfi_ctrl_props {
|
||||
* metadata and user data
|
||||
* 1=5%, 2=10%, 3=15% and so on
|
||||
*/
|
||||
uint8_t viewSpace; /* snapshot writeable VIEWs
|
||||
uint8_t viewSpace; /* snapshot writable VIEWs
|
||||
* capacity as a % of source LD
|
||||
* capacity. 0=READ only
|
||||
* 1=5%, 2=10%, 3=15% and so on
|
||||
|
@ -165,7 +165,7 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
|
||||
}
|
||||
|
||||
if (tte & IOMMU_TTE_DATA_W) {
|
||||
/* Writeable */
|
||||
/* Writable */
|
||||
ret.perm = IOMMU_RW;
|
||||
} else {
|
||||
ret.perm = IOMMU_RO;
|
||||
|
@ -324,7 +324,7 @@ static void sse_timer_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
{
|
||||
uint32_t old_ctl = s->cntp_aival_ctl;
|
||||
|
||||
/* EN bit is writeable; CLR bit is write-0-to-clear, write-1-ignored */
|
||||
/* EN bit is writable; CLR bit is write-0-to-clear, write-1-ignored */
|
||||
s->cntp_aival_ctl &= ~R_CNTP_AIVAL_CTL_EN_MASK;
|
||||
s->cntp_aival_ctl |= value & R_CNTP_AIVAL_CTL_EN_MASK;
|
||||
if (!(value & R_CNTP_AIVAL_CTL_CLR_MASK)) {
|
||||
|
@ -35,14 +35,20 @@
|
||||
#include "hw/dma/xlnx_dpdma.h"
|
||||
#include "audio/audio.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define AUD_CHBUF_MAX_DEPTH (32 * KiB)
|
||||
#define MAX_QEMU_BUFFER_SIZE (4 * KiB)
|
||||
|
||||
#define DP_CORE_REG_ARRAY_SIZE (0x3AF >> 2)
|
||||
#define DP_CORE_REG_OFFSET (0x0000)
|
||||
#define DP_CORE_REG_ARRAY_SIZE (0x3B0 >> 2)
|
||||
#define DP_AVBUF_REG_OFFSET (0xB000)
|
||||
#define DP_AVBUF_REG_ARRAY_SIZE (0x238 >> 2)
|
||||
#define DP_VBLEND_REG_ARRAY_SIZE (0x1DF >> 2)
|
||||
#define DP_VBLEND_REG_OFFSET (0xA000)
|
||||
#define DP_VBLEND_REG_ARRAY_SIZE (0x1E0 >> 2)
|
||||
#define DP_AUDIO_REG_OFFSET (0xC000)
|
||||
#define DP_AUDIO_REG_ARRAY_SIZE (0x50 >> 2)
|
||||
#define DP_CONTAINER_SIZE (0xC050)
|
||||
|
||||
struct PixmanPlane {
|
||||
pixman_format_code_t format;
|
||||
@ -102,6 +108,8 @@ struct XlnxDPState {
|
||||
*/
|
||||
DPCDState *dpcd;
|
||||
I2CDDCState *edid;
|
||||
|
||||
ptimer_state *vblank;
|
||||
};
|
||||
|
||||
#define TYPE_XLNX_DP "xlnx.v-dp"
|
||||
|
@ -315,7 +315,7 @@ static int target_restore_sigframe(CPUARMState *env,
|
||||
|
||||
case TARGET_SVE_MAGIC:
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
|
||||
vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = sve_vq(env);
|
||||
sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
|
||||
if (!sve && size == sve_size) {
|
||||
sve = (struct target_sve_context *)ctx;
|
||||
@ -434,7 +434,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
|
||||
/* SVE state needs saving only if it exists. */
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
|
||||
vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = sve_vq(env);
|
||||
sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
|
||||
sve_ofs = alloc_sigframe_space(sve_size, &layout);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ static abi_long do_prctl_get_vl(CPUArchState *env)
|
||||
{
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||
return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
|
||||
return sve_vq(env) * 16;
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
@ -25,18 +25,24 @@ static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2)
|
||||
*/
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))
|
||||
&& arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
uint32_t vq, old_vq;
|
||||
|
||||
old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = MAX(arg2 / 16, 1);
|
||||
vq = MIN(vq, cpu->sve_max_vq);
|
||||
old_vq = sve_vq(env);
|
||||
|
||||
/*
|
||||
* Bound the value of arg2, so that we know that it fits into
|
||||
* the 4-bit field in ZCR_EL1. Rely on the hflags rebuild to
|
||||
* sort out the length supported by the cpu.
|
||||
*/
|
||||
vq = MAX(arg2 / 16, 1);
|
||||
vq = MIN(vq, ARM_MAX_VQ);
|
||||
env->vfp.zcr_el[1] = vq - 1;
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
vq = sve_vq(env);
|
||||
if (vq < old_vq) {
|
||||
aarch64_sve_narrow_vq(env, vq);
|
||||
}
|
||||
env->vfp.zcr_el[1] = vq - 1;
|
||||
arm_rebuild_hflags(env);
|
||||
return vq * 16;
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
|
@ -495,7 +495,7 @@ class QEMUMachine:
|
||||
"""
|
||||
# If we keep the console socket open, we may deadlock waiting
|
||||
# for QEMU to exit, while QEMU is waiting for the socket to
|
||||
# become writeable.
|
||||
# become writable.
|
||||
if self._console_socket is not None:
|
||||
self._console_socket.close()
|
||||
self._console_socket = None
|
||||
|
@ -166,7 +166,7 @@ static off_t sve_fpcr_offset(uint32_t vq)
|
||||
|
||||
static uint32_t sve_current_vq(CPUARMState *env)
|
||||
{
|
||||
return sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
|
||||
return sve_vqm1_for_el(env, arm_current_el(env)) + 1;
|
||||
}
|
||||
|
||||
static size_t sve_size_vq(uint32_t vq)
|
||||
|
@ -208,8 +208,7 @@ static void arm_cpu_reset(DeviceState *dev)
|
||||
CPACR_EL1, ZEN, 3);
|
||||
/* with reasonable vector length */
|
||||
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||
env->vfp.zcr_el[1] =
|
||||
aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1);
|
||||
env->vfp.zcr_el[1] = cpu->sve_default_vq - 1;
|
||||
}
|
||||
/*
|
||||
* Enable 48-bit address space (TODO: take reserved_va into account).
|
||||
@ -926,7 +925,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
vfp_get_fpcr(env), vfp_get_fpsr(env));
|
||||
|
||||
if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
|
||||
int j, zcr_len = sve_zcr_len_for_el(env, el);
|
||||
int j, zcr_len = sve_vqm1_for_el(env, el);
|
||||
|
||||
for (i = 0; i <= FFR_PRED_NUM; i++) {
|
||||
bool eol;
|
||||
|
@ -966,6 +966,7 @@ struct ArchCPU {
|
||||
uint64_t id_aa64dfr0;
|
||||
uint64_t id_aa64dfr1;
|
||||
uint64_t id_aa64zfr0;
|
||||
uint64_t id_aa64smfr0;
|
||||
uint64_t reset_pmcr_el0;
|
||||
} isar;
|
||||
uint64_t midr;
|
||||
@ -1041,9 +1042,9 @@ struct ArchCPU {
|
||||
* Bits set in sve_vq_supported represent valid vector lengths for
|
||||
* the CPU type.
|
||||
*/
|
||||
DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
|
||||
DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
|
||||
DECLARE_BITMAP(sve_vq_supported, ARM_MAX_VQ);
|
||||
uint32_t sve_vq_map;
|
||||
uint32_t sve_vq_init;
|
||||
uint32_t sve_vq_supported;
|
||||
|
||||
/* Generic timer counter frequency, in Hz */
|
||||
uint64_t gt_cntfrq_hz;
|
||||
@ -1132,7 +1133,16 @@ void aarch64_sync_64_to_32(CPUARMState *env);
|
||||
|
||||
int fp_exception_el(CPUARMState *env, int cur_el);
|
||||
int sve_exception_el(CPUARMState *env, int cur_el);
|
||||
uint32_t sve_zcr_len_for_el(CPUARMState *env, int el);
|
||||
|
||||
/**
|
||||
* sve_vqm1_for_el:
|
||||
* @env: CPUARMState
|
||||
* @el: exception level
|
||||
*
|
||||
* Compute the current SVE vector length for @el, in units of
|
||||
* Quadwords Minus 1 -- the same scale used for ZCR_ELx.LEN.
|
||||
*/
|
||||
uint32_t sve_vqm1_for_el(CPUARMState *env, int el);
|
||||
|
||||
static inline bool is_a64(CPUARMState *env)
|
||||
{
|
||||
@ -2181,6 +2191,15 @@ FIELD(ID_AA64ZFR0, I8MM, 44, 4)
|
||||
FIELD(ID_AA64ZFR0, F32MM, 52, 4)
|
||||
FIELD(ID_AA64ZFR0, F64MM, 56, 4)
|
||||
|
||||
FIELD(ID_AA64SMFR0, F32F32, 32, 1)
|
||||
FIELD(ID_AA64SMFR0, B16F32, 34, 1)
|
||||
FIELD(ID_AA64SMFR0, F16F32, 35, 1)
|
||||
FIELD(ID_AA64SMFR0, I8I32, 36, 4)
|
||||
FIELD(ID_AA64SMFR0, F64F64, 48, 1)
|
||||
FIELD(ID_AA64SMFR0, I16I64, 52, 4)
|
||||
FIELD(ID_AA64SMFR0, SMEVER, 56, 4)
|
||||
FIELD(ID_AA64SMFR0, FA64, 63, 1)
|
||||
|
||||
FIELD(ID_DFR0, COPDBG, 0, 4)
|
||||
FIELD(ID_DFR0, COPSDBG, 4, 4)
|
||||
FIELD(ID_DFR0, MMAPDBG, 8, 4)
|
||||
@ -3241,7 +3260,8 @@ FIELD(TBFLAG_M32, MVE_NO_PRED, 5, 1) /* Not cached. */
|
||||
*/
|
||||
FIELD(TBFLAG_A64, TBII, 0, 2)
|
||||
FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
|
||||
FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
|
||||
/* The current vector length, either NVL or SVL. */
|
||||
FIELD(TBFLAG_A64, VL, 4, 4)
|
||||
FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1)
|
||||
FIELD(TBFLAG_A64, BT, 9, 1)
|
||||
FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */
|
||||
@ -3285,6 +3305,17 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
|
||||
return EX_TBFLAG_ANY(env->hflags, MMUIDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* sve_vq
|
||||
* @env: the cpu context
|
||||
*
|
||||
* Return the VL cached within env->hflags, in units of quadwords.
|
||||
*/
|
||||
static inline int sve_vq(CPUARMState *env)
|
||||
{
|
||||
return EX_TBFLAG_A64(env->hflags, VL) + 1;
|
||||
}
|
||||
|
||||
static inline bool bswap_code(bool sctlr_b)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@ -3952,6 +3983,11 @@ static inline bool isar_feature_aa64_ras(const ARMISARegisters *id)
|
||||
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
|
||||
@ -4022,6 +4058,11 @@ static inline bool isar_feature_aa64_mte(const ARMISARegisters *id)
|
||||
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_sme(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
|
||||
@ -4164,6 +4205,21 @@ static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id)
|
||||
return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64);
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Feature tests for "does this exist in either 32-bit or 64-bit?"
|
||||
*/
|
||||
|
@ -355,8 +355,11 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
* any of the above. Finally, if SVE is not disabled, then at least one
|
||||
* vector length must be enabled.
|
||||
*/
|
||||
DECLARE_BITMAP(tmp, ARM_MAX_VQ);
|
||||
uint32_t vq, max_vq = 0;
|
||||
uint32_t vq_map = cpu->sve_vq_map;
|
||||
uint32_t vq_init = cpu->sve_vq_init;
|
||||
uint32_t vq_supported;
|
||||
uint32_t vq_mask = 0;
|
||||
uint32_t tmp, vq, max_vq = 0;
|
||||
|
||||
/*
|
||||
* CPU models specify a set of supported vector lengths which are
|
||||
@ -364,10 +367,16 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
* in the supported bitmap results in an error. When KVM is enabled we
|
||||
* fetch the supported bitmap from the host.
|
||||
*/
|
||||
if (kvm_enabled() && kvm_arm_sve_supported()) {
|
||||
kvm_arm_sve_get_vls(CPU(cpu), cpu->sve_vq_supported);
|
||||
} else if (kvm_enabled()) {
|
||||
assert(!cpu_isar_feature(aa64_sve, cpu));
|
||||
if (kvm_enabled()) {
|
||||
if (kvm_arm_sve_supported()) {
|
||||
cpu->sve_vq_supported = kvm_arm_sve_get_vls(CPU(cpu));
|
||||
vq_supported = cpu->sve_vq_supported;
|
||||
} else {
|
||||
assert(!cpu_isar_feature(aa64_sve, cpu));
|
||||
vq_supported = 0;
|
||||
}
|
||||
} else {
|
||||
vq_supported = cpu->sve_vq_supported;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -375,8 +384,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
* From the properties, sve_vq_map<N> implies sve_vq_init<N>.
|
||||
* Check first for any sve<N> enabled.
|
||||
*/
|
||||
if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
|
||||
max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
|
||||
if (vq_map != 0) {
|
||||
max_vq = 32 - clz32(vq_map);
|
||||
vq_mask = MAKE_64BIT_MASK(0, max_vq);
|
||||
|
||||
if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
|
||||
error_setg(errp, "cannot enable sve%d", max_vq * 128);
|
||||
@ -392,15 +402,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
* For KVM we have to automatically enable all supported unitialized
|
||||
* lengths, even when the smaller lengths are not all powers-of-two.
|
||||
*/
|
||||
bitmap_andnot(tmp, cpu->sve_vq_supported, cpu->sve_vq_init, max_vq);
|
||||
bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
|
||||
vq_map |= vq_supported & ~vq_init & vq_mask;
|
||||
} else {
|
||||
/* Propagate enabled bits down through required powers-of-two. */
|
||||
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
|
||||
if (!test_bit(vq - 1, cpu->sve_vq_init)) {
|
||||
set_bit(vq - 1, cpu->sve_vq_map);
|
||||
}
|
||||
}
|
||||
vq_map |= SVE_VQ_POW2_MAP & ~vq_init & vq_mask;
|
||||
}
|
||||
} else if (cpu->sve_max_vq == 0) {
|
||||
/*
|
||||
@ -413,25 +418,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* Disabling a supported length disables all larger lengths. */
|
||||
for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
|
||||
if (test_bit(vq - 1, cpu->sve_vq_init) &&
|
||||
test_bit(vq - 1, cpu->sve_vq_supported)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp = vq_init & vq_supported;
|
||||
} else {
|
||||
/* Disabling a power-of-two disables all larger lengths. */
|
||||
for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) {
|
||||
if (test_bit(vq - 1, cpu->sve_vq_init)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp = vq_init & SVE_VQ_POW2_MAP;
|
||||
}
|
||||
vq = ctz32(tmp) + 1;
|
||||
|
||||
max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
|
||||
bitmap_andnot(cpu->sve_vq_map, cpu->sve_vq_supported,
|
||||
cpu->sve_vq_init, max_vq);
|
||||
if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
|
||||
vq_mask = MAKE_64BIT_MASK(0, max_vq);
|
||||
vq_map = vq_supported & ~vq_init & vq_mask;
|
||||
|
||||
if (max_vq == 0 || vq_map == 0) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "Disabling sve%d results in all "
|
||||
"vector lengths being disabled.\n",
|
||||
@ -441,7 +439,8 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
|
||||
max_vq = 32 - clz32(vq_map);
|
||||
vq_mask = MAKE_64BIT_MASK(0, max_vq);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -451,9 +450,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
*/
|
||||
if (cpu->sve_max_vq != 0) {
|
||||
max_vq = cpu->sve_max_vq;
|
||||
vq_mask = MAKE_64BIT_MASK(0, max_vq);
|
||||
|
||||
if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
|
||||
test_bit(max_vq - 1, cpu->sve_vq_init)) {
|
||||
if (vq_init & ~vq_map & (1 << (max_vq - 1))) {
|
||||
error_setg(errp, "cannot disable sve%d", max_vq * 128);
|
||||
error_append_hint(errp, "The maximum vector length must be "
|
||||
"enabled, sve-max-vq=%d (%d bits)\n",
|
||||
@ -462,8 +461,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
}
|
||||
|
||||
/* Set all bits not explicitly set within sve-max-vq. */
|
||||
bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
|
||||
bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
|
||||
vq_map |= ~vq_init & vq_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -472,13 +470,14 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
* are clear, just in case anybody looks.
|
||||
*/
|
||||
assert(max_vq != 0);
|
||||
bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
|
||||
assert(vq_mask != 0);
|
||||
vq_map &= vq_mask;
|
||||
|
||||
/* Ensure the set of lengths matches what is supported. */
|
||||
bitmap_xor(tmp, cpu->sve_vq_map, cpu->sve_vq_supported, max_vq);
|
||||
if (!bitmap_empty(tmp, max_vq)) {
|
||||
vq = find_last_bit(tmp, max_vq) + 1;
|
||||
if (test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
tmp = vq_map ^ (vq_supported & vq_mask);
|
||||
if (tmp) {
|
||||
vq = 32 - clz32(tmp);
|
||||
if (vq_map & (1 << (vq - 1))) {
|
||||
if (cpu->sve_max_vq) {
|
||||
error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq);
|
||||
error_append_hint(errp, "This CPU does not support "
|
||||
@ -502,15 +501,15 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
return;
|
||||
} else {
|
||||
/* Ensure all required powers-of-two are enabled. */
|
||||
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
|
||||
if (!test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "sve%d is required as it "
|
||||
"is a power-of-two length smaller "
|
||||
"than the maximum, sve%d\n",
|
||||
vq * 128, max_vq * 128);
|
||||
return;
|
||||
}
|
||||
tmp = SVE_VQ_POW2_MAP & vq_mask & ~vq_map;
|
||||
if (tmp) {
|
||||
vq = 32 - clz32(tmp);
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "sve%d is required as it "
|
||||
"is a power-of-two length smaller "
|
||||
"than the maximum, sve%d\n",
|
||||
vq * 128, max_vq * 128);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -530,6 +529,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
||||
|
||||
/* From now on sve_max_vq is the actual maximum supported length. */
|
||||
cpu->sve_max_vq = max_vq;
|
||||
cpu->sve_vq_map = vq_map;
|
||||
}
|
||||
|
||||
static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
|
||||
@ -590,7 +590,7 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
|
||||
if (!cpu_isar_feature(aa64_sve, cpu)) {
|
||||
value = false;
|
||||
} else {
|
||||
value = test_bit(vq - 1, cpu->sve_vq_map);
|
||||
value = extract32(cpu->sve_vq_map, vq - 1, 1);
|
||||
}
|
||||
visit_type_bool(v, name, &value, errp);
|
||||
}
|
||||
@ -612,12 +612,8 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
set_bit(vq - 1, cpu->sve_vq_map);
|
||||
} else {
|
||||
clear_bit(vq - 1, cpu->sve_vq_map);
|
||||
}
|
||||
set_bit(vq - 1, cpu->sve_vq_init);
|
||||
cpu->sve_vq_map = deposit32(cpu->sve_vq_map, vq - 1, 1, value);
|
||||
cpu->sve_vq_init |= 1 << (vq - 1);
|
||||
}
|
||||
|
||||
static bool cpu_arm_get_sve(Object *obj, Error **errp)
|
||||
@ -899,7 +895,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||
t = cpu->isar.id_aa64pfr0;
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, RAS, 1); /* FEAT_RAS */
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */
|
||||
@ -916,6 +912,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||
* we do for EL2 with the virtualization=on property.
|
||||
*/
|
||||
t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */
|
||||
t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */
|
||||
t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
|
||||
cpu->isar.id_aa64pfr1 = t;
|
||||
|
||||
@ -978,7 +975,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||
cpu->dcz_blocksize = 7; /* 512 bytes */
|
||||
#endif
|
||||
|
||||
bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ);
|
||||
cpu->sve_vq_supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ);
|
||||
|
||||
aarch64_add_pauth_properties(obj);
|
||||
aarch64_add_sve_properties(obj);
|
||||
@ -1025,12 +1022,11 @@ static void aarch64_a64fx_initfn(Object *obj)
|
||||
cpu->gic_vprebits = 5;
|
||||
cpu->gic_pribits = 5;
|
||||
|
||||
/* Suppport of A64FX's vector length are 128,256 and 512bit only */
|
||||
/* The A64FX supports only 128, 256 and 512 bit vector lengths */
|
||||
aarch64_add_sve_properties(obj);
|
||||
bitmap_zero(cpu->sve_vq_supported, ARM_MAX_VQ);
|
||||
set_bit(0, cpu->sve_vq_supported); /* 128bit */
|
||||
set_bit(1, cpu->sve_vq_supported); /* 256bit */
|
||||
set_bit(3, cpu->sve_vq_supported); /* 512bit */
|
||||
cpu->sve_vq_supported = (1 << 0) /* 128bit */
|
||||
| (1 << 1) /* 256bit */
|
||||
| (1 << 3); /* 512bit */
|
||||
|
||||
cpu->isar.reset_pmcr_el0 = 0x46014040;
|
||||
|
||||
|
@ -118,7 +118,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
/*
|
||||
* Don't allow writing to XPSR.Exception as it can cause
|
||||
* a transition into or out of handler mode (it's not
|
||||
* writeable via the MSR insn so this is a reasonable
|
||||
* writable via the MSR insn so this is a reasonable
|
||||
* restriction). Other fields are safe to update.
|
||||
*/
|
||||
xpsr_write(env, tmp, ~XPSR_EXCP);
|
||||
|
@ -152,7 +152,7 @@ int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
|
||||
* We report in Vector Granules (VG) which is 64bit in a Z reg
|
||||
* while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
|
||||
*/
|
||||
int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
|
||||
int vq = sve_vqm1_for_el(env, arm_current_el(env)) + 1;
|
||||
return gdb_get_reg64(buf, vq * 2);
|
||||
}
|
||||
default:
|
||||
|
2742
target/arm/helper.c
2742
target/arm/helper.c
File diff suppressed because it is too large
Load Diff
@ -978,8 +978,8 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
|
||||
}
|
||||
}
|
||||
|
||||
env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK;
|
||||
env->cp15.c9_pmcr |= (val & PMCR_WRITEABLE_MASK);
|
||||
env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK;
|
||||
env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK);
|
||||
|
||||
pmu_op_finish(env);
|
||||
break;
|
||||
|
@ -189,17 +189,6 @@ void arm_translate_init(void);
|
||||
void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb);
|
||||
#endif /* CONFIG_TCG */
|
||||
|
||||
/**
|
||||
* aarch64_sve_zcr_get_valid_len:
|
||||
* @cpu: cpu context
|
||||
* @start_len: maximum len to consider
|
||||
*
|
||||
* Return the maximum supported sve vector length <= @start_len.
|
||||
* Note that both @start_len and the return value are in units
|
||||
* of ZCR_ELx.LEN, so the vector bit length is (x + 1) * 128.
|
||||
*/
|
||||
uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len);
|
||||
|
||||
enum arm_fprounding {
|
||||
FPROUNDING_TIEEVEN,
|
||||
FPROUNDING_POSINF,
|
||||
@ -613,8 +602,13 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
|
||||
/* Return the MMU index for a v7M CPU in the specified security state */
|
||||
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
|
||||
|
||||
/* Return true if the stage 1 translation regime is using LPAE format page
|
||||
* tables */
|
||||
/* Return true if the translation regime is using LPAE format page tables */
|
||||
bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
|
||||
|
||||
/*
|
||||
* Return true if the stage 1 translation regime is using LPAE
|
||||
* format page tables
|
||||
*/
|
||||
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
|
||||
|
||||
/* Raise a data fault alignment exception for the specified virtual address */
|
||||
@ -777,6 +771,12 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the SCTLR value which controls this address translation regime */
|
||||
static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
return env->cp15.sctlr_el[regime_el(env, mmu_idx)];
|
||||
}
|
||||
|
||||
/* Return the TCR controlling this translation regime */
|
||||
static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
@ -979,11 +979,16 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env);
|
||||
* Return the ARMMMUIdx for the stage1 traversal for the current regime.
|
||||
*/
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
|
||||
{
|
||||
return ARMMMUIdx_Stage1_E0;
|
||||
}
|
||||
static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
|
||||
{
|
||||
return ARMMMUIdx_Stage1_E0;
|
||||
}
|
||||
#else
|
||||
ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx);
|
||||
ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
|
||||
#endif
|
||||
|
||||
@ -1090,6 +1095,9 @@ typedef struct ARMVAParameters {
|
||||
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx, bool data);
|
||||
|
||||
int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx);
|
||||
int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx);
|
||||
|
||||
static inline int exception_target_el(CPUARMState *env)
|
||||
{
|
||||
int target_el = MAX(1, arm_current_el(env));
|
||||
@ -1280,10 +1288,10 @@ enum MVEECIState {
|
||||
#define PMCRP 0x2
|
||||
#define PMCRE 0x1
|
||||
/*
|
||||
* Mask of PMCR bits writeable by guest (not including WO bits like C, P,
|
||||
* Mask of PMCR bits writable by guest (not including WO bits like C, P,
|
||||
* which can be written as 1 to trigger behaviour but which stay RAZ).
|
||||
*/
|
||||
#define PMCR_WRITEABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE)
|
||||
#define PMCR_WRITABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE)
|
||||
|
||||
#define PMXEVTYPER_P 0x80000000
|
||||
#define PMXEVTYPER_U 0x40000000
|
||||
@ -1328,6 +1336,13 @@ static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { }
|
||||
void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu);
|
||||
#endif
|
||||
|
||||
bool el_is_in_host(CPUARMState *env, int el);
|
||||
|
||||
void aa32_max_features(ARMCPU *cpu);
|
||||
|
||||
/* Powers of 2 for sve_vq_map et al. */
|
||||
#define SVE_VQ_POW2_MAP \
|
||||
((1 << (1 - 1)) | (1 << (2 - 1)) | \
|
||||
(1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1)))
|
||||
|
||||
#endif
|
||||
|
@ -574,6 +574,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||
} else {
|
||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
|
||||
ARM64_SYS_REG(3, 0, 0, 4, 1));
|
||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0,
|
||||
ARM64_SYS_REG(3, 0, 0, 4, 5));
|
||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0,
|
||||
ARM64_SYS_REG(3, 0, 0, 5, 0));
|
||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1,
|
||||
@ -682,10 +684,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||
ahcf->isar.id_aa64pfr0 = t;
|
||||
|
||||
/*
|
||||
* Before v5.1, KVM did not support SVE and did not expose
|
||||
* ID_AA64ZFR0_EL1 even as RAZ. After v5.1, KVM still does
|
||||
* not expose the register to "user" requests like this
|
||||
* unless the host supports SVE.
|
||||
* There is a range of kernels between kernel commit 73433762fcae
|
||||
* and f81cb2c3ad41 which have a bug where the kernel doesn't expose
|
||||
* SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled
|
||||
* SVE support, so we only read it here, rather than together with all
|
||||
* the other ID registers earlier.
|
||||
*/
|
||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0,
|
||||
ARM64_SYS_REG(3, 0, 0, 4, 4));
|
||||
@ -760,15 +763,13 @@ bool kvm_arm_steal_time_supported(void)
|
||||
|
||||
QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
|
||||
|
||||
void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
|
||||
uint32_t kvm_arm_sve_get_vls(CPUState *cs)
|
||||
{
|
||||
/* Only call this function if kvm_arm_sve_supported() returns true. */
|
||||
static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
|
||||
static bool probed;
|
||||
uint32_t vq = 0;
|
||||
int i, j;
|
||||
|
||||
bitmap_zero(map, ARM_MAX_VQ);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* KVM ensures all host CPUs support the same set of vector lengths.
|
||||
@ -809,46 +810,24 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
|
||||
if (vq > ARM_MAX_VQ) {
|
||||
warn_report("KVM supports vector lengths larger than "
|
||||
"QEMU can enable");
|
||||
vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) {
|
||||
if (!vls[i]) {
|
||||
continue;
|
||||
}
|
||||
for (j = 1; j <= 64; ++j) {
|
||||
vq = j + i * 64;
|
||||
if (vq > ARM_MAX_VQ) {
|
||||
return;
|
||||
}
|
||||
if (vls[i] & (1UL << (j - 1))) {
|
||||
set_bit(vq - 1, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
return vls[0];
|
||||
}
|
||||
|
||||
static int kvm_arm_sve_set_vls(CPUState *cs)
|
||||
{
|
||||
uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0};
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq_map };
|
||||
struct kvm_one_reg reg = {
|
||||
.id = KVM_REG_ARM64_SVE_VLS,
|
||||
.addr = (uint64_t)&vls[0],
|
||||
};
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
uint32_t vq;
|
||||
int i, j;
|
||||
|
||||
assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
|
||||
|
||||
for (vq = 1; vq <= cpu->sve_max_vq; ++vq) {
|
||||
if (test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
i = (vq - 1) / 64;
|
||||
j = (vq - 1) % 64;
|
||||
vls[i] |= 1UL << j;
|
||||
}
|
||||
}
|
||||
|
||||
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
}
|
||||
|
||||
|
@ -239,13 +239,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
|
||||
/**
|
||||
* kvm_arm_sve_get_vls:
|
||||
* @cs: CPUState
|
||||
* @map: bitmap to fill in
|
||||
*
|
||||
* Get all the SVE vector lengths supported by the KVM host, setting
|
||||
* the bits corresponding to their length in quadwords minus one
|
||||
* (vq - 1) in @map up to ARM_MAX_VQ.
|
||||
* (vq - 1) up to ARM_MAX_VQ. Return the resulting map.
|
||||
*/
|
||||
void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
|
||||
uint32_t kvm_arm_sve_get_vls(CPUState *cs);
|
||||
|
||||
/**
|
||||
* kvm_arm_set_cpu_features_from_host:
|
||||
@ -439,7 +438,7 @@ static inline void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
|
||||
static inline uint32_t kvm_arm_sve_get_vls(CPUState *cs)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ arm_softmmu_ss.add(files(
|
||||
'machine.c',
|
||||
'monitor.c',
|
||||
'psci.c',
|
||||
'ptw.c',
|
||||
))
|
||||
|
||||
subdir('hvf')
|
||||
|
@ -726,7 +726,7 @@ static void mergemask_sb(int8_t *d, int8_t r, uint16_t mask)
|
||||
|
||||
static void mergemask_uh(uint16_t *d, uint16_t r, uint16_t mask)
|
||||
{
|
||||
uint16_t bmask = expand_pred_b_data[mask & 3];
|
||||
uint16_t bmask = expand_pred_b(mask);
|
||||
*d = (*d & ~bmask) | (r & bmask);
|
||||
}
|
||||
|
||||
@ -737,7 +737,7 @@ static void mergemask_sh(int16_t *d, int16_t r, uint16_t mask)
|
||||
|
||||
static void mergemask_uw(uint32_t *d, uint32_t r, uint16_t mask)
|
||||
{
|
||||
uint32_t bmask = expand_pred_b_data[mask & 0xf];
|
||||
uint32_t bmask = expand_pred_b(mask);
|
||||
*d = (*d & ~bmask) | (r & bmask);
|
||||
}
|
||||
|
||||
@ -748,7 +748,7 @@ static void mergemask_sw(int32_t *d, int32_t r, uint16_t mask)
|
||||
|
||||
static void mergemask_uq(uint64_t *d, uint64_t r, uint16_t mask)
|
||||
{
|
||||
uint64_t bmask = expand_pred_b_data[mask & 0xff];
|
||||
uint64_t bmask = expand_pred_b(mask);
|
||||
*d = (*d & ~bmask) | (r & bmask);
|
||||
}
|
||||
|
||||
|
2540
target/arm/ptw.c
Normal file
2540
target/arm/ptw.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,12 +21,12 @@
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "fpu/softfloat.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "vec_internal.h"
|
||||
#include "sve_ldst_internal.h"
|
||||
|
||||
|
||||
/* Return a value for NZCV as per the ARM PredTest pseudofunction.
|
||||
@ -103,44 +103,6 @@ uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words)
|
||||
return flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand active predicate bits to bytes, for byte elements.
|
||||
* (The data table itself is in vec_helper.c as MVE also needs it.)
|
||||
*/
|
||||
static inline uint64_t expand_pred_b(uint8_t byte)
|
||||
{
|
||||
return expand_pred_b_data[byte];
|
||||
}
|
||||
|
||||
/* Similarly for half-word elements.
|
||||
* for (i = 0; i < 256; ++i) {
|
||||
* unsigned long m = 0;
|
||||
* if (i & 0xaa) {
|
||||
* continue;
|
||||
* }
|
||||
* for (j = 0; j < 8; j += 2) {
|
||||
* if ((i >> j) & 1) {
|
||||
* m |= 0xfffful << (j << 3);
|
||||
* }
|
||||
* }
|
||||
* printf("[0x%x] = 0x%016lx,\n", i, m);
|
||||
* }
|
||||
*/
|
||||
static inline uint64_t expand_pred_h(uint8_t byte)
|
||||
{
|
||||
static const uint64_t word[] = {
|
||||
[0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000,
|
||||
[0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000,
|
||||
[0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000,
|
||||
[0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000,
|
||||
[0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000,
|
||||
[0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000,
|
||||
[0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000,
|
||||
[0x55] = 0xffffffffffffffff,
|
||||
};
|
||||
return word[byte & 0x55];
|
||||
}
|
||||
|
||||
/* Similarly for single word elements. */
|
||||
static inline uint64_t expand_pred_s(uint8_t byte)
|
||||
{
|
||||
@ -5301,111 +5263,6 @@ void HELPER(sve_fcmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va,
|
||||
* Load contiguous data, protected by a governing predicate.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Load one element into @vd + @reg_off from @host.
|
||||
* The controlling predicate is known to be true.
|
||||
*/
|
||||
typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host);
|
||||
|
||||
/*
|
||||
* Load one element into @vd + @reg_off from (@env, @vaddr, @ra).
|
||||
* The controlling predicate is known to be true.
|
||||
*/
|
||||
typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off,
|
||||
target_ulong vaddr, uintptr_t retaddr);
|
||||
|
||||
/*
|
||||
* Generate the above primitives.
|
||||
*/
|
||||
|
||||
#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \
|
||||
static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
|
||||
{ \
|
||||
TYPEM val = HOST(host); \
|
||||
*(TYPEE *)(vd + H(reg_off)) = val; \
|
||||
}
|
||||
|
||||
#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \
|
||||
static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
|
||||
{ HOST(host, (TYPEM)*(TYPEE *)(vd + H(reg_off))); }
|
||||
|
||||
#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \
|
||||
static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \
|
||||
target_ulong addr, uintptr_t ra) \
|
||||
{ \
|
||||
*(TYPEE *)(vd + H(reg_off)) = \
|
||||
(TYPEM)TLB(env, useronly_clean_ptr(addr), ra); \
|
||||
}
|
||||
|
||||
#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \
|
||||
static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \
|
||||
target_ulong addr, uintptr_t ra) \
|
||||
{ \
|
||||
TLB(env, useronly_clean_ptr(addr), \
|
||||
(TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \
|
||||
}
|
||||
|
||||
#define DO_LD_PRIM_1(NAME, H, TE, TM) \
|
||||
DO_LD_HOST(NAME, H, TE, TM, ldub_p) \
|
||||
DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra)
|
||||
|
||||
DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t)
|
||||
DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t)
|
||||
DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t)
|
||||
|
||||
#define DO_ST_PRIM_1(NAME, H, TE, TM) \
|
||||
DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \
|
||||
DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra)
|
||||
|
||||
DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t)
|
||||
DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t)
|
||||
DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t)
|
||||
DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t)
|
||||
|
||||
#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \
|
||||
DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \
|
||||
DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \
|
||||
DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \
|
||||
DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra)
|
||||
|
||||
#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \
|
||||
DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \
|
||||
DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \
|
||||
DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \
|
||||
DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra)
|
||||
|
||||
DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw)
|
||||
DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw)
|
||||
|
||||
DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw)
|
||||
DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw)
|
||||
DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw)
|
||||
|
||||
DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl)
|
||||
DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl)
|
||||
DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl)
|
||||
|
||||
DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl)
|
||||
DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl)
|
||||
|
||||
DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq)
|
||||
DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq)
|
||||
|
||||
#undef DO_LD_TLB
|
||||
#undef DO_ST_TLB
|
||||
#undef DO_LD_HOST
|
||||
#undef DO_LD_PRIM_1
|
||||
#undef DO_ST_PRIM_1
|
||||
#undef DO_LD_PRIM_2
|
||||
#undef DO_ST_PRIM_2
|
||||
|
||||
/*
|
||||
* Skip through a sequence of inactive elements in the guarding predicate @vg,
|
||||
* beginning at @reg_off bounded by @reg_max. Return the offset of the active
|
||||
@ -5446,16 +5303,9 @@ static intptr_t find_next_active(uint64_t *vg, intptr_t reg_off,
|
||||
* exit via page fault exception.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
void *host;
|
||||
int flags;
|
||||
MemTxAttrs attrs;
|
||||
} SVEHostPage;
|
||||
|
||||
static bool sve_probe_page(SVEHostPage *info, bool nofault,
|
||||
CPUARMState *env, target_ulong addr,
|
||||
int mem_off, MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
|
||||
target_ulong addr, int mem_off, MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
int flags;
|
||||
|
||||
@ -5511,59 +5361,13 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Analyse contiguous data, protected by a governing predicate.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
FAULT_NO,
|
||||
FAULT_FIRST,
|
||||
FAULT_ALL,
|
||||
} SVEContFault;
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* First and last element wholly contained within the two pages.
|
||||
* mem_off_first[0] and reg_off_first[0] are always set >= 0.
|
||||
* reg_off_last[0] may be < 0 if the first element crosses pages.
|
||||
* All of mem_off_first[1], reg_off_first[1] and reg_off_last[1]
|
||||
* are set >= 0 only if there are complete elements on a second page.
|
||||
*
|
||||
* The reg_off_* offsets are relative to the internal vector register.
|
||||
* The mem_off_first offset is relative to the memory address; the
|
||||
* two offsets are different when a load operation extends, a store
|
||||
* operation truncates, or for multi-register operations.
|
||||
*/
|
||||
int16_t mem_off_first[2];
|
||||
int16_t reg_off_first[2];
|
||||
int16_t reg_off_last[2];
|
||||
|
||||
/*
|
||||
* One element that is misaligned and spans both pages,
|
||||
* or -1 if there is no such active element.
|
||||
*/
|
||||
int16_t mem_off_split;
|
||||
int16_t reg_off_split;
|
||||
|
||||
/*
|
||||
* The byte offset at which the entire operation crosses a page boundary.
|
||||
* Set >= 0 if and only if the entire operation spans two pages.
|
||||
*/
|
||||
int16_t page_split;
|
||||
|
||||
/* TLB data for the two pages. */
|
||||
SVEHostPage page[2];
|
||||
} SVEContLdSt;
|
||||
|
||||
/*
|
||||
* Find first active element on each page, and a loose bound for the
|
||||
* final element on each page. Identify any single element that spans
|
||||
* the page boundary. Return true if there are any active elements.
|
||||
*/
|
||||
static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr,
|
||||
uint64_t *vg, intptr_t reg_max,
|
||||
int esz, int msize)
|
||||
bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg,
|
||||
intptr_t reg_max, int esz, int msize)
|
||||
{
|
||||
const int esize = 1 << esz;
|
||||
const uint64_t pg_mask = pred_esz_masks[esz];
|
||||
@ -5653,9 +5457,9 @@ static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr,
|
||||
* Control the generation of page faults with @fault. Return false if
|
||||
* there is no work to do, which can only happen with @fault == FAULT_NO.
|
||||
*/
|
||||
static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
|
||||
CPUARMState *env, target_ulong addr,
|
||||
MMUAccessType access_type, uintptr_t retaddr)
|
||||
bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
|
||||
CPUARMState *env, target_ulong addr,
|
||||
MMUAccessType access_type, uintptr_t retaddr)
|
||||
{
|
||||
int mmu_idx = cpu_mmu_index(env, false);
|
||||
int mem_off = info->mem_off_first[0];
|
||||
@ -5711,12 +5515,12 @@ static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
|
||||
return have_work;
|
||||
}
|
||||
|
||||
static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, int wp_access,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, int wp_access,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
intptr_t mem_off, reg_off, reg_last;
|
||||
int flags0 = info->page[0].flags;
|
||||
int flags1 = info->page[1].flags;
|
||||
@ -5772,12 +5576,12 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
|
||||
} while (reg_off & 63);
|
||||
} while (reg_off <= reg_last);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
|
221
target/arm/sve_ldst_internal.h
Normal file
221
target/arm/sve_ldst_internal.h
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* ARM SVE Load/Store Helpers
|
||||
*
|
||||
* Copyright (c) 2018-2022 Linaro
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef TARGET_ARM_SVE_LDST_INTERNAL_H
|
||||
#define TARGET_ARM_SVE_LDST_INTERNAL_H
|
||||
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
/*
|
||||
* Load one element into @vd + @reg_off from @host.
|
||||
* The controlling predicate is known to be true.
|
||||
*/
|
||||
typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host);
|
||||
|
||||
/*
|
||||
* Load one element into @vd + @reg_off from (@env, @vaddr, @ra).
|
||||
* The controlling predicate is known to be true.
|
||||
*/
|
||||
typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off,
|
||||
target_ulong vaddr, uintptr_t retaddr);
|
||||
|
||||
/*
|
||||
* Generate the above primitives.
|
||||
*/
|
||||
|
||||
#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \
|
||||
static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
|
||||
{ TYPEM val = HOST(host); *(TYPEE *)(vd + H(reg_off)) = val; }
|
||||
|
||||
#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \
|
||||
static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
|
||||
{ TYPEM val = *(TYPEE *)(vd + H(reg_off)); HOST(host, val); }
|
||||
|
||||
#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \
|
||||
static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \
|
||||
intptr_t reg_off, target_ulong addr, uintptr_t ra) \
|
||||
{ \
|
||||
TYPEM val = TLB(env, useronly_clean_ptr(addr), ra); \
|
||||
*(TYPEE *)(vd + H(reg_off)) = val; \
|
||||
}
|
||||
|
||||
#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \
|
||||
static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \
|
||||
intptr_t reg_off, target_ulong addr, uintptr_t ra) \
|
||||
{ \
|
||||
TYPEM val = *(TYPEE *)(vd + H(reg_off)); \
|
||||
TLB(env, useronly_clean_ptr(addr), val, ra); \
|
||||
}
|
||||
|
||||
#define DO_LD_PRIM_1(NAME, H, TE, TM) \
|
||||
DO_LD_HOST(NAME, H, TE, TM, ldub_p) \
|
||||
DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra)
|
||||
|
||||
DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t)
|
||||
DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t)
|
||||
DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t)
|
||||
DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t)
|
||||
|
||||
#define DO_ST_PRIM_1(NAME, H, TE, TM) \
|
||||
DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \
|
||||
DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra)
|
||||
|
||||
DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t)
|
||||
DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t)
|
||||
DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t)
|
||||
DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t)
|
||||
|
||||
#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \
|
||||
DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \
|
||||
DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \
|
||||
DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \
|
||||
DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra)
|
||||
|
||||
#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \
|
||||
DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \
|
||||
DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \
|
||||
DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \
|
||||
DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra)
|
||||
|
||||
DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw)
|
||||
DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw)
|
||||
DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw)
|
||||
|
||||
DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw)
|
||||
DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw)
|
||||
DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw)
|
||||
|
||||
DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl)
|
||||
DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl)
|
||||
DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl)
|
||||
|
||||
DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl)
|
||||
DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl)
|
||||
|
||||
DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq)
|
||||
DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq)
|
||||
|
||||
#undef DO_LD_TLB
|
||||
#undef DO_ST_TLB
|
||||
#undef DO_LD_HOST
|
||||
#undef DO_LD_PRIM_1
|
||||
#undef DO_ST_PRIM_1
|
||||
#undef DO_LD_PRIM_2
|
||||
#undef DO_ST_PRIM_2
|
||||
|
||||
/*
|
||||
* Resolve the guest virtual address to info->host and info->flags.
|
||||
* If @nofault, return false if the page is invalid, otherwise
|
||||
* exit via page fault exception.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
void *host;
|
||||
int flags;
|
||||
MemTxAttrs attrs;
|
||||
} SVEHostPage;
|
||||
|
||||
bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
|
||||
target_ulong addr, int mem_off, MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr);
|
||||
|
||||
/*
|
||||
* Analyse contiguous data, protected by a governing predicate.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
FAULT_NO,
|
||||
FAULT_FIRST,
|
||||
FAULT_ALL,
|
||||
} SVEContFault;
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* First and last element wholly contained within the two pages.
|
||||
* mem_off_first[0] and reg_off_first[0] are always set >= 0.
|
||||
* reg_off_last[0] may be < 0 if the first element crosses pages.
|
||||
* All of mem_off_first[1], reg_off_first[1] and reg_off_last[1]
|
||||
* are set >= 0 only if there are complete elements on a second page.
|
||||
*
|
||||
* The reg_off_* offsets are relative to the internal vector register.
|
||||
* The mem_off_first offset is relative to the memory address; the
|
||||
* two offsets are different when a load operation extends, a store
|
||||
* operation truncates, or for multi-register operations.
|
||||
*/
|
||||
int16_t mem_off_first[2];
|
||||
int16_t reg_off_first[2];
|
||||
int16_t reg_off_last[2];
|
||||
|
||||
/*
|
||||
* One element that is misaligned and spans both pages,
|
||||
* or -1 if there is no such active element.
|
||||
*/
|
||||
int16_t mem_off_split;
|
||||
int16_t reg_off_split;
|
||||
|
||||
/*
|
||||
* The byte offset at which the entire operation crosses a page boundary.
|
||||
* Set >= 0 if and only if the entire operation spans two pages.
|
||||
*/
|
||||
int16_t page_split;
|
||||
|
||||
/* TLB data for the two pages. */
|
||||
SVEHostPage page[2];
|
||||
} SVEContLdSt;
|
||||
|
||||
/*
|
||||
* Find first active element on each page, and a loose bound for the
|
||||
* final element on each page. Identify any single element that spans
|
||||
* the page boundary. Return true if there are any active elements.
|
||||
*/
|
||||
bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg,
|
||||
intptr_t reg_max, int esz, int msize);
|
||||
|
||||
/*
|
||||
* Resolve the guest virtual addresses to info->page[].
|
||||
* Control the generation of page faults with @fault. Return false if
|
||||
* there is no work to do, which can only happen with @fault == FAULT_NO.
|
||||
*/
|
||||
bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
|
||||
CPUARMState *env, target_ulong addr,
|
||||
MMUAccessType access_type, uintptr_t retaddr);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline void
|
||||
sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, uint64_t *vg,
|
||||
target_ulong addr, int esize, int msize,
|
||||
int wp_access, uintptr_t retaddr)
|
||||
{ }
|
||||
#else
|
||||
void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
|
||||
uint64_t *vg, target_ulong addr,
|
||||
int esize, int msize, int wp_access,
|
||||
uintptr_t retaddr);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#endif /* TARGET_ARM_SVE_LDST_INTERNAL_H */
|
@ -11,6 +11,32 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
|
||||
/* Return true if the translation regime is using LPAE format page tables */
|
||||
bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
int el = regime_el(env, mmu_idx);
|
||||
if (el == 2 || arm_el_is_aa64(env, el)) {
|
||||
return true;
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_LPAE)
|
||||
&& (regime_tcr(env, mmu_idx)->raw_tcr & TTBCR_EAE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the stage 1 translation regime is using LPAE format page
|
||||
* tables. Used when raising alignment exceptions, whose FSR changes depending
|
||||
* on whether the long or short descriptor format is in use.
|
||||
*/
|
||||
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
mmu_idx = stage_1_mmu_idx(mmu_idx);
|
||||
return regime_using_lpae_format(env, mmu_idx);
|
||||
}
|
||||
|
||||
static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
|
||||
unsigned int target_el,
|
||||
bool same_el, bool ea,
|
||||
|
@ -14608,7 +14608,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
|
||||
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
|
||||
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
|
||||
dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16;
|
||||
dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
|
||||
dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
|
||||
dc->bt = EX_TBFLAG_A64(tb_flags, BT);
|
||||
dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
|
||||
|
@ -104,7 +104,7 @@ static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno)
|
||||
/* Return the byte size of the "whole" vector register, VL / 8. */
|
||||
static inline int vec_full_reg_size(DisasContext *s)
|
||||
{
|
||||
return s->sve_len;
|
||||
return s->vl;
|
||||
}
|
||||
|
||||
bool disas_sve(DisasContext *, uint32_t);
|
||||
|
@ -111,7 +111,7 @@ static inline int pred_full_reg_offset(DisasContext *s, int regno)
|
||||
/* Return the byte size of the whole predicate register, VL / 64. */
|
||||
static inline int pred_full_reg_size(DisasContext *s)
|
||||
{
|
||||
return s->sve_len >> 3;
|
||||
return s->vl >> 3;
|
||||
}
|
||||
|
||||
/* Round up the size of a register to a size allowed by
|
||||
|
@ -42,7 +42,7 @@ typedef struct DisasContext {
|
||||
bool ns; /* Use non-secure CPREG bank on access */
|
||||
int fp_excp_el; /* FP exception EL or 0 if enabled */
|
||||
int sve_excp_el; /* SVE exception EL or 0 if enabled */
|
||||
int sve_len; /* SVE vector length in bytes */
|
||||
int vl; /* current vector length in bytes */
|
||||
/* Flag indicating that exceptions from secure mode are routed to EL3. */
|
||||
bool secure_routed_to_el3;
|
||||
bool vfp_enabled; /* FP enabled via FPSCR.EN */
|
||||
|
@ -127,6 +127,32 @@ const uint64_t expand_pred_b_data[256] = {
|
||||
0xffffffffffffffff,
|
||||
};
|
||||
|
||||
/*
|
||||
* Similarly for half-word elements.
|
||||
* for (i = 0; i < 256; ++i) {
|
||||
* unsigned long m = 0;
|
||||
* if (i & 0xaa) {
|
||||
* continue;
|
||||
* }
|
||||
* for (j = 0; j < 8; j += 2) {
|
||||
* if ((i >> j) & 1) {
|
||||
* m |= 0xfffful << (j << 3);
|
||||
* }
|
||||
* }
|
||||
* printf("[0x%x] = 0x%016lx,\n", i, m);
|
||||
* }
|
||||
*/
|
||||
const uint64_t expand_pred_h_data[0x55 + 1] = {
|
||||
[0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000,
|
||||
[0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000,
|
||||
[0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000,
|
||||
[0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000,
|
||||
[0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000,
|
||||
[0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000,
|
||||
[0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000,
|
||||
[0x55] = 0xffffffffffffffff,
|
||||
};
|
||||
|
||||
/* Signed saturating rounding doubling multiply-accumulate high half, 8-bit */
|
||||
int8_t do_sqrdmlah_b(int8_t src1, int8_t src2, int8_t src3,
|
||||
bool neg, bool round)
|
||||
@ -2531,7 +2557,7 @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b)
|
||||
* BFloat16 Dot Product
|
||||
*/
|
||||
|
||||
static float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2)
|
||||
float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2)
|
||||
{
|
||||
/* FPCR is ignored for BFDOT and BFMMLA. */
|
||||
float_status bf_status = {
|
||||
|
@ -50,8 +50,21 @@
|
||||
#define H8(x) (x)
|
||||
#define H1_8(x) (x)
|
||||
|
||||
/* Data for expanding active predicate bits to bytes, for byte elements. */
|
||||
/*
|
||||
* Expand active predicate bits to bytes, for byte elements.
|
||||
*/
|
||||
extern const uint64_t expand_pred_b_data[256];
|
||||
static inline uint64_t expand_pred_b(uint8_t byte)
|
||||
{
|
||||
return expand_pred_b_data[byte];
|
||||
}
|
||||
|
||||
/* Similarly for half-word elements. */
|
||||
extern const uint64_t expand_pred_h_data[0x55 + 1];
|
||||
static inline uint64_t expand_pred_h(uint8_t byte)
|
||||
{
|
||||
return expand_pred_h_data[byte & 0x55];
|
||||
}
|
||||
|
||||
static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz)
|
||||
{
|
||||
@ -217,4 +230,17 @@ uint64_t pmull_h(uint64_t op1, uint64_t op2);
|
||||
*/
|
||||
uint64_t pmull_w(uint64_t op1, uint64_t op2);
|
||||
|
||||
/**
|
||||
* bfdotadd:
|
||||
* @sum: addend
|
||||
* @e1, @e2: multiplicand vectors
|
||||
*
|
||||
* BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum.
|
||||
* The @e1 and @e2 operands correspond to the 32-bit source vector
|
||||
* slots and contain two Bfloat16 values each.
|
||||
*
|
||||
* Corresponds to the ARM pseudocode function BFDotAdd.
|
||||
*/
|
||||
float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2);
|
||||
|
||||
#endif /* TARGET_ARM_VEC_INTERNAL_H */
|
||||
|
@ -103,7 +103,7 @@ static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
|
||||
|
||||
/* Convert CPU model data from X86CPU object to a property dictionary
|
||||
* that can recreate exactly the same CPU model, including every
|
||||
* writeable QOM property.
|
||||
* writable QOM property.
|
||||
*/
|
||||
static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
|
||||
{
|
||||
|
@ -330,7 +330,7 @@
|
||||
#define EPT_VIOLATION_DATA_WRITE (1UL << 1)
|
||||
#define EPT_VIOLATION_INST_FETCH (1UL << 2)
|
||||
#define EPT_VIOLATION_GPA_READABLE (1UL << 3)
|
||||
#define EPT_VIOLATION_GPA_WRITEABLE (1UL << 4)
|
||||
#define EPT_VIOLATION_GPA_WRITABLE (1UL << 4)
|
||||
#define EPT_VIOLATION_GPA_EXECUTABLE (1UL << 5)
|
||||
#define EPT_VIOLATION_GLA_VALID (1UL << 7)
|
||||
#define EPT_VIOLATION_XLAT_VALID (1UL << 8)
|
||||
|
@ -80,7 +80,7 @@ static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl)
|
||||
|
||||
#define AR_TYPE_ACCESSES_MASK 1
|
||||
#define AR_TYPE_READABLE_MASK (1 << 1)
|
||||
#define AR_TYPE_WRITEABLE_MASK (1 << 2)
|
||||
#define AR_TYPE_WRITABLE_MASK (1 << 2)
|
||||
#define AR_TYPE_CODE_MASK (1 << 3)
|
||||
#define AR_TYPE_MASK 0x0f
|
||||
#define AR_TYPE_BUSY_64_TSS 11
|
||||
|
@ -284,7 +284,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
|
||||
g_assert(!s390_is_pv());
|
||||
/*
|
||||
* As operand exceptions have a lower priority than access exceptions,
|
||||
* we check whether the memory area is writeable (injecting the
|
||||
* we check whether the memory area is writable (injecting the
|
||||
* access execption if it is not) first.
|
||||
*/
|
||||
if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {
|
||||
|
@ -56,7 +56,7 @@
|
||||
*
|
||||
* - `ebx`: contains the physical memory address where the loader has placed
|
||||
* the boot start info structure.
|
||||
* - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared.
|
||||
* - `cr0`: bit 0 (PE) must be set. All the other writable bits are cleared.
|
||||
* - `cr4`: all bits are cleared.
|
||||
* - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’
|
||||
* and a limit of ‘0xFFFFFFFF’. The selector value is unspecified.
|
||||
|
Loading…
Reference in New Issue
Block a user