target-arm queue:

* Optimize codegen for MVE when predication not active
  * hvf: Add Apple Silicon support
  * hw/intc: Set GIC maintenance interrupt level to only 0 or 1
  * Fix mishandling of MVE FPSCR.LTPSIZE reset for usermode emulator
  * elf2dmp: Fix coverity nits
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmFJ+sUZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oxLEACJSAHzww9iuVa18kTr0A8L
 Zi5IXewym/XIBGI0dzSdcWm+KmwLSsWQCE267M8/wG+H4aPwkWKk5y9DjIUyvFd4
 ozxgaAuQtIFZDlubZ1VdVo3b+cMfF0xLye8iIjeYUIDfoYAZzN9+KH8ctD0PWgLm
 3FivfVjFzX5KnC2bOi6P13bzZxPoyQPExcQbtf85Whaujui40rPLrVsnl+6N3ulw
 sgBYUjT8jxECdBLh/kaSqt33WoAL23amIPfuZl/juNQwxtXYu+tCyFHtOxVNZ4Rt
 BOOYHgCDWJNKjdts2CA/YqITOyk44hMfRAYZKuSQAz1BVZVi2Z8FDgjTwAzc9inE
 /nB6EqT/67tF8lGUg0w9OnsGCSA6px3xUYUYrZk7efo7oGcyknsleDbuKE76UHE0
 plFuUPZyc0jBGKdSwZGBwzc5UkA3qmcoN83HAl2jE/5piHTaqqyu7KSqMXymwAij
 WGOO5L2Svgwi+11BgfEFbPbgKOz+XwwvAMXj1drQm6Nf0hKt1YQYvH6oQQYoqjT+
 bkUrejjOb04tyA50KTqz4gbj9s8B3/cPSuD3xWl390bDbP7jpgFOmffVj5A16wbx
 DL7rmwnghoOI3T+5uXXNQFA856XfuVWy1gtwpFzCYZu4hseNPw+MXKwj4YUfM/V3
 QonDlN98W4C5M2u4CW09Zw==
 =vapC
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210921' into staging

target-arm queue:
 * Optimize codegen for MVE when predication not active
 * hvf: Add Apple Silicon support
 * hw/intc: Set GIC maintenance interrupt level to only 0 or 1
 * Fix mishandling of MVE FPSCR.LTPSIZE reset for usermode emulator
 * elf2dmp: Fix coverity nits

# gpg: Signature made Tue 21 Sep 2021 16:31:17 BST
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20210921: (27 commits)
  target/arm: Optimize MVE 1op-immediate insns
  target/arm: Optimize MVE VSLI and VSRI
  target/arm: Optimize MVE VSHLL and VMOVL
  target/arm: Optimize MVE VSHL, VSHR immediate forms
  target/arm: Optimize MVE VMVN
  target/arm: Optimize MVE VDUP
  target/arm: Optimize MVE VNEG, VABS
  target/arm: Optimize MVE arithmetic ops
  target/arm: Optimize MVE logic ops
  target/arm: Add TB flag for "MVE insns not predicated"
  target/arm: Enforce that FPDSCR.LTPSIZE is 4 on inbound migration
  target/arm: Avoid goto_tb if we're trying to exit to the main loop
  hvf: arm: Add rudimentary PMC support
  arm: Add Hypervisor.framework build target
  hvf: arm: Implement PSCI handling
  hvf: arm: Implement -cpu host
  arm/hvf: Add a WFI handler
  hvf: Add Apple Silicon support
  hvf: Introduce hvf_arch_init() callback
  hvf: Add execute to dirty log permission bitmap
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-21 16:32:19 +01:00
commit 81ceb36b96
24 changed files with 1825 additions and 168 deletions

View File

@ -433,6 +433,11 @@ F: accel/accel-*.c
F: accel/Makefile.objs
F: accel/stubs/Makefile.objs
Apple Silicon HVF CPUs
M: Alexander Graf <agraf@csgraf.de>
S: Maintained
F: target/arm/hvf/
X86 HVF CPUs
M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <r.bolshakov@yadro.com>

View File

@ -60,6 +60,10 @@
HVFState *hvf_state;
#ifdef __aarch64__
#define HV_VM_DEFAULT NULL
#endif
/* Memory slots */
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
@ -239,12 +243,12 @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
if (on) {
slot->flags |= HVF_SLOT_LOG;
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
HV_MEMORY_READ);
HV_MEMORY_READ | HV_MEMORY_EXEC);
/* stop tracking region*/
} else {
slot->flags &= ~HVF_SLOT_LOG;
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
HV_MEMORY_READ | HV_MEMORY_WRITE);
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
}
}
@ -324,7 +328,8 @@ static int hvf_accel_init(MachineState *ms)
hvf_state = s;
memory_listener_register(&hvf_memory_listener, &address_space_memory);
return 0;
return hvf_arch_init();
}
static void hvf_accel_class_init(ObjectClass *oc, void *data)
@ -365,17 +370,20 @@ static int hvf_init_vcpu(CPUState *cpu)
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
/* init cpu signals */
sigset_t set;
struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = dummy_signal;
sigaction(SIG_IPI, &sigact, NULL);
pthread_sigmask(SIG_BLOCK, NULL, &set);
sigdelset(&set, SIG_IPI);
pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
#ifdef __aarch64__
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
#else
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
#endif
cpu->vcpu_dirty = 1;
assert_hvf_ok(r);
@ -451,6 +459,7 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
ops->create_vcpu_thread = hvf_start_vcpu_thread;
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;

View File

@ -25,21 +25,19 @@ int download_url(const char *name, const char *url)
goto out_curl;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
if (curl_easy_perform(curl) != CURLE_OK) {
err = 1;
fclose(file);
if (curl_easy_setopt(curl, CURLOPT_URL, url) != CURLE_OK
|| curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL) != CURLE_OK
|| curl_easy_setopt(curl, CURLOPT_WRITEDATA, file) != CURLE_OK
|| curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK
|| curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK
|| curl_easy_perform(curl) != CURLE_OK) {
unlink(name);
goto out_curl;
fclose(file);
err = 1;
} else {
err = fclose(file);
}
err = fclose(file);
out_curl:
curl_easy_cleanup(curl);

View File

@ -215,6 +215,10 @@ out_symbols:
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
{
if (hdr->block_size == 0) {
return 1;
}
memset(r->file_used, 0, sizeof(r->file_used));
r->ds.header = hdr;
r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +

View File

@ -417,8 +417,9 @@ static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
}
}
if (cs->ich_hcr_el2 & ICH_HCR_EL2_EN) {
maintlevel = maintenance_interrupt_state(cs);
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_EN) &&
maintenance_interrupt_state(cs) != 0) {
maintlevel = 1;
}
trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel,

View File

@ -11,7 +11,11 @@
#ifndef HVF_INT_H
#define HVF_INT_H
#ifdef __aarch64__
#include <Hypervisor/Hypervisor.h>
#else
#include <Hypervisor/hv.h>
#endif
/* hvf_slot flags */
#define HVF_SLOT_LOG (1 << 0)
@ -40,19 +44,25 @@ struct HVFState {
int num_slots;
hvf_vcpu_caps *hvf_caps;
uint64_t vtimer_offset;
};
extern HVFState *hvf_state;
struct hvf_vcpu_state {
int fd;
uint64_t fd;
void *exit;
bool vtimer_masked;
sigset_t unblock_ipi_mask;
};
void assert_hvf_ok(hv_return_t ret);
int hvf_arch_init(void);
int hvf_arch_init_vcpu(CPUState *cpu);
void hvf_arch_vcpu_destroy(CPUState *cpu);
int hvf_vcpu_exec(CPUState *);
hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t);
int hvf_put_registers(CPUState *);
int hvf_get_registers(CPUState *);
void hvf_kick_vcpu_thread(CPUState *cpu);
#endif

View File

@ -77,6 +77,13 @@ else
endif
accelerator_targets = { 'CONFIG_KVM': kvm_targets }
if cpu in ['aarch64']
accelerator_targets += {
'CONFIG_HVF': ['aarch64-softmmu']
}
endif
if cpu in ['x86', 'x86_64', 'arm', 'aarch64']
# i386 emulator provides xenpv machine type for multiple architectures
accelerator_targets += {
@ -2169,6 +2176,7 @@ if have_system or have_user
'accel/tcg',
'hw/core',
'target/arm',
'target/arm/hvf',
'target/hppa',
'target/i386',
'target/i386/kvm',

View File

@ -39,6 +39,7 @@
#include "sysemu/tcg.h"
#include "sysemu/hw_accel.h"
#include "kvm_arm.h"
#include "hvf_arm.h"
#include "disas/capstone.h"
#include "fpu/softfloat.h"
@ -266,11 +267,24 @@ static void arm_cpu_reset(DeviceState *dev)
}
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
* executing as AArch32 then check if highvecs are enabled and
* adjust the PC accordingly.
*/
if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
env->regs[15] = 0xFFFF0000;
}
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif
if (arm_feature(env, ARM_FEATURE_M)) {
#ifndef CONFIG_USER_ONLY
uint32_t initial_msp; /* Loaded from 0x0 */
uint32_t initial_pc; /* Loaded from 0x4 */
uint8_t *rom;
uint32_t vecbase;
#endif
if (cpu_isar_feature(aa32_lob, cpu)) {
/*
@ -324,6 +338,8 @@ static void arm_cpu_reset(DeviceState *dev)
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
}
#ifndef CONFIG_USER_ONLY
/* Unlike A/R profile, M profile defines the reset LR value */
env->regs[14] = 0xffffffff;
@ -352,14 +368,19 @@ static void arm_cpu_reset(DeviceState *dev)
env->regs[13] = initial_msp & 0xFFFFFFFC;
env->regs[15] = initial_pc & ~1;
env->thumb = initial_pc & 1;
}
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
* executing as AArch32 then check if highvecs are enabled and
* adjust the PC accordingly.
*/
if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
env->regs[15] = 0xFFFF0000;
#else
/*
* For user mode we run non-secure and with access to the FPU.
* The FPU context is active (ie does not need further setup)
* and is owned by non-secure.
*/
env->v7m.secure = false;
env->v7m.nsacr = 0xcff;
env->v7m.cpacr[M_REG_NS] = 0xf0ffff;
env->v7m.fpccr[M_REG_S] &=
~(R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK);
env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
#endif
}
/* M profile requires that reset clears the exclusive monitor;
@ -368,9 +389,6 @@ static void arm_cpu_reset(DeviceState *dev)
*/
arm_clear_exclusive(env);
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif
if (arm_feature(env, ARM_FEATURE_PMSA)) {
if (cpu->pmsav7_dregion > 0) {
if (arm_feature(env, ARM_FEATURE_V8)) {
@ -1095,8 +1113,8 @@ static void arm_cpu_initfn(Object *obj)
cpu->psci_version = 1; /* By default assume PSCI v0.1 */
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
if (tcg_enabled()) {
cpu->psci_version = 2; /* TCG implements PSCI 0.2 */
if (tcg_enabled() || hvf_enabled()) {
cpu->psci_version = 2; /* TCG and HVF implement PSCI 0.2 */
}
}
@ -1400,8 +1418,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
* this is the first point where we can report it.
*/
if (cpu->host_cpu_probe_failed) {
if (!kvm_enabled()) {
error_setg(errp, "The 'host' CPU type can only be used with KVM");
if (!kvm_enabled() && !hvf_enabled()) {
error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
} else {
error_setg(errp, "Failed to retrieve host CPU features");
}
@ -2061,15 +2079,19 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#endif /* CONFIG_TCG */
}
#ifdef CONFIG_KVM
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
static void arm_host_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
#ifdef CONFIG_KVM
kvm_arm_set_cpu_features_from_host(cpu);
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
aarch64_add_sve_properties(obj);
}
#else
hvf_arm_set_cpu_features_from_host(cpu);
#endif
arm_cpu_post_init(obj);
}
@ -2129,7 +2151,7 @@ static void arm_cpu_register_types(void)
{
type_register_static(&arm_cpu_type_info);
#ifdef CONFIG_KVM
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
type_register_static(&host_arm_cpu_type_info);
#endif
}

View File

@ -3015,6 +3015,8 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
#define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
#define CPU_RESOLVING_TYPE TYPE_ARM_CPU
#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
@ -3439,7 +3441,7 @@ typedef ARMCPU ArchCPU;
* | TBFLAG_AM32 | +-----+----------+
* | | |TBFLAG_M32|
* +-------------+----------------+----------+
* 31 23 5 4 0
* 31 23 6 5 0
*
* Unless otherwise noted, these bits are cached in env->hflags.
*/
@ -3497,6 +3499,8 @@ FIELD(TBFLAG_M32, LSPACT, 2, 1) /* Not cached. */
FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 3, 1) /* Not cached. */
/* Set if FPCCR.S does not match current security state */
FIELD(TBFLAG_M32, FPCCR_S_WRONG, 4, 1) /* Not cached. */
/* Set if MVE insns are definitely not predicated by VPR or LTPSIZE */
FIELD(TBFLAG_M32, MVE_NO_PRED, 5, 1) /* Not cached. */
/*
* Bit usage when in AArch64 state

View File

@ -1114,50 +1114,6 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
REGINFO_SENTINEL
};
/* Definitions for the PMU registers */
#define PMCRN_MASK 0xf800
#define PMCRN_SHIFT 11
#define PMCRLC 0x40
#define PMCRDP 0x20
#define PMCRX 0x10
#define PMCRD 0x8
#define PMCRC 0x4
#define PMCRP 0x2
#define PMCRE 0x1
/*
* Mask of PMCR bits writeable 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 PMXEVTYPER_P 0x80000000
#define PMXEVTYPER_U 0x40000000
#define PMXEVTYPER_NSK 0x20000000
#define PMXEVTYPER_NSU 0x10000000
#define PMXEVTYPER_NSH 0x08000000
#define PMXEVTYPER_M 0x04000000
#define PMXEVTYPER_MT 0x02000000
#define PMXEVTYPER_EVTCOUNT 0x0000ffff
#define PMXEVTYPER_MASK (PMXEVTYPER_P | PMXEVTYPER_U | PMXEVTYPER_NSK | \
PMXEVTYPER_NSU | PMXEVTYPER_NSH | \
PMXEVTYPER_M | PMXEVTYPER_MT | \
PMXEVTYPER_EVTCOUNT)
#define PMCCFILTR 0xf8000000
#define PMCCFILTR_M PMXEVTYPER_M
#define PMCCFILTR_EL0 (PMCCFILTR | PMCCFILTR_M)
static inline uint32_t pmu_num_counters(CPUARMState *env)
{
return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT;
}
/* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */
static inline uint64_t pmu_counter_mask(CPUARMState *env)
{
return (1 << 31) | ((1 << pmu_num_counters(env)) - 1);
}
typedef struct pm_event {
uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */
/* If the event is supported on this CPU (used to generate PMCEID[01]) */
@ -13681,6 +13637,35 @@ static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
#endif
}
static bool mve_no_pred(CPUARMState *env)
{
/*
* Return true if there is definitely no predication of MVE
* instructions by VPR or LTPSIZE. (Returning false even if there
* isn't any predication is OK; generated code will just be
* a little worse.)
* If the CPU does not implement MVE then this TB flag is always 0.
*
* NOTE: if you change this logic, the "recalculate s->mve_no_pred"
* logic in gen_update_fp_context() needs to be updated to match.
*
* We do not include the effect of the ECI bits here -- they are
* tracked in other TB flags. This simplifies the logic for
* "when did we emit code that changes the MVE_NO_PRED TB flag
* and thus need to end the TB?".
*/
if (cpu_isar_feature(aa32_mve, env_archcpu(env))) {
return false;
}
if (env->v7m.vpr) {
return false;
}
if (env->v7m.ltpsize < 4) {
return false;
}
return true;
}
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
@ -13720,6 +13705,10 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
DP_TBFLAG_M32(flags, LSPACT, 1);
}
if (mve_no_pred(env)) {
DP_TBFLAG_M32(flags, MVE_NO_PRED, 1);
}
} else {
/*
* Note that XSCALE_CPAR shares bits with VECSTRIDE.

1278
target/arm/hvf/hvf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
arm_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
'hvf.c',
))

View File

@ -0,0 +1,11 @@
hvf_unhandled_sysreg_read(uint64_t pc, uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2) "unhandled sysreg read at pc=0x%"PRIx64": 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d)"
hvf_unhandled_sysreg_write(uint64_t pc, uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2) "unhandled sysreg write at pc=0x%"PRIx64": 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d)"
hvf_inject_fiq(void) "injecting FIQ"
hvf_inject_irq(void) "injecting IRQ"
hvf_data_abort(uint64_t pc, uint64_t va, uint64_t pa, bool isv, bool iswrite, bool s1ptw, uint32_t len, uint32_t srt) "data abort: [pc=0x%"PRIx64" va=0x%016"PRIx64" pa=0x%016"PRIx64" isv=%d iswrite=%d s1ptw=%d len=%d srt=%d]"
hvf_sysreg_read(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg read 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d) = 0x%016"PRIx64
hvf_sysreg_write(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg write 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d, val=0x%016"PRIx64")"
hvf_unknown_hvc(uint64_t x0) "unknown HVC! 0x%016"PRIx64
hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64
hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]"
hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpu=0x%x"

18
target/arm/hvf_arm.h Normal file
View File

@ -0,0 +1,18 @@
/*
* QEMU Hypervisor.framework (HVF) support -- ARM specifics
*
* Copyright (c) 2021 Alexander Graf
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_HVF_ARM_H
#define QEMU_HVF_ARM_H
#include "cpu.h"
void hvf_arm_set_cpu_features_from_host(struct ARMCPU *cpu);
#endif

View File

@ -1226,4 +1226,48 @@ enum MVEECIState {
/* All other values reserved */
};
/* Definitions for the PMU registers */
#define PMCRN_MASK 0xf800
#define PMCRN_SHIFT 11
#define PMCRLC 0x40
#define PMCRDP 0x20
#define PMCRX 0x10
#define PMCRD 0x8
#define PMCRC 0x4
#define PMCRP 0x2
#define PMCRE 0x1
/*
* Mask of PMCR bits writeable 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 PMXEVTYPER_P 0x80000000
#define PMXEVTYPER_U 0x40000000
#define PMXEVTYPER_NSK 0x20000000
#define PMXEVTYPER_NSU 0x10000000
#define PMXEVTYPER_NSH 0x08000000
#define PMXEVTYPER_M 0x04000000
#define PMXEVTYPER_MT 0x02000000
#define PMXEVTYPER_EVTCOUNT 0x0000ffff
#define PMXEVTYPER_MASK (PMXEVTYPER_P | PMXEVTYPER_U | PMXEVTYPER_NSK | \
PMXEVTYPER_NSU | PMXEVTYPER_NSH | \
PMXEVTYPER_M | PMXEVTYPER_MT | \
PMXEVTYPER_EVTCOUNT)
#define PMCCFILTR 0xf8000000
#define PMCCFILTR_M PMXEVTYPER_M
#define PMCCFILTR_EL0 (PMCCFILTR | PMCCFILTR_M)
static inline uint32_t pmu_num_counters(CPUARMState *env)
{
return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT;
}
/* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */
static inline uint64_t pmu_counter_mask(CPUARMState *env)
{
return (1 << 31) | ((1 << pmu_num_counters(env)) - 1);
}
#endif

View File

@ -214,8 +214,6 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
*/
void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
/**
* ARMHostCPUFeatures: information about the host CPU (identified
* by asking the host kernel)

View File

@ -781,6 +781,19 @@ static int cpu_post_load(void *opaque, int version_id)
hw_breakpoint_update_all(cpu);
hw_watchpoint_update_all(cpu);
/*
* TCG gen_update_fp_context() relies on the invariant that
* FPDSCR.LTPSIZE is constant 4 for M-profile with the LOB extension;
* forbid bogus incoming data with some other value.
*/
if (arm_feature(env, ARM_FEATURE_M) && cpu_isar_feature(aa32_lob, cpu)) {
if (extract32(env->v7m.fpdscr[M_REG_NS],
FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4 ||
extract32(env->v7m.fpdscr[M_REG_S],
FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4) {
return -1;
}
}
if (!kvm_enabled()) {
pmu_op_finish(&cpu->env);
}

View File

@ -60,5 +60,7 @@ arm_softmmu_ss.add(files(
'psci.c',
))
subdir('hvf')
target_arch += {'arm': arm_ss}
target_softmmu_arch += {'arm': arm_softmmu_ss}

View File

@ -95,7 +95,10 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
clear_eci_state(s);
/* End the TB, because we have updated FP control bits */
/*
* End the TB, because we have updated FP control bits,
* and possibly VPR or LTPSIZE.
*/
s->base.is_jmp = DISAS_UPDATE_EXIT;
return true;
}
@ -397,6 +400,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
store_cpu_field(control, v7m.control[M_REG_S]);
tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK);
gen_helper_vfp_set_fpscr(cpu_env, tmp);
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(sfpa);
break;
@ -409,6 +413,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
}
tmp = loadfn(s, opaque, true);
store_cpu_field(tmp, v7m.vpr);
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
break;
case ARM_VFP_P0:
{
@ -418,6 +423,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
tcg_gen_deposit_i32(vpr, vpr, tmp,
R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
store_cpu_field(vpr, v7m.vpr);
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
tcg_temp_free_i32(tmp);
break;
}

View File

@ -64,6 +64,16 @@ static TCGv_ptr mve_qreg_ptr(unsigned reg)
return ret;
}
static bool mve_no_predication(DisasContext *s)
{
/*
* Return true if we are executing the entire MVE instruction
* with no predication or partial-execution, and so we can safely
* use an inline TCG vector implementation.
*/
return s->eci == 0 && s->mve_no_pred;
}
static bool mve_check_qreg_bank(DisasContext *s, int qmask)
{
/*
@ -490,17 +500,22 @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
return true;
}
qd = mve_qreg_ptr(a->qd);
rt = load_reg(s, a->rt);
tcg_gen_dup_i32(a->size, rt, rt);
gen_helper_mve_vdup(cpu_env, qd, rt);
tcg_temp_free_ptr(qd);
if (mve_no_predication(s)) {
tcg_gen_gvec_dup_i32(a->size, mve_qreg_offset(a->qd), 16, 16, rt);
} else {
qd = mve_qreg_ptr(a->qd);
tcg_gen_dup_i32(a->size, rt, rt);
gen_helper_mve_vdup(cpu_env, qd, rt);
tcg_temp_free_ptr(qd);
}
tcg_temp_free_i32(rt);
mve_update_eci(s);
return true;
}
static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
static bool do_1op_vec(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn,
GVecGen2Fn vecfn)
{
TCGv_ptr qd, qm;
@ -514,16 +529,25 @@ static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
return true;
}
qd = mve_qreg_ptr(a->qd);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qm);
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qm);
if (vecfn && mve_no_predication(s)) {
vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm), 16, 16);
} else {
qd = mve_qreg_ptr(a->qd);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qm);
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qm);
}
mve_update_eci(s);
return true;
}
#define DO_1OP(INSN, FN) \
static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
{
return do_1op_vec(s, a, fn, NULL);
}
#define DO_1OP_VEC(INSN, FN, VECFN) \
static bool trans_##INSN(DisasContext *s, arg_1op *a) \
{ \
static MVEGenOneOpFn * const fns[] = { \
@ -532,13 +556,15 @@ static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
gen_helper_mve_##FN##w, \
NULL, \
}; \
return do_1op(s, a, fns[a->size]); \
return do_1op_vec(s, a, fns[a->size], VECFN); \
}
#define DO_1OP(INSN, FN) DO_1OP_VEC(INSN, FN, NULL)
DO_1OP(VCLZ, vclz)
DO_1OP(VCLS, vcls)
DO_1OP(VABS, vabs)
DO_1OP(VNEG, vneg)
DO_1OP_VEC(VABS, vabs, tcg_gen_gvec_abs)
DO_1OP_VEC(VNEG, vneg, tcg_gen_gvec_neg)
DO_1OP(VQABS, vqabs)
DO_1OP(VQNEG, vqneg)
DO_1OP(VMAXA, vmaxa)
@ -743,7 +769,7 @@ static bool trans_VREV64(DisasContext *s, arg_1op *a)
static bool trans_VMVN(DisasContext *s, arg_1op *a)
{
return do_1op(s, a, gen_helper_mve_vmvn);
return do_1op_vec(s, a, gen_helper_mve_vmvn, tcg_gen_gvec_not);
}
static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
@ -774,7 +800,8 @@ static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
return do_1op(s, a, fns[a->size]);
}
static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
static bool do_2op_vec(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn,
GVecGen3Fn *vecfn)
{
TCGv_ptr qd, qn, qm;
@ -787,32 +814,47 @@ static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
return true;
}
qd = mve_qreg_ptr(a->qd);
qn = mve_qreg_ptr(a->qn);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qn, qm);
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qn);
tcg_temp_free_ptr(qm);
if (vecfn && mve_no_predication(s)) {
vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qn),
mve_qreg_offset(a->qm), 16, 16);
} else {
qd = mve_qreg_ptr(a->qd);
qn = mve_qreg_ptr(a->qn);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qn, qm);
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qn);
tcg_temp_free_ptr(qm);
}
mve_update_eci(s);
return true;
}
#define DO_LOGIC(INSN, HELPER) \
static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn *fn)
{
return do_2op_vec(s, a, fn, NULL);
}
#define DO_LOGIC(INSN, HELPER, VECFN) \
static bool trans_##INSN(DisasContext *s, arg_2op *a) \
{ \
return do_2op(s, a, HELPER); \
return do_2op_vec(s, a, HELPER, VECFN); \
}
DO_LOGIC(VAND, gen_helper_mve_vand)
DO_LOGIC(VBIC, gen_helper_mve_vbic)
DO_LOGIC(VORR, gen_helper_mve_vorr)
DO_LOGIC(VORN, gen_helper_mve_vorn)
DO_LOGIC(VEOR, gen_helper_mve_veor)
DO_LOGIC(VAND, gen_helper_mve_vand, tcg_gen_gvec_and)
DO_LOGIC(VBIC, gen_helper_mve_vbic, tcg_gen_gvec_andc)
DO_LOGIC(VORR, gen_helper_mve_vorr, tcg_gen_gvec_or)
DO_LOGIC(VORN, gen_helper_mve_vorn, tcg_gen_gvec_orc)
DO_LOGIC(VEOR, gen_helper_mve_veor, tcg_gen_gvec_xor)
DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
static bool trans_VPSEL(DisasContext *s, arg_2op *a)
{
/* This insn updates predication bits */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
return do_2op(s, a, gen_helper_mve_vpsel);
}
#define DO_2OP(INSN, FN) \
#define DO_2OP_VEC(INSN, FN, VECFN) \
static bool trans_##INSN(DisasContext *s, arg_2op *a) \
{ \
static MVEGenTwoOpFn * const fns[] = { \
@ -821,20 +863,22 @@ DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
gen_helper_mve_##FN##w, \
NULL, \
}; \
return do_2op(s, a, fns[a->size]); \
return do_2op_vec(s, a, fns[a->size], VECFN); \
}
DO_2OP(VADD, vadd)
DO_2OP(VSUB, vsub)
DO_2OP(VMUL, vmul)
#define DO_2OP(INSN, FN) DO_2OP_VEC(INSN, FN, NULL)
DO_2OP_VEC(VADD, vadd, tcg_gen_gvec_add)
DO_2OP_VEC(VSUB, vsub, tcg_gen_gvec_sub)
DO_2OP_VEC(VMUL, vmul, tcg_gen_gvec_mul)
DO_2OP(VMULH_S, vmulhs)
DO_2OP(VMULH_U, vmulhu)
DO_2OP(VRMULH_S, vrmulhs)
DO_2OP(VRMULH_U, vrmulhu)
DO_2OP(VMAX_S, vmaxs)
DO_2OP(VMAX_U, vmaxu)
DO_2OP(VMIN_S, vmins)
DO_2OP(VMIN_U, vminu)
DO_2OP_VEC(VMAX_S, vmaxs, tcg_gen_gvec_smax)
DO_2OP_VEC(VMAX_U, vmaxu, tcg_gen_gvec_umax)
DO_2OP_VEC(VMIN_S, vmins, tcg_gen_gvec_smin)
DO_2OP_VEC(VMIN_U, vminu, tcg_gen_gvec_umin)
DO_2OP(VABD_S, vabds)
DO_2OP(VABD_U, vabdu)
DO_2OP(VHADD_S, vhadds)
@ -1366,6 +1410,8 @@ static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a)
}
gen_helper_mve_vpnot(cpu_env);
/* This insn updates predication bits */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
mve_update_eci(s);
return true;
}
@ -1475,7 +1521,8 @@ static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
return true;
}
static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn,
GVecGen2iFn *vecfn)
{
TCGv_ptr qd;
uint64_t imm;
@ -1491,17 +1538,29 @@ static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
imm = asimd_imm_const(a->imm, a->cmode, a->op);
qd = mve_qreg_ptr(a->qd);
fn(cpu_env, qd, tcg_constant_i64(imm));
tcg_temp_free_ptr(qd);
if (vecfn && mve_no_predication(s)) {
vecfn(MO_64, mve_qreg_offset(a->qd), mve_qreg_offset(a->qd),
imm, 16, 16);
} else {
qd = mve_qreg_ptr(a->qd);
fn(cpu_env, qd, tcg_constant_i64(imm));
tcg_temp_free_ptr(qd);
}
mve_update_eci(s);
return true;
}
static void gen_gvec_vmovi(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t c, uint32_t oprsz, uint32_t maxsz)
{
tcg_gen_gvec_dup_imm(vece, dofs, oprsz, maxsz, c);
}
static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
{
/* Handle decode of cmode/op here between VORR/VBIC/VMOV */
MVEGenOneOpImmFn *fn;
GVecGen2iFn *vecfn;
if ((a->cmode & 1) && a->cmode < 12) {
if (a->op) {
@ -1510,8 +1569,10 @@ static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
* so the VBIC becomes a logical AND operation.
*/
fn = gen_helper_mve_vandi;
vecfn = tcg_gen_gvec_andi;
} else {
fn = gen_helper_mve_vorri;
vecfn = tcg_gen_gvec_ori;
}
} else {
/* There is one unallocated cmode/op combination in this space */
@ -1520,12 +1581,13 @@ static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
}
/* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
fn = gen_helper_mve_vmovi;
vecfn = gen_gvec_vmovi;
}
return do_1imm(s, a, fn);
return do_1imm(s, a, fn, vecfn);
}
static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
bool negateshift)
static bool do_2shift_vec(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
bool negateshift, GVecGen2iFn vecfn)
{
TCGv_ptr qd, qm;
int shift = a->shift;
@ -1548,39 +1610,82 @@ static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
shift = -shift;
}
qd = mve_qreg_ptr(a->qd);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qm, tcg_constant_i32(shift));
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qm);
if (vecfn && mve_no_predication(s)) {
vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm),
shift, 16, 16);
} else {
qd = mve_qreg_ptr(a->qd);
qm = mve_qreg_ptr(a->qm);
fn(cpu_env, qd, qm, tcg_constant_i32(shift));
tcg_temp_free_ptr(qd);
tcg_temp_free_ptr(qm);
}
mve_update_eci(s);
return true;
}
#define DO_2SHIFT(INSN, FN, NEGATESHIFT) \
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
{ \
static MVEGenTwoOpShiftFn * const fns[] = { \
gen_helper_mve_##FN##b, \
gen_helper_mve_##FN##h, \
gen_helper_mve_##FN##w, \
NULL, \
}; \
return do_2shift(s, a, fns[a->size], NEGATESHIFT); \
static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
bool negateshift)
{
return do_2shift_vec(s, a, fn, negateshift, NULL);
}
#define DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, VECFN) \
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
{ \
static MVEGenTwoOpShiftFn * const fns[] = { \
gen_helper_mve_##FN##b, \
gen_helper_mve_##FN##h, \
gen_helper_mve_##FN##w, \
NULL, \
}; \
return do_2shift_vec(s, a, fns[a->size], NEGATESHIFT, VECFN); \
}
DO_2SHIFT(VSHLI, vshli_u, false)
#define DO_2SHIFT(INSN, FN, NEGATESHIFT) \
DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, NULL)
static void do_gvec_shri_s(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
/*
* We get here with a negated shift count, and we must handle
* shifts by the element size, which tcg_gen_gvec_sari() does not do.
*/
shift = -shift;
if (shift == (8 << vece)) {
shift--;
}
tcg_gen_gvec_sari(vece, dofs, aofs, shift, oprsz, maxsz);
}
static void do_gvec_shri_u(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
/*
* We get here with a negated shift count, and we must handle
* shifts by the element size, which tcg_gen_gvec_shri() does not do.
*/
shift = -shift;
if (shift == (8 << vece)) {
tcg_gen_gvec_dup_imm(vece, dofs, oprsz, maxsz, 0);
} else {
tcg_gen_gvec_shri(vece, dofs, aofs, shift, oprsz, maxsz);
}
}
DO_2SHIFT_VEC(VSHLI, vshli_u, false, tcg_gen_gvec_shli)
DO_2SHIFT(VQSHLI_S, vqshli_s, false)
DO_2SHIFT(VQSHLI_U, vqshli_u, false)
DO_2SHIFT(VQSHLUI, vqshlui_s, false)
/* These right shifts use a left-shift helper with negated shift count */
DO_2SHIFT(VSHRI_S, vshli_s, true)
DO_2SHIFT(VSHRI_U, vshli_u, true)
DO_2SHIFT_VEC(VSHRI_S, vshli_s, true, do_gvec_shri_s)
DO_2SHIFT_VEC(VSHRI_U, vshli_u, true, do_gvec_shri_u)
DO_2SHIFT(VRSHRI_S, vrshli_s, true)
DO_2SHIFT(VRSHRI_U, vrshli_u, true)
DO_2SHIFT(VSRI, vsri, false)
DO_2SHIFT(VSLI, vsli, false)
DO_2SHIFT_VEC(VSRI, vsri, false, gen_gvec_sri)
DO_2SHIFT_VEC(VSLI, vsli, false, gen_gvec_sli)
#define DO_2SHIFT_FP(INSN, FN) \
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
@ -1646,16 +1751,67 @@ DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
#define DO_VSHLL(INSN, FN) \
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
{ \
static MVEGenTwoOpShiftFn * const fns[] = { \
gen_helper_mve_##FN##b, \
gen_helper_mve_##FN##h, \
}; \
return do_2shift(s, a, fns[a->size], false); \
#define DO_VSHLL(INSN, FN) \
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
{ \
static MVEGenTwoOpShiftFn * const fns[] = { \
gen_helper_mve_##FN##b, \
gen_helper_mve_##FN##h, \
}; \
return do_2shift_vec(s, a, fns[a->size], false, do_gvec_##FN); \
}
/*
* For the VSHLL vector helpers, the vece is the size of the input
* (ie MO_8 or MO_16); the helpers want to work in the output size.
* The shift count can be 0..<input size>, inclusive. (0 is VMOVL.)
*/
static void do_gvec_vshllbs(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
unsigned ovece = vece + 1;
unsigned ibits = vece == MO_8 ? 8 : 16;
tcg_gen_gvec_shli(ovece, dofs, aofs, ibits, oprsz, maxsz);
tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
}
static void do_gvec_vshllbu(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
unsigned ovece = vece + 1;
tcg_gen_gvec_andi(ovece, dofs, aofs,
ovece == MO_16 ? 0xff : 0xffff, oprsz, maxsz);
tcg_gen_gvec_shli(ovece, dofs, dofs, shift, oprsz, maxsz);
}
static void do_gvec_vshllts(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
unsigned ovece = vece + 1;
unsigned ibits = vece == MO_8 ? 8 : 16;
if (shift == 0) {
tcg_gen_gvec_sari(ovece, dofs, aofs, ibits, oprsz, maxsz);
} else {
tcg_gen_gvec_andi(ovece, dofs, aofs,
ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
}
}
static void do_gvec_vshlltu(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz)
{
unsigned ovece = vece + 1;
unsigned ibits = vece == MO_8 ? 8 : 16;
if (shift == 0) {
tcg_gen_gvec_shri(ovece, dofs, aofs, ibits, oprsz, maxsz);
} else {
tcg_gen_gvec_andi(ovece, dofs, aofs,
ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
tcg_gen_gvec_shri(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
}
}
DO_VSHLL(VSHLL_BS, vshllbs)
DO_VSHLL(VSHLL_BU, vshllbu)
DO_VSHLL(VSHLL_TS, vshllts)
@ -1852,6 +2008,8 @@ static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
/* VPT */
gen_vpst(s, a->mask);
}
/* This insn updates predication bits */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
mve_update_eci(s);
return true;
}
@ -1883,6 +2041,8 @@ static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
/* VPT */
gen_vpst(s, a->mask);
}
/* This insn updates predication bits */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
mve_update_eci(s);
return true;
}

View File

@ -109,7 +109,7 @@ static inline long vfp_f16_offset(unsigned reg, bool top)
* Generate code for M-profile lazy FP state preservation if needed;
* this corresponds to the pseudocode PreserveFPState() function.
*/
static void gen_preserve_fp_state(DisasContext *s)
static void gen_preserve_fp_state(DisasContext *s, bool skip_context_update)
{
if (s->v7m_lspact) {
/*
@ -128,6 +128,20 @@ static void gen_preserve_fp_state(DisasContext *s)
* any further FP insns in this TB.
*/
s->v7m_lspact = false;
/*
* The helper might have zeroed VPR, so we do not know the
* correct value for the MVE_NO_PRED TB flag any more.
* If we're about to create a new fp context then that
* will precisely determine the MVE_NO_PRED value (see
* gen_update_fp_context()). Otherwise, we must:
* - set s->mve_no_pred to false, so this instruction
* is generated to use helper functions
* - end the TB now, without chaining to the next TB
*/
if (skip_context_update || !s->v7m_new_fp_ctxt_needed) {
s->mve_no_pred = false;
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
}
}
}
@ -169,12 +183,19 @@ static void gen_update_fp_context(DisasContext *s)
TCGv_i32 z32 = tcg_const_i32(0);
store_cpu_field(z32, v7m.vpr);
}
/*
* We don't need to arrange to end the TB, because the only
* parts of FPSCR which we cache in the TB flags are the VECLEN
* and VECSTRIDE, and those don't exist for M-profile.
* We just updated the FPSCR and VPR. Some of this state is cached
* in the MVE_NO_PRED TB flag. We want to avoid having to end the
* TB here, which means we need the new value of the MVE_NO_PRED
* flag to be exactly known here and the same for all executions.
* Luckily FPDSCR.LTPSIZE is always constant 4 and the VPR is
* always set to 0, so the new MVE_NO_PRED flag is always 1
* if and only if we have MVE.
*
* (The other FPSCR state cached in TB flags is VECLEN and VECSTRIDE,
* but those do not exist for M-profile, so are not relevant here.)
*/
s->mve_no_pred = dc_isar_feature(aa32_mve, s);
if (s->v8m_secure) {
bits |= R_V7M_CONTROL_SFPA_MASK;
@ -238,7 +259,7 @@ bool vfp_access_check_m(DisasContext *s, bool skip_context_update)
/* Handle M-profile lazy FP state mechanics */
/* Trigger lazy-state preservation if necessary */
gen_preserve_fp_state(s);
gen_preserve_fp_state(s, skip_context_update);
if (!skip_context_update) {
/* Update ownership of FP context and create new FP context if needed */

View File

@ -2610,8 +2610,40 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
/* An indirect jump so that we still trigger the debug exception. */
gen_set_pc_im(s, dest);
s->base.is_jmp = DISAS_JUMP;
} else {
return;
}
switch (s->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
case DISAS_NORETURN:
/*
* The normal case: just go to the destination TB.
* NB: NORETURN happens if we generate code like
* gen_brcondi(l);
* gen_jmp();
* gen_set_label(l);
* gen_jmp();
* on the second call to gen_jmp().
*/
gen_goto_tb(s, tbno, dest);
break;
case DISAS_UPDATE_NOCHAIN:
case DISAS_UPDATE_EXIT:
/*
* We already decided we're leaving the TB for some other reason.
* Avoid using goto_tb so we really do exit back to the main loop
* and don't chain to another TB.
*/
gen_set_pc_im(s, dest);
gen_goto_ptr();
s->base.is_jmp = DISAS_NORETURN;
break;
default:
/*
* We shouldn't be emitting code for a jump and also have
* is_jmp set to one of the special cases like DISAS_SWI.
*/
g_assert_not_reached();
}
}
@ -8464,6 +8496,7 @@ static bool trans_DLS(DisasContext *s, arg_DLS *a)
/* DLSTP: set FPSCR.LTPSIZE */
tmp = tcg_const_i32(a->size);
store_cpu_field(tmp, v7m.ltpsize);
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
}
return true;
}
@ -8529,6 +8562,10 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
assert(ok);
tmp = tcg_const_i32(a->size);
store_cpu_field(tmp, v7m.ltpsize);
/*
* LTPSIZE updated, but MVE_NO_PRED will always be the same thing (0)
* when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
*/
}
gen_jmp_tb(s, s->base.pc_next, 1);
@ -8711,6 +8748,8 @@ static bool trans_VCTP(DisasContext *s, arg_VCTP *a)
gen_helper_mve_vctp(cpu_env, masklen);
tcg_temp_free_i32(masklen);
tcg_temp_free_i32(rn_shifted);
/* This insn updates predication bits */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
mve_update_eci(s);
return true;
}
@ -9381,6 +9420,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->v7m_new_fp_ctxt_needed =
EX_TBFLAG_M32(tb_flags, NEW_FP_CTXT_NEEDED);
dc->v7m_lspact = EX_TBFLAG_M32(tb_flags, LSPACT);
dc->mve_no_pred = EX_TBFLAG_M32(tb_flags, MVE_NO_PRED);
} else {
dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL);
dc->sctlr_b = EX_TBFLAG_A32(tb_flags, SCTLR__B);

View File

@ -100,6 +100,8 @@ typedef struct DisasContext {
bool align_mem;
/* True if PSTATE.IL is set */
bool pstate_il;
/* True if MVE insns are definitely not predicated by VPR or LTPSIZE */
bool mve_no_pred;
/*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction.

View File

@ -53,6 +53,7 @@
#include "sysemu/hvf.h"
#include "sysemu/hvf_int.h"
#include "sysemu/runstate.h"
#include "sysemu/cpus.h"
#include "hvf-i386.h"
#include "vmcs.h"
#include "vmx.h"
@ -206,6 +207,16 @@ static inline bool apic_bus_freq_is_known(CPUX86State *env)
return env->apic_bus_freq != 0;
}
void hvf_kick_vcpu_thread(CPUState *cpu)
{
cpus_kick_thread(cpu);
}
int hvf_arch_init(void)
{
return 0;
}
int hvf_arch_init_vcpu(CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);