mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:17 +00:00
Call TargetInfo::target_aarch64() at runtime, allowing to remove the target-specific TARGET_AARCH64 definition and build cpu-max.c once as common object. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Acked-by: Peter Maydell <peter.maydell@linaro.org> Message-Id: <20260526203722.79463-18-philmd@linaro.org>
242 lines
8.3 KiB
C
242 lines
8.3 KiB
C
/*
|
|
* QEMU ARM 'max' CPU
|
|
*
|
|
* Copyright (c) 2018 Linaro Ltd
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/units.h"
|
|
#include "qemu/target-info.h"
|
|
#include "system/hw_accel.h"
|
|
#include "system/kvm.h"
|
|
#include "system/qtest.h"
|
|
#include "system/tcg.h"
|
|
#include "target/arm/internals.h"
|
|
#include "target/arm/cpregs.h"
|
|
|
|
void aarch64_aa32_a57_init(Object *obj, bool aa32_only)
|
|
{
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
ARMISARegisters *isar = &cpu->isar;
|
|
const bool aarch64_enabled = !aa32_only;
|
|
|
|
cpu->dtb_compatible = "arm,cortex-a57";
|
|
set_feature(&cpu->env, ARM_FEATURE_V8);
|
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
|
set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ);
|
|
if (aarch64_enabled) {
|
|
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
|
}
|
|
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
|
set_feature(&cpu->env, ARM_FEATURE_EL2);
|
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
|
if (kvm_enabled()) {
|
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
|
|
}
|
|
cpu->midr = 0x411fd070;
|
|
cpu->revidr = 0x00000000;
|
|
cpu->reset_fpsid = 0x41034070;
|
|
cpu->isar.mvfr0 = 0x10110222;
|
|
cpu->isar.mvfr1 = 0x12111111;
|
|
cpu->isar.mvfr2 = 0x00000043;
|
|
cpu->ctr = 0x8444c004;
|
|
cpu->reset_sctlr = 0x00c50838;
|
|
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
|
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
|
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
|
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
|
SET_IDREG(isar, ID_MMFR0, 0x10101105);
|
|
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
|
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
|
SET_IDREG(isar, ID_MMFR3, 0x02102211);
|
|
SET_IDREG(isar, ID_ISAR0, 0x02101110);
|
|
SET_IDREG(isar, ID_ISAR1, 0x13112111);
|
|
SET_IDREG(isar, ID_ISAR2, 0x21232042);
|
|
SET_IDREG(isar, ID_ISAR3, 0x01112131);
|
|
SET_IDREG(isar, ID_ISAR4, 0x00011142);
|
|
SET_IDREG(isar, ID_ISAR5, 0x00011121);
|
|
SET_IDREG(isar, ID_ISAR6, 0);
|
|
if (aarch64_enabled) {
|
|
SET_IDREG(isar, ID_AA64PFR0, 0x00002222);
|
|
SET_IDREG(isar, ID_AA64DFR0, 0x10305106);
|
|
SET_IDREG(isar, ID_AA64ISAR0, 0x00011120);
|
|
SET_IDREG(isar, ID_AA64MMFR0, 0x00001124);
|
|
}
|
|
cpu->isar.dbgdidr = 0x3516d000;
|
|
cpu->isar.dbgdevid = 0x01110f13;
|
|
cpu->isar.dbgdevid1 = 0x2;
|
|
cpu->isar.reset_pmcr_el0 = 0x41013000;
|
|
SET_IDREG(isar, CLIDR, 0x0a200023);
|
|
/* 32KB L1 dcache */
|
|
cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
|
|
/* 48KB L1 icache */
|
|
cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 3, 64, 48 * KiB, 2);
|
|
/* 2048KB L2 cache */
|
|
cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 2 * MiB, 7);
|
|
if (aarch64_enabled) {
|
|
set_dczid_bs(cpu, 4); /* 64 bytes */
|
|
cpu->gic_num_lrs = 4;
|
|
cpu->gic_vpribits = 5;
|
|
cpu->gic_vprebits = 5;
|
|
cpu->gic_pribits = 5;
|
|
}
|
|
define_cortex_a72_a57_a53_cp_reginfo(cpu);
|
|
}
|
|
|
|
/* Share AArch32 -cpu max features with AArch64. */
|
|
void aa32_max_features(ARMCPU *cpu)
|
|
{
|
|
uint32_t t;
|
|
ARMISARegisters *isar = &cpu->isar;
|
|
|
|
/* Add additional features supported by QEMU */
|
|
t = GET_IDREG(isar, ID_ISAR5);
|
|
t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */
|
|
t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */
|
|
t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */
|
|
t = FIELD_DP32(t, ID_ISAR5, CRC32, 1);
|
|
t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */
|
|
t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */
|
|
SET_IDREG(isar, ID_ISAR5, t);
|
|
|
|
t = GET_IDREG(isar, ID_ISAR6);
|
|
t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */
|
|
t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */
|
|
t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */
|
|
t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */
|
|
t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */
|
|
t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */
|
|
t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */
|
|
SET_IDREG(isar, ID_ISAR6, t);
|
|
|
|
t = cpu->isar.mvfr1;
|
|
t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */
|
|
t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */
|
|
cpu->isar.mvfr1 = t;
|
|
|
|
t = cpu->isar.mvfr2;
|
|
t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */
|
|
t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */
|
|
cpu->isar.mvfr2 = t;
|
|
|
|
FIELD_DP32_IDREG(isar, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */
|
|
|
|
t = GET_IDREG(isar, ID_MMFR4);
|
|
t = FIELD_DP32(t, ID_MMFR4, HPDS, 2); /* FEAT_HPDS2 */
|
|
t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
|
|
t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */
|
|
t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */
|
|
t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT */
|
|
SET_IDREG(isar, ID_MMFR4, t);
|
|
|
|
FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 2); /* FEAT_ETS2 */
|
|
|
|
t = GET_IDREG(isar, ID_PFR0);
|
|
t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CSV2 */
|
|
t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */
|
|
t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */
|
|
SET_IDREG(isar, ID_PFR0, t);
|
|
|
|
t = GET_IDREG(isar, ID_PFR2);
|
|
t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */
|
|
t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */
|
|
SET_IDREG(isar, ID_PFR2, t);
|
|
|
|
t = GET_IDREG(isar, ID_DFR0);
|
|
t = FIELD_DP32(t, ID_DFR0, COPDBG, 10); /* FEAT_Debugv8p8 */
|
|
t = FIELD_DP32(t, ID_DFR0, COPSDBG, 10); /* FEAT_Debugv8p8 */
|
|
t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */
|
|
SET_IDREG(isar, ID_DFR0, t);
|
|
|
|
/* Debug ID registers. */
|
|
|
|
/* Bit[15] is RES1, Bit[13] and Bits[11:0] are RES0. */
|
|
t = 0x00008000;
|
|
t = FIELD_DP32(t, DBGDIDR, SE_IMP, 1);
|
|
t = FIELD_DP32(t, DBGDIDR, NSUHD_IMP, 1);
|
|
t = FIELD_DP32(t, DBGDIDR, VERSION, 10); /* FEAT_Debugv8p8 */
|
|
t = FIELD_DP32(t, DBGDIDR, CTX_CMPS, 1);
|
|
t = FIELD_DP32(t, DBGDIDR, BRPS, 5);
|
|
t = FIELD_DP32(t, DBGDIDR, WRPS, 3);
|
|
cpu->isar.dbgdidr = t;
|
|
|
|
t = 0;
|
|
t = FIELD_DP32(t, DBGDEVID, PCSAMPLE, 3);
|
|
t = FIELD_DP32(t, DBGDEVID, WPADDRMASK, 1);
|
|
t = FIELD_DP32(t, DBGDEVID, BPADDRMASK, 15);
|
|
t = FIELD_DP32(t, DBGDEVID, VECTORCATCH, 0);
|
|
t = FIELD_DP32(t, DBGDEVID, VIRTEXTNS, 1);
|
|
t = FIELD_DP32(t, DBGDEVID, DOUBLELOCK, 1);
|
|
t = FIELD_DP32(t, DBGDEVID, AUXREGS, 0);
|
|
t = FIELD_DP32(t, DBGDEVID, CIDMASK, 0);
|
|
cpu->isar.dbgdevid = t;
|
|
|
|
/* Bits[31:4] are RES0. */
|
|
t = 0;
|
|
t = FIELD_DP32(t, DBGDEVID1, PCSROFFSET, 2);
|
|
cpu->isar.dbgdevid1 = t;
|
|
|
|
FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */
|
|
}
|
|
|
|
/*
|
|
* -cpu max: a CPU with as many features enabled as our emulation supports.
|
|
* The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c;
|
|
* this only needs to handle 32 bits, and need not care about KVM.
|
|
*/
|
|
static void cpu_max_initfn(Object *obj)
|
|
{
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
const bool aarch64_enabled = target_aarch64();
|
|
|
|
if (hwaccel_enabled()) {
|
|
assert(aarch64_enabled);
|
|
/*
|
|
* When hardware acceleration enabled, '-cpu max' is
|
|
* identical to '-cpu host'
|
|
*/
|
|
aarch64_host_initfn(obj);
|
|
return;
|
|
}
|
|
|
|
if (tcg_enabled() || qtest_enabled()) {
|
|
aarch64_aa32_a57_init(obj, !aarch64_enabled);
|
|
}
|
|
|
|
if (!aarch64_enabled) {
|
|
aa32_max_features(cpu);
|
|
#ifdef CONFIG_USER_ONLY
|
|
/*
|
|
* Break with true ARMv8 and add back old-style VFP short-vector
|
|
* support. Only do this for user-mode, where -cpu max is the default,
|
|
* so that older v6 and v7 programs are more likely to work without
|
|
* adjustment.
|
|
*/
|
|
cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1);
|
|
#endif
|
|
} else if (tcg_enabled()) {
|
|
assert(aarch64_enabled);
|
|
/*
|
|
* '-cpu max' for TCG: we currently do this as
|
|
* "A57 with extra things"
|
|
*/
|
|
aarch64_max_tcg_initfn(obj);
|
|
}
|
|
}
|
|
|
|
static const ARMCPUInfo arm_max_cpu = {
|
|
.name = "max",
|
|
.initfn = cpu_max_initfn,
|
|
};
|
|
|
|
static void arm_max_cpu_register_types(void)
|
|
{
|
|
arm_cpu_register(&arm_max_cpu);
|
|
}
|
|
|
|
type_init(arm_max_cpu_register_types)
|