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:
Richard Henderson 2022-06-09 06:47:03 -07:00
commit 028f2361d0
50 changed files with 3240 additions and 3037 deletions

View File

@ -120,12 +120,12 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
{ {
hvf_slot *mem; hvf_slot *mem;
MemoryRegion *area = section->mr; MemoryRegion *area = section->mr;
bool writeable = !area->readonly && !area->rom_device; bool writable = !area->readonly && !area->rom_device;
hv_memory_flags_t flags; hv_memory_flags_t flags;
uint64_t page_size = qemu_real_host_page_size(); uint64_t page_size = qemu_real_host_page_size();
if (!memory_region_is_ram(area)) { if (!memory_region_is_ram(area)) {
if (writeable) { if (writable) {
return; return;
} else if (!memory_region_is_romd(area)) { } else if (!memory_region_is_romd(area)) {
/* /*

View File

@ -1346,13 +1346,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
KVMSlot *mem; KVMSlot *mem;
int err; int err;
MemoryRegion *mr = section->mr; 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; hwaddr start_addr, size, slot_size, mr_offset;
ram_addr_t ram_start_offset; ram_addr_t ram_start_offset;
void *ram; void *ram;
if (!memory_region_is_ram(mr)) { if (!memory_region_is_ram(mr)) {
if (writeable || !kvm_readonly_mem_allowed) { if (writable || !kvm_readonly_mem_allowed) {
return; return;
} else if (!mr->romd_mode) { } else if (!mr->romd_mode) {
/* If the memory device is not in romd_mode, then we actually want /* If the memory device is not in romd_mode, then we actually want

View File

@ -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. * 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 * 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 * 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 * a page that's writable this means we had two threads racing and
* another thread got there first and already made the page writeable; * another thread got there first and already made the page writable;
* so we will retry the access. If we were to call page_unprotect() * 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 * 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. * guest, we'd end up in an infinite loop of retrying the faulting access.

View File

@ -222,7 +222,7 @@ Virtio device config space
:size: a 32-bit configuration space access size in bytes :size: a 32-bit configuration space access size in bytes
:flags: a 32-bit value: :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 - 1: Vhost front-end messages used for live migration
:payload: Size bytes array holding the contents of the virtio :payload: Size bytes array holding the contents of the virtio

View File

@ -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 backed-up or snapshotted image. In order to do this, QEMU must know the
address that has been allocated. 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 These are data object that are visible to both QEMU and guests, and are
addressable as sequential files. 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 /etc/vmgenid_guid - contains the actual VM Generation ID GUID
- read-only to the guest - read-only to the guest
/etc/vmgenid_addr - contains the address of the downloaded vmgenid blob /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: QEMU sends the following commands to the guest at startup:

View File

@ -23,6 +23,7 @@ the following architecture extensions:
- FEAT_Debugv8p2 (Debug changes for v8.2) - FEAT_Debugv8p2 (Debug changes for v8.2)
- FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_Debugv8p4 (Debug changes for v8.4)
- FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_DotProd (Advanced SIMD dot product instructions)
- FEAT_DoubleFault (Double Fault Extension)
- FEAT_FCMA (Floating-point complex number instructions) - FEAT_FCMA (Floating-point complex number instructions)
- FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions)
- FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP16 (Half-precision floating-point data processing)
@ -52,6 +53,7 @@ the following architecture extensions:
- FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p1 (PMU Extensions v3.1)
- FEAT_PMUv3p4 (PMU Extensions v3.4) - FEAT_PMUv3p4 (PMU Extensions v3.4)
- FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RAS (Reliability, availability, and serviceability)
- FEAT_RASv1p1 (RAS Extension v1.1)
- FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions)
- FEAT_RNG (Random number generator) - FEAT_RNG (Random number generator)
- FEAT_S2FWB (Stage 2 forced Write-Back) - FEAT_S2FWB (Stage 2 forced Write-Back)

View File

@ -249,7 +249,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
/* /*
* Initialize the value of read_ack_register to 1, so GHES can be * 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 * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2
* (GHESv2 - Type 10) * (GHESv2 - Type 10)
*/ */

View File

@ -60,10 +60,10 @@
#define SERDES_SIZE 0x20000 #define SERDES_SIZE 0x20000
#define DP_ADDR 0xfd4a0000 #define DP_ADDR 0xfd4a0000
#define DP_IRQ 113 #define DP_IRQ 0x77
#define DPDMA_ADDR 0xfd4c0000 #define DPDMA_ADDR 0xfd4c0000
#define DPDMA_IRQ 116 #define DPDMA_IRQ 0x7a
#define APU_ADDR 0xfd5c0000 #define APU_ADDR 0xfd5c0000
#define APU_IRQ 153 #define APU_IRQ 153

View File

@ -114,6 +114,7 @@
#define DP_TX_N_AUD (0x032C >> 2) #define DP_TX_N_AUD (0x032C >> 2)
#define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2) #define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2)
#define DP_INT_STATUS (0x03A0 >> 2) #define DP_INT_STATUS (0x03A0 >> 2)
#define DP_INT_VBLNK_START (1 << 13)
#define DP_INT_MASK (0x03A4 >> 2) #define DP_INT_MASK (0x03A4 >> 2)
#define DP_INT_EN (0x03A8 >> 2) #define DP_INT_EN (0x03A8 >> 2)
#define DP_INT_DS (0x03AC >> 2) #define DP_INT_DS (0x03AC >> 2)
@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt;
static const VMStateDescription vmstate_dp = { static const VMStateDescription vmstate_dp = {
.name = TYPE_XLNX_DP, .name = TYPE_XLNX_DP,
.version_id = 1, .version_id = 2,
.fields = (VMStateField[]){ .fields = (VMStateField[]){
VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState, VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState,
DP_CORE_REG_ARRAY_SIZE), DP_CORE_REG_ARRAY_SIZE),
@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = {
DP_VBLEND_REG_ARRAY_SIZE), DP_VBLEND_REG_ARRAY_SIZE),
VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState, VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState,
DP_AUDIO_REG_ARRAY_SIZE), DP_AUDIO_REG_ARRAY_SIZE),
VMSTATE_PTIMER(vblank, XlnxDPState),
VMSTATE_END_OF_LIST() 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 void xlnx_dp_update_irq(XlnxDPState *s);
static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size) 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; break;
case DP_TRANSMITTER_ENABLE: case DP_TRANSMITTER_ENABLE:
s->core_registers[offset] = value & 0x01; 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; break;
case DP_FORCE_SCRAMBLER_RESET: 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); xlnx_dp_update_irq(s);
break; break;
case DP_INT_DS: case DP_INT_DS:
s->core_registers[DP_INT_MASK] |= ~value; s->core_registers[DP_INT_MASK] |= value;
xlnx_dp_update_irq(s); xlnx_dp_update_irq(s);
break; break;
default: default:
@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque)
return; return;
} }
s->core_registers[DP_INT_STATUS] |= (1 << 13);
xlnx_dp_update_irq(s);
xlnx_dpdma_trigger_vsync_irq(s->dpdma); xlnx_dpdma_trigger_vsync_irq(s->dpdma);
/* /*
@ -1219,19 +1229,22 @@ static void xlnx_dp_init(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
XlnxDPState *s = XLNX_DP(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 memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP
".core", 0x3AF); ".core", sizeof(s->core_registers));
memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem); 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 memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP
".v_blend", 0x1DF); ".v_blend", sizeof(s->vblend_registers));
memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem); 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 memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP
".av_buffer_manager", 0x238); ".av_buffer_manager", sizeof(s->avbufm_registers));
memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem); 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 memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP
".audio", sizeof(s->audio_registers)); ".audio", sizeof(s->audio_registers));
@ -1272,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj)
fifo8_destroy(&s->rx_fifo); 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) static void xlnx_dp_realize(DeviceState *dev, Error **errp)
{ {
XlnxDPState *s = XLNX_DP(dev); XlnxDPState *s = XLNX_DP(dev);
@ -1306,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
&as); &as);
AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255); AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
xlnx_dp_audio_activate(s); 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) static void xlnx_dp_reset(DeviceState *dev)

View File

@ -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; 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; mask = ICC_CTLR_EL3_EOIMODE_EL3;
cs->icc_ctlr_el3 &= ~mask; cs->icc_ctlr_el3 &= ~mask;

View File

@ -611,7 +611,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset,
if (value & mask & GICD_CTLR_DS) { if (value & mask & GICD_CTLR_DS) {
/* We just set DS, so the ARE_NS and EnG1S bits are now RES0. /* 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 * 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. * hardware reset.
*/ */
s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS);

View File

@ -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; * 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 | newval &= R_GICR_VPENDBASER_INNERCACHE_MASK |
R_GICR_VPENDBASER_SHAREABILITY_MASK | R_GICR_VPENDBASER_SHAREABILITY_MASK |
@ -491,7 +491,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
/* RAZ/WI for our implementation */ /* RAZ/WI for our implementation */
return MEMTX_OK; return MEMTX_OK;
case GICR_WAKER: 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 * it it requests that we transition the channel between the
* redistributor and the cpu interface to quiescent, and that * redistributor and the cpu interface to quiescent, and that
* we set the ChildrenAsleep bit once the inteface has reached the * we set the ChildrenAsleep bit once the inteface has reached the

View File

@ -463,7 +463,7 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
/* Claim software interrupt bits */ /* Claim software interrupt bits */
for (i = 0; i < swi->num_harts; i++) { for (i = 0; i < swi->num_harts; i++) {
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + 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) { if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) {
error_report("MSIP already claimed"); error_report("MSIP already claimed");
exit(1); exit(1);

View File

@ -646,7 +646,7 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
} }
if (addr == APLIC_DOMAINCFG) { if (addr == APLIC_DOMAINCFG) {
/* Only IE bit writeable at the moment */ /* Only IE bit writable at the moment */
value &= APLIC_DOMAINCFG_IE; value &= APLIC_DOMAINCFG_IE;
aplic->domaincfg = value; aplic->domaincfg = value;
} else if ((APLIC_SOURCECFG_BASE <= addr) && } else if ((APLIC_SOURCECFG_BASE <= addr) &&

View File

@ -456,7 +456,7 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp)
pci_set_byte(config + SHPC_CAP_CxP, 0); pci_set_byte(config + SHPC_CAP_CxP, 0);
pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
d->shpc->cap = config_offset; 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_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
return 0; return 0;

View File

@ -633,7 +633,7 @@ struct mfi_ctrl_props {
* metadata and user data * metadata and user data
* 1=5%, 2=10%, 3=15% and so on * 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 as a % of source LD
* capacity. 0=READ only * capacity. 0=READ only
* 1=5%, 2=10%, 3=15% and so on * 1=5%, 2=10%, 3=15% and so on

View File

@ -165,7 +165,7 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
} }
if (tte & IOMMU_TTE_DATA_W) { if (tte & IOMMU_TTE_DATA_W) {
/* Writeable */ /* Writable */
ret.perm = IOMMU_RW; ret.perm = IOMMU_RW;
} else { } else {
ret.perm = IOMMU_RO; ret.perm = IOMMU_RO;

View File

@ -324,7 +324,7 @@ static void sse_timer_write(void *opaque, hwaddr offset, uint64_t value,
{ {
uint32_t old_ctl = s->cntp_aival_ctl; 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 &= ~R_CNTP_AIVAL_CTL_EN_MASK;
s->cntp_aival_ctl |= value & 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)) { if (!(value & R_CNTP_AIVAL_CTL_CLR_MASK)) {

View File

@ -35,14 +35,20 @@
#include "hw/dma/xlnx_dpdma.h" #include "hw/dma/xlnx_dpdma.h"
#include "audio/audio.h" #include "audio/audio.h"
#include "qom/object.h" #include "qom/object.h"
#include "hw/ptimer.h"
#define AUD_CHBUF_MAX_DEPTH (32 * KiB) #define AUD_CHBUF_MAX_DEPTH (32 * KiB)
#define MAX_QEMU_BUFFER_SIZE (4 * 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_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_AUDIO_REG_ARRAY_SIZE (0x50 >> 2)
#define DP_CONTAINER_SIZE (0xC050)
struct PixmanPlane { struct PixmanPlane {
pixman_format_code_t format; pixman_format_code_t format;
@ -102,6 +108,8 @@ struct XlnxDPState {
*/ */
DPCDState *dpcd; DPCDState *dpcd;
I2CDDCState *edid; I2CDDCState *edid;
ptimer_state *vblank;
}; };
#define TYPE_XLNX_DP "xlnx.v-dp" #define TYPE_XLNX_DP "xlnx.v-dp"

View File

@ -315,7 +315,7 @@ static int target_restore_sigframe(CPUARMState *env,
case TARGET_SVE_MAGIC: case TARGET_SVE_MAGIC:
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { 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_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
if (!sve && size == sve_size) { if (!sve && size == sve_size) {
sve = (struct target_sve_context *)ctx; 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. */ /* SVE state needs saving only if it exists. */
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { 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_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
sve_ofs = alloc_sigframe_space(sve_size, &layout); sve_ofs = alloc_sigframe_space(sve_size, &layout);
} }

View File

@ -10,7 +10,7 @@ static abi_long do_prctl_get_vl(CPUArchState *env)
{ {
ARMCPU *cpu = env_archcpu(env); ARMCPU *cpu = env_archcpu(env);
if (cpu_isar_feature(aa64_sve, cpu)) { 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; 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)) if (cpu_isar_feature(aa64_sve, env_archcpu(env))
&& arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
ARMCPU *cpu = env_archcpu(env);
uint32_t vq, old_vq; uint32_t vq, old_vq;
old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; old_vq = sve_vq(env);
vq = MAX(arg2 / 16, 1);
vq = MIN(vq, cpu->sve_max_vq);
/*
* 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) { if (vq < old_vq) {
aarch64_sve_narrow_vq(env, vq); aarch64_sve_narrow_vq(env, vq);
} }
env->vfp.zcr_el[1] = vq - 1;
arm_rebuild_hflags(env);
return vq * 16; return vq * 16;
} }
return -TARGET_EINVAL; return -TARGET_EINVAL;

View File

@ -495,7 +495,7 @@ class QEMUMachine:
""" """
# If we keep the console socket open, we may deadlock waiting # If we keep the console socket open, we may deadlock waiting
# for QEMU to exit, while QEMU is waiting for the socket to # for QEMU to exit, while QEMU is waiting for the socket to
# become writeable. # become writable.
if self._console_socket is not None: if self._console_socket is not None:
self._console_socket.close() self._console_socket.close()
self._console_socket = None self._console_socket = None

View File

@ -166,7 +166,7 @@ static off_t sve_fpcr_offset(uint32_t vq)
static uint32_t sve_current_vq(CPUARMState *env) 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) static size_t sve_size_vq(uint32_t vq)

View File

@ -208,8 +208,7 @@ static void arm_cpu_reset(DeviceState *dev)
CPACR_EL1, ZEN, 3); CPACR_EL1, ZEN, 3);
/* with reasonable vector length */ /* with reasonable vector length */
if (cpu_isar_feature(aa64_sve, cpu)) { if (cpu_isar_feature(aa64_sve, cpu)) {
env->vfp.zcr_el[1] = env->vfp.zcr_el[1] = cpu->sve_default_vq - 1;
aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1);
} }
/* /*
* Enable 48-bit address space (TODO: take reserved_va into account). * 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)); vfp_get_fpcr(env), vfp_get_fpsr(env));
if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { 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++) { for (i = 0; i <= FFR_PRED_NUM; i++) {
bool eol; bool eol;

View File

@ -966,6 +966,7 @@ struct ArchCPU {
uint64_t id_aa64dfr0; uint64_t id_aa64dfr0;
uint64_t id_aa64dfr1; uint64_t id_aa64dfr1;
uint64_t id_aa64zfr0; uint64_t id_aa64zfr0;
uint64_t id_aa64smfr0;
uint64_t reset_pmcr_el0; uint64_t reset_pmcr_el0;
} isar; } isar;
uint64_t midr; uint64_t midr;
@ -1041,9 +1042,9 @@ struct ArchCPU {
* Bits set in sve_vq_supported represent valid vector lengths for * Bits set in sve_vq_supported represent valid vector lengths for
* the CPU type. * the CPU type.
*/ */
DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); uint32_t sve_vq_map;
DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); uint32_t sve_vq_init;
DECLARE_BITMAP(sve_vq_supported, ARM_MAX_VQ); uint32_t sve_vq_supported;
/* Generic timer counter frequency, in Hz */ /* Generic timer counter frequency, in Hz */
uint64_t gt_cntfrq_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 fp_exception_el(CPUARMState *env, int cur_el);
int sve_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) 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, F32MM, 52, 4)
FIELD(ID_AA64ZFR0, F64MM, 56, 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, COPDBG, 0, 4)
FIELD(ID_DFR0, COPSDBG, 4, 4) FIELD(ID_DFR0, COPSDBG, 4, 4)
FIELD(ID_DFR0, MMAPDBG, 8, 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, TBII, 0, 2)
FIELD(TBFLAG_A64, SVEEXC_EL, 2, 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, PAUTH_ACTIVE, 8, 1)
FIELD(TBFLAG_A64, BT, 9, 1) FIELD(TBFLAG_A64, BT, 9, 1)
FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */ 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); 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) static inline bool bswap_code(bool sctlr_b)
{ {
#ifdef CONFIG_USER_ONLY #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; 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) static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; 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; 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) static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && 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; 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?" * Feature tests for "does this exist in either 32-bit or 64-bit?"
*/ */

View File

@ -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 * any of the above. Finally, if SVE is not disabled, then at least one
* vector length must be enabled. * vector length must be enabled.
*/ */
DECLARE_BITMAP(tmp, ARM_MAX_VQ); uint32_t vq_map = cpu->sve_vq_map;
uint32_t vq, max_vq = 0; 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 * 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 * in the supported bitmap results in an error. When KVM is enabled we
* fetch the supported bitmap from the host. * fetch the supported bitmap from the host.
*/ */
if (kvm_enabled() && kvm_arm_sve_supported()) { if (kvm_enabled()) {
kvm_arm_sve_get_vls(CPU(cpu), cpu->sve_vq_supported); if (kvm_arm_sve_supported()) {
} else if (kvm_enabled()) { cpu->sve_vq_supported = kvm_arm_sve_get_vls(CPU(cpu));
assert(!cpu_isar_feature(aa64_sve, 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>. * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
* Check first for any sve<N> enabled. * Check first for any sve<N> enabled.
*/ */
if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) { if (vq_map != 0) {
max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1; 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) { if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
error_setg(errp, "cannot enable sve%d", max_vq * 128); 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 * For KVM we have to automatically enable all supported unitialized
* lengths, even when the smaller lengths are not all powers-of-two. * 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); vq_map |= vq_supported & ~vq_init & vq_mask;
bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
} else { } else {
/* Propagate enabled bits down through required powers-of-two. */ /* Propagate enabled bits down through required powers-of-two. */
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { vq_map |= SVE_VQ_POW2_MAP & ~vq_init & vq_mask;
if (!test_bit(vq - 1, cpu->sve_vq_init)) {
set_bit(vq - 1, cpu->sve_vq_map);
}
}
} }
} else if (cpu->sve_max_vq == 0) { } else if (cpu->sve_max_vq == 0) {
/* /*
@ -413,25 +418,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
if (kvm_enabled()) { if (kvm_enabled()) {
/* Disabling a supported length disables all larger lengths. */ /* Disabling a supported length disables all larger lengths. */
for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { tmp = vq_init & vq_supported;
if (test_bit(vq - 1, cpu->sve_vq_init) &&
test_bit(vq - 1, cpu->sve_vq_supported)) {
break;
}
}
} else { } else {
/* Disabling a power-of-two disables all larger lengths. */ /* Disabling a power-of-two disables all larger lengths. */
for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) { tmp = vq_init & SVE_VQ_POW2_MAP;
if (test_bit(vq - 1, cpu->sve_vq_init)) {
break;
}
}
} }
vq = ctz32(tmp) + 1;
max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
bitmap_andnot(cpu->sve_vq_map, cpu->sve_vq_supported, vq_mask = MAKE_64BIT_MASK(0, max_vq);
cpu->sve_vq_init, max_vq); vq_map = vq_supported & ~vq_init & vq_mask;
if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
if (max_vq == 0 || vq_map == 0) {
error_setg(errp, "cannot disable sve%d", vq * 128); error_setg(errp, "cannot disable sve%d", vq * 128);
error_append_hint(errp, "Disabling sve%d results in all " error_append_hint(errp, "Disabling sve%d results in all "
"vector lengths being disabled.\n", "vector lengths being disabled.\n",
@ -441,7 +439,8 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return; 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) { if (cpu->sve_max_vq != 0) {
max_vq = cpu->sve_max_vq; max_vq = cpu->sve_max_vq;
vq_mask = MAKE_64BIT_MASK(0, max_vq);
if (!test_bit(max_vq - 1, cpu->sve_vq_map) && if (vq_init & ~vq_map & (1 << (max_vq - 1))) {
test_bit(max_vq - 1, cpu->sve_vq_init)) {
error_setg(errp, "cannot disable sve%d", max_vq * 128); error_setg(errp, "cannot disable sve%d", max_vq * 128);
error_append_hint(errp, "The maximum vector length must be " error_append_hint(errp, "The maximum vector length must be "
"enabled, sve-max-vq=%d (%d bits)\n", "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. */ /* Set all bits not explicitly set within sve-max-vq. */
bitmap_complement(tmp, cpu->sve_vq_init, max_vq); vq_map |= ~vq_init & vq_mask;
bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
} }
/* /*
@ -472,13 +470,14 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
* are clear, just in case anybody looks. * are clear, just in case anybody looks.
*/ */
assert(max_vq != 0); 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. */ /* Ensure the set of lengths matches what is supported. */
bitmap_xor(tmp, cpu->sve_vq_map, cpu->sve_vq_supported, max_vq); tmp = vq_map ^ (vq_supported & vq_mask);
if (!bitmap_empty(tmp, max_vq)) { if (tmp) {
vq = find_last_bit(tmp, max_vq) + 1; vq = 32 - clz32(tmp);
if (test_bit(vq - 1, cpu->sve_vq_map)) { if (vq_map & (1 << (vq - 1))) {
if (cpu->sve_max_vq) { if (cpu->sve_max_vq) {
error_setg(errp, "cannot set sve-max-vq=%d", 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 " error_append_hint(errp, "This CPU does not support "
@ -502,15 +501,15 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return; return;
} else { } else {
/* Ensure all required powers-of-two are enabled. */ /* Ensure all required powers-of-two are enabled. */
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { tmp = SVE_VQ_POW2_MAP & vq_mask & ~vq_map;
if (!test_bit(vq - 1, cpu->sve_vq_map)) { if (tmp) {
error_setg(errp, "cannot disable sve%d", vq * 128); vq = 32 - clz32(tmp);
error_append_hint(errp, "sve%d is required as it " error_setg(errp, "cannot disable sve%d", vq * 128);
"is a power-of-two length smaller " error_append_hint(errp, "sve%d is required as it "
"than the maximum, sve%d\n", "is a power-of-two length smaller "
vq * 128, max_vq * 128); "than the maximum, sve%d\n",
return; 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. */ /* From now on sve_max_vq is the actual maximum supported length. */
cpu->sve_max_vq = max_vq; 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, 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)) { if (!cpu_isar_feature(aa64_sve, cpu)) {
value = false; value = false;
} else { } 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); 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; return;
} }
if (value) { cpu->sve_vq_map = deposit32(cpu->sve_vq_map, vq - 1, 1, value);
set_bit(vq - 1, cpu->sve_vq_map); cpu->sve_vq_init |= 1 << (vq - 1);
} else {
clear_bit(vq - 1, cpu->sve_vq_map);
}
set_bit(vq - 1, cpu->sve_vq_init);
} }
static bool cpu_arm_get_sve(Object *obj, Error **errp) 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 = cpu->isar.id_aa64pfr0;
t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ 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, 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, SVE, 1);
t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */
t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ 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. * 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, 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 */ t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
cpu->isar.id_aa64pfr1 = t; cpu->isar.id_aa64pfr1 = t;
@ -978,7 +975,7 @@ static void aarch64_max_initfn(Object *obj)
cpu->dcz_blocksize = 7; /* 512 bytes */ cpu->dcz_blocksize = 7; /* 512 bytes */
#endif #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_pauth_properties(obj);
aarch64_add_sve_properties(obj); aarch64_add_sve_properties(obj);
@ -1025,12 +1022,11 @@ static void aarch64_a64fx_initfn(Object *obj)
cpu->gic_vprebits = 5; cpu->gic_vprebits = 5;
cpu->gic_pribits = 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); aarch64_add_sve_properties(obj);
bitmap_zero(cpu->sve_vq_supported, ARM_MAX_VQ); cpu->sve_vq_supported = (1 << 0) /* 128bit */
set_bit(0, cpu->sve_vq_supported); /* 128bit */ | (1 << 1) /* 256bit */
set_bit(1, cpu->sve_vq_supported); /* 256bit */ | (1 << 3); /* 512bit */
set_bit(3, cpu->sve_vq_supported); /* 512bit */
cpu->isar.reset_pmcr_el0 = 0x46014040; cpu->isar.reset_pmcr_el0 = 0x46014040;

View File

@ -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 * Don't allow writing to XPSR.Exception as it can cause
* a transition into or out of handler mode (it's not * 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. * restriction). Other fields are safe to update.
*/ */
xpsr_write(env, tmp, ~XPSR_EXCP); xpsr_write(env, tmp, ~XPSR_EXCP);

View File

@ -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 * 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. * 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); return gdb_get_reg64(buf, vq * 2);
} }
default: default:

File diff suppressed because it is too large Load Diff

View File

@ -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 &= ~PMCR_WRITABLE_MASK;
env->cp15.c9_pmcr |= (val & PMCR_WRITEABLE_MASK); env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK);
pmu_op_finish(env); pmu_op_finish(env);
break; break;

View File

@ -189,17 +189,6 @@ void arm_translate_init(void);
void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb);
#endif /* CONFIG_TCG */ #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 { enum arm_fprounding {
FPROUNDING_TIEEVEN, FPROUNDING_TIEEVEN,
FPROUNDING_POSINF, 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 */ /* Return the MMU index for a v7M CPU in the specified security state */
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
/* Return true if the stage 1 translation regime is using LPAE format page /* Return true if the translation regime is using LPAE format page tables */
* 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); bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
/* Raise a data fault alignment exception for the specified virtual address */ /* 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 */ /* Return the TCR controlling this translation regime */
static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) 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. * Return the ARMMMUIdx for the stage1 traversal for the current regime.
*/ */
#ifdef CONFIG_USER_ONLY #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) static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
{ {
return ARMMMUIdx_Stage1_E0; return ARMMMUIdx_Stage1_E0;
} }
#else #else
ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx);
ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env); ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
#endif #endif
@ -1090,6 +1095,9 @@ typedef struct ARMVAParameters {
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
ARMMMUIdx mmu_idx, bool data); 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) static inline int exception_target_el(CPUARMState *env)
{ {
int target_el = MAX(1, arm_current_el(env)); int target_el = MAX(1, arm_current_el(env));
@ -1280,10 +1288,10 @@ enum MVEECIState {
#define PMCRP 0x2 #define PMCRP 0x2
#define PMCRE 0x1 #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). * 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_P 0x80000000
#define PMXEVTYPER_U 0x40000000 #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); void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu);
#endif #endif
bool el_is_in_host(CPUARMState *env, int el);
void aa32_max_features(ARMCPU *cpu); 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 #endif

View File

@ -574,6 +574,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
} else { } else {
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
ARM64_SYS_REG(3, 0, 0, 4, 1)); 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, err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0,
ARM64_SYS_REG(3, 0, 0, 5, 0)); ARM64_SYS_REG(3, 0, 0, 5, 0));
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, 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; ahcf->isar.id_aa64pfr0 = t;
/* /*
* Before v5.1, KVM did not support SVE and did not expose * There is a range of kernels between kernel commit 73433762fcae
* ID_AA64ZFR0_EL1 even as RAZ. After v5.1, KVM still does * and f81cb2c3ad41 which have a bug where the kernel doesn't expose
* not expose the register to "user" requests like this * SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled
* unless the host supports SVE. * 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, err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0,
ARM64_SYS_REG(3, 0, 0, 4, 4)); 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); 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. */ /* Only call this function if kvm_arm_sve_supported() returns true. */
static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS]; static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
static bool probed; static bool probed;
uint32_t vq = 0; uint32_t vq = 0;
int i, j; int i;
bitmap_zero(map, ARM_MAX_VQ);
/* /*
* KVM ensures all host CPUs support the same set of vector lengths. * 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) { if (vq > ARM_MAX_VQ) {
warn_report("KVM supports vector lengths larger than " warn_report("KVM supports vector lengths larger than "
"QEMU can enable"); "QEMU can enable");
vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
} }
} }
for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) { return vls[0];
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);
}
}
}
} }
static int kvm_arm_sve_set_vls(CPUState *cs) 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 = { struct kvm_one_reg reg = {
.id = KVM_REG_ARM64_SVE_VLS, .id = KVM_REG_ARM64_SVE_VLS,
.addr = (uint64_t)&vls[0], .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); 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, &reg); return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
} }

View File

@ -239,13 +239,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
/** /**
* kvm_arm_sve_get_vls: * kvm_arm_sve_get_vls:
* @cs: CPUState * @cs: CPUState
* @map: bitmap to fill in
* *
* Get all the SVE vector lengths supported by the KVM host, setting * Get all the SVE vector lengths supported by the KVM host, setting
* the bits corresponding to their length in quadwords minus one * 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: * 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(); 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(); g_assert_not_reached();
} }

View File

@ -58,6 +58,7 @@ arm_softmmu_ss.add(files(
'machine.c', 'machine.c',
'monitor.c', 'monitor.c',
'psci.c', 'psci.c',
'ptw.c',
)) ))
subdir('hvf') subdir('hvf')

View File

@ -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) 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); *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) 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); *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) 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); *d = (*d & ~bmask) | (r & bmask);
} }

2540
target/arm/ptw.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -21,12 +21,12 @@
#include "cpu.h" #include "cpu.h"
#include "internals.h" #include "internals.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "tcg/tcg-gvec-desc.h" #include "tcg/tcg-gvec-desc.h"
#include "fpu/softfloat.h" #include "fpu/softfloat.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "vec_internal.h" #include "vec_internal.h"
#include "sve_ldst_internal.h"
/* Return a value for NZCV as per the ARM PredTest pseudofunction. /* 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; 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. */ /* Similarly for single word elements. */
static inline uint64_t expand_pred_s(uint8_t byte) 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 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, * 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 * 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. * exit via page fault exception.
*/ */
typedef struct { bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
void *host; target_ulong addr, int mem_off, MMUAccessType access_type,
int flags; int mmu_idx, uintptr_t retaddr)
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)
{ {
int flags; int flags;
@ -5511,59 +5361,13 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault,
return true; 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 * Find first active element on each page, and a loose bound for the
* final element on each page. Identify any single element that spans * final element on each page. Identify any single element that spans
* the page boundary. Return true if there are any active elements. * the page boundary. Return true if there are any active elements.
*/ */
static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg,
uint64_t *vg, intptr_t reg_max, intptr_t reg_max, int esz, int msize)
int esz, int msize)
{ {
const int esize = 1 << esz; const int esize = 1 << esz;
const uint64_t pg_mask = pred_esz_masks[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 * 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. * there is no work to do, which can only happen with @fault == FAULT_NO.
*/ */
static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
CPUARMState *env, target_ulong addr, CPUARMState *env, target_ulong addr,
MMUAccessType access_type, uintptr_t retaddr) MMUAccessType access_type, uintptr_t retaddr)
{ {
int mmu_idx = cpu_mmu_index(env, false); int mmu_idx = cpu_mmu_index(env, false);
int mem_off = info->mem_off_first[0]; 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; 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 #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; intptr_t mem_off, reg_off, reg_last;
int flags0 = info->page[0].flags; int flags0 = info->page[0].flags;
int flags1 = info->page[1].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 & 63);
} while (reg_off <= reg_last); } while (reg_off <= reg_last);
} }
#endif
} }
#endif
static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env,
uint64_t *vg, target_ulong addr, int esize, uint64_t *vg, target_ulong addr, int esize,
int msize, uint32_t mtedesc, uintptr_t ra) int msize, uint32_t mtedesc, uintptr_t ra)
{ {
intptr_t mem_off, reg_off, reg_last; intptr_t mem_off, reg_off, reg_last;

View 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 */

View File

@ -11,6 +11,32 @@
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/helper-proto.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, static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
unsigned int target_el, unsigned int target_el,
bool same_el, bool ea, bool same_el, bool ea,

View File

@ -14608,7 +14608,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); 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->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
dc->bt = EX_TBFLAG_A64(tb_flags, BT); dc->bt = EX_TBFLAG_A64(tb_flags, BT);
dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE); dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);

View File

@ -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. */ /* Return the byte size of the "whole" vector register, VL / 8. */
static inline int vec_full_reg_size(DisasContext *s) static inline int vec_full_reg_size(DisasContext *s)
{ {
return s->sve_len; return s->vl;
} }
bool disas_sve(DisasContext *, uint32_t); bool disas_sve(DisasContext *, uint32_t);

View File

@ -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. */ /* Return the byte size of the whole predicate register, VL / 64. */
static inline int pred_full_reg_size(DisasContext *s) 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 /* Round up the size of a register to a size allowed by

View File

@ -42,7 +42,7 @@ typedef struct DisasContext {
bool ns; /* Use non-secure CPREG bank on access */ bool ns; /* Use non-secure CPREG bank on access */
int fp_excp_el; /* FP exception EL or 0 if enabled */ int fp_excp_el; /* FP exception EL or 0 if enabled */
int sve_excp_el; /* SVE 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. */ /* Flag indicating that exceptions from secure mode are routed to EL3. */
bool secure_routed_to_el3; bool secure_routed_to_el3;
bool vfp_enabled; /* FP enabled via FPSCR.EN */ bool vfp_enabled; /* FP enabled via FPSCR.EN */

View File

@ -127,6 +127,32 @@ const uint64_t expand_pred_b_data[256] = {
0xffffffffffffffff, 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 */ /* Signed saturating rounding doubling multiply-accumulate high half, 8-bit */
int8_t do_sqrdmlah_b(int8_t src1, int8_t src2, int8_t src3, int8_t do_sqrdmlah_b(int8_t src1, int8_t src2, int8_t src3,
bool neg, bool round) bool neg, bool round)
@ -2531,7 +2557,7 @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b)
* BFloat16 Dot Product * 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. */ /* FPCR is ignored for BFDOT and BFMMLA. */
float_status bf_status = { float_status bf_status = {

View File

@ -50,8 +50,21 @@
#define H8(x) (x) #define H8(x) (x)
#define H1_8(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]; 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) 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); 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 */ #endif /* TARGET_ARM_VEC_INTERNAL_H */

View File

@ -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 /* Convert CPU model data from X86CPU object to a property dictionary
* that can recreate exactly the same CPU model, including every * 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) static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
{ {

View File

@ -330,7 +330,7 @@
#define EPT_VIOLATION_DATA_WRITE (1UL << 1) #define EPT_VIOLATION_DATA_WRITE (1UL << 1)
#define EPT_VIOLATION_INST_FETCH (1UL << 2) #define EPT_VIOLATION_INST_FETCH (1UL << 2)
#define EPT_VIOLATION_GPA_READABLE (1UL << 3) #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_GPA_EXECUTABLE (1UL << 5)
#define EPT_VIOLATION_GLA_VALID (1UL << 7) #define EPT_VIOLATION_GLA_VALID (1UL << 7)
#define EPT_VIOLATION_XLAT_VALID (1UL << 8) #define EPT_VIOLATION_XLAT_VALID (1UL << 8)

View File

@ -80,7 +80,7 @@ static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl)
#define AR_TYPE_ACCESSES_MASK 1 #define AR_TYPE_ACCESSES_MASK 1
#define AR_TYPE_READABLE_MASK (1 << 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_CODE_MASK (1 << 3)
#define AR_TYPE_MASK 0x0f #define AR_TYPE_MASK 0x0f
#define AR_TYPE_BUSY_64_TSS 11 #define AR_TYPE_BUSY_64_TSS 11

View File

@ -284,7 +284,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
g_assert(!s390_is_pv()); g_assert(!s390_is_pv());
/* /*
* As operand exceptions have a lower priority than access exceptions, * 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. * access execption if it is not) first.
*/ */
if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {

View File

@ -56,7 +56,7 @@
* *
* - `ebx`: contains the physical memory address where the loader has placed * - `ebx`: contains the physical memory address where the loader has placed
* the boot start info structure. * 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. * - `cr4`: all bits are cleared.
* - `cs `: must be a 32-bit read/execute code segment with a base of 0 * - `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. * and a limit of 0xFFFFFFFF. The selector value is unspecified.