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;
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)) {
/*

View File

@ -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

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.
*
* 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.

View File

@ -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

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
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:

View File

@ -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)

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++) {
/*
* 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)
*/

View File

@ -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

View File

@ -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)

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;
}
/* 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;

View File

@ -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);

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;
* 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

View File

@ -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);

View File

@ -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) &&

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_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;

View File

@ -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

View File

@ -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;

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;
/* 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)) {

View File

@ -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"

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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?"
*/

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
* 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;

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
* 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);

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
* 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:

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

View File

@ -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

View File

@ -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, &reg);
}

View File

@ -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();
}

View File

@ -58,6 +58,7 @@ arm_softmmu_ss.add(files(
'machine.c',
'monitor.c',
'psci.c',
'ptw.c',
))
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)
{
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

File diff suppressed because it is too large Load Diff

View File

@ -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;

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/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,

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->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);

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. */
static inline int vec_full_reg_size(DisasContext *s)
{
return s->sve_len;
return s->vl;
}
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. */
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

View File

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

View File

@ -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 = {

View File

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

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
* 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)
{

View File

@ -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)

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_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

View File

@ -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))) {

View File

@ -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.