Add cortex-a35.

Fix bcm2835 framebuffer for rpi firmware.
 Add FEAT_ETS.
 Add FEAT_PMUv3p5.
 Cleanups to armv7m_load_kernel.
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmMhwAsdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/7Xgf9Ezg+etwsEzY0EWtH
 yoQ7ymJHM1VKqtLkbk9U+Ju18YHEi3fwbYbfLgzkAMFHKDUteKJivKm2w41tsw5g
 lE+5PojQT3k8PffaqeFzKG/JsDPoqKtTa23WjkafbIQAbjRT8JtmF/JmSLaaxyqW
 DozPXJ9jXMS+Q2BxHnoCBuy/Kb3zsqekCr8DOgUIXY5gcAB6q1I8SMX2BrhsIyvV
 vZxNm+hFDCOJtXvkAekMrwGkiIBYoBNpswnv40ldeSvRtD8tnty73JUt+AnWoCwi
 zH4k+CvWICIuZT7oxVecRhlOojtaP5cUTXs0+zhk6GxEx/X6wmXd42heO9ZJL0y1
 6FH0xw==
 =ohPU
 -----END PGP SIGNATURE-----

Merge tag 'pull-arm-20220914' of https://gitlab.com/rth7680/qemu into staging

Add cortex-a35.
Fix bcm2835 framebuffer for rpi firmware.
Add FEAT_ETS.
Add FEAT_PMUv3p5.
Cleanups to armv7m_load_kernel.

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmMhwAsdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/7Xgf9Ezg+etwsEzY0EWtH
# yoQ7ymJHM1VKqtLkbk9U+Ju18YHEi3fwbYbfLgzkAMFHKDUteKJivKm2w41tsw5g
# lE+5PojQT3k8PffaqeFzKG/JsDPoqKtTa23WjkafbIQAbjRT8JtmF/JmSLaaxyqW
# DozPXJ9jXMS+Q2BxHnoCBuy/Kb3zsqekCr8DOgUIXY5gcAB6q1I8SMX2BrhsIyvV
# vZxNm+hFDCOJtXvkAekMrwGkiIBYoBNpswnv40ldeSvRtD8tnty73JUt+AnWoCwi
# zH4k+CvWICIuZT7oxVecRhlOojtaP5cUTXs0+zhk6GxEx/X6wmXd42heO9ZJL0y1
# 6FH0xw==
# =ohPU
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 14 Sep 2022 07:50:35 EDT
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* tag 'pull-arm-20220914' of https://gitlab.com/rth7680/qemu:
  target/arm: Make boards pass base address to armv7m_load_kernel()
  target/arm: Remove useless TARGET_BIG_ENDIAN check in armv7m_load_kernel()
  target/arm: Report FEAT_PMUv3p5 for TCG '-cpu max'
  target/arm: Support 64-bit event counters for FEAT_PMUv3p5
  target/arm: Implement FEAT_PMUv3p5 cycle counter disable bits
  target/arm: Rename pmu_8_n feature test functions
  target/arm: Detect overflow when calculating next PMU interrupt
  target/arm: Honour MDCR_EL2.HPMD in Secure EL2
  target/arm: Ignore PMCR.D when PMCR.LC is set
  target/arm: Don't mishandle count when enabling or disabling PMU counters
  target/arm: Correct value returned by pmu_counter_mask()
  target/arm: Don't corrupt high half of PMOVSR when cycle counter overflows
  target/arm: Add missing space in comment
  target/arm: Advertise FEAT_ETS for '-cpu max'
  target/arm: Implement ID_DFR1
  target/arm: Implement ID_MMFR5
  target/arm: Sort KVM reads of AArch32 ID registers into encoding order
  target/arm: Make cpregs 0, c0, c{3-15}, {0-7} correctly RAZ in v8
  hw/arm/bcm2835_property: Add support for RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS
  target/arm: Add cortex-a35

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-09-17 10:29:47 -04:00
commit 50eac424c7
22 changed files with 374 additions and 83 deletions

View File

@ -24,6 +24,7 @@ the following architecture extensions:
- FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_Debugv8p4 (Debug changes for v8.4)
- FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_DotProd (Advanced SIMD dot product instructions)
- FEAT_DoubleFault (Double Fault Extension) - FEAT_DoubleFault (Double Fault Extension)
- FEAT_ETS (Enhanced Translation Synchronization)
- FEAT_FCMA (Floating-point complex number instructions) - FEAT_FCMA (Floating-point complex number instructions)
- FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions)
- FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP16 (Half-precision floating-point data processing)
@ -52,6 +53,7 @@ the following architecture extensions:
- FEAT_PMULL (PMULL, PMULL2 instructions) - FEAT_PMULL (PMULL, PMULL2 instructions)
- FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p1 (PMU Extensions v3.1)
- FEAT_PMUv3p4 (PMU Extensions v3.4) - FEAT_PMUv3p4 (PMU Extensions v3.4)
- FEAT_PMUv3p5 (PMU Extensions v3.5)
- FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RAS (Reliability, availability, and serviceability)
- FEAT_RASv1p1 (RAS Extension v1.1) - FEAT_RASv1p1 (RAS Extension v1.1)
- FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions)

View File

@ -52,6 +52,7 @@ Supported guest CPU types:
- ``cortex-a7`` (32-bit) - ``cortex-a7`` (32-bit)
- ``cortex-a15`` (32-bit; the default) - ``cortex-a15`` (32-bit; the default)
- ``cortex-a35`` (64-bit)
- ``cortex-a53`` (64-bit) - ``cortex-a53`` (64-bit)
- ``cortex-a57`` (64-bit) - ``cortex-a57`` (64-bit)
- ``cortex-a72`` (64-bit) - ``cortex-a72`` (64-bit)

View File

@ -568,21 +568,15 @@ static void armv7m_reset(void *opaque)
cpu_reset(CPU(cpu)); cpu_reset(CPU(cpu));
} }
void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename,
hwaddr mem_base, int mem_size)
{ {
ssize_t image_size; ssize_t image_size;
uint64_t entry; uint64_t entry;
int big_endian;
AddressSpace *as; AddressSpace *as;
int asidx; int asidx;
CPUState *cs = CPU(cpu); CPUState *cs = CPU(cpu);
#if TARGET_BIG_ENDIAN
big_endian = 1;
#else
big_endian = 0;
#endif
if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
asidx = ARMASIdx_S; asidx = ARMASIdx_S;
} else { } else {
@ -593,9 +587,9 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
if (kernel_filename) { if (kernel_filename) {
image_size = load_elf_as(kernel_filename, NULL, NULL, NULL, image_size = load_elf_as(kernel_filename, NULL, NULL, NULL,
&entry, NULL, NULL, &entry, NULL, NULL,
NULL, big_endian, EM_ARM, 1, 0, as); NULL, 0, EM_ARM, 1, 0, as);
if (image_size < 0) { if (image_size < 0) {
image_size = load_image_targphys_as(kernel_filename, 0, image_size = load_image_targphys_as(kernel_filename, mem_base,
mem_size, as); mem_size, as);
} }
if (image_size < 0) { if (image_size < 0) {

View File

@ -1430,6 +1430,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
armv7m_load_kernel(ARM_CPU(first_cpu), armv7m_load_kernel(ARM_CPU(first_cpu),
machine->kernel_filename, machine->kernel_filename,
0,
AST1030_INTERNAL_FLASH_SIZE); AST1030_INTERNAL_FLASH_SIZE);
} }

View File

@ -57,7 +57,7 @@ static void microbit_init(MachineState *machine)
mr, -1); mr, -1);
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
s->nrf51.flash_size); 0, s->nrf51.flash_size);
} }
static void microbit_machine_class_init(ObjectClass *oc, void *data) static void microbit_machine_class_init(ObjectClass *oc, void *data)

View File

@ -1197,7 +1197,7 @@ static void mps2tz_common_init(MachineState *machine)
} }
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
boot_ram_size(mms)); 0, boot_ram_size(mms));
} }
static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,

View File

@ -450,7 +450,7 @@ static void mps2_common_init(MachineState *machine)
mmc->fpga_type == FPGA_AN511 ? 47 : 13)); mmc->fpga_type == FPGA_AN511 ? 47 : 13));
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
0x400000); 0, 0x400000);
} }
static void mps2_class_init(ObjectClass *oc, void *data) static void mps2_class_init(ObjectClass *oc, void *data)

View File

@ -98,7 +98,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line); sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line);
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
soc->envm_size); 0, soc->envm_size);
} }
static void emcraft_sf2_machine_init(MachineClass *mc) static void emcraft_sf2_machine_init(MachineClass *mc)

View File

@ -597,7 +597,8 @@ static void musca_init(MachineState *machine)
"cfg_sec_resp", 0)); "cfg_sec_resp", 0));
} }
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x2000000); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
0, 0x2000000);
} }
static void musca_class_init(ObjectClass *oc, void *data) static void musca_class_init(ObjectClass *oc, void *data)

View File

@ -49,7 +49,7 @@ static void netduino2_init(MachineState *machine)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
FLASH_SIZE); 0, FLASH_SIZE);
} }
static void netduino2_machine_init(MachineClass *mc) static void netduino2_machine_init(MachineClass *mc)

View File

@ -50,7 +50,7 @@ static void netduinoplus2_init(MachineState *machine)
armv7m_load_kernel(ARM_CPU(first_cpu), armv7m_load_kernel(ARM_CPU(first_cpu),
machine->kernel_filename, machine->kernel_filename,
FLASH_SIZE); 0, FLASH_SIZE);
} }
static void netduinoplus2_machine_init(MachineClass *mc) static void netduinoplus2_machine_init(MachineClass *mc)

View File

@ -1302,7 +1302,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
create_unimplemented_device("hibernation", 0x400fc000, 0x1000); create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
create_unimplemented_device("flash-control", 0x400fd000, 0x1000); create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, flash_size); armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, 0, flash_size);
} }
/* FIXME: Figure out how to generate these from stellaris_boards. */ /* FIXME: Figure out how to generate these from stellaris_boards. */

View File

@ -53,7 +53,7 @@ static void stm32vldiscovery_init(MachineState *machine)
armv7m_load_kernel(ARM_CPU(first_cpu), armv7m_load_kernel(ARM_CPU(first_cpu),
machine->kernel_filename, machine->kernel_filename,
FLASH_SIZE); 0, FLASH_SIZE);
} }
static void stm32vldiscovery_machine_init(MachineClass *mc) static void stm32vldiscovery_machine_init(MachineClass *mc)

View File

@ -199,6 +199,7 @@ static const int a15irqmap[] = {
static const char *valid_cpus[] = { static const char *valid_cpus[] = {
ARM_CPU_TYPE_NAME("cortex-a7"), ARM_CPU_TYPE_NAME("cortex-a7"),
ARM_CPU_TYPE_NAME("cortex-a15"), ARM_CPU_TYPE_NAME("cortex-a15"),
ARM_CPU_TYPE_NAME("cortex-a35"),
ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a57"),
ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a72"),

View File

@ -270,6 +270,10 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
stl_le_phys(&s->dma_as, value + 12, 0); stl_le_phys(&s->dma_as, value + 12, 0);
resplen = 4; resplen = 4;
break; break;
case 0x00040013: /* Get number of displays */
stl_le_phys(&s->dma_as, value + 12, 1);
resplen = 4;
break;
case 0x00060001: /* Get DMA channels */ case 0x00060001: /* Get DMA channels */
/* channels 2-5 */ /* channels 2-5 */

View File

@ -25,13 +25,16 @@ typedef enum {
* armv7m_load_kernel: * armv7m_load_kernel:
* @cpu: CPU * @cpu: CPU
* @kernel_filename: file to load * @kernel_filename: file to load
* @mem_base: base address to load image at (should be where the
* CPU expects to find its vector table on reset)
* @mem_size: mem_size: maximum image size to load * @mem_size: mem_size: maximum image size to load
* *
* Load the guest image for an ARMv7M system. This must be called by * Load the guest image for an ARMv7M system. This must be called by
* any ARMv7M board. (This is necessary to ensure that the CPU resets * any ARMv7M board. (This is necessary to ensure that the CPU resets
* correctly on system reset, as well as for kernel loading.) * correctly on system reset, as well as for kernel loading.)
*/ */
void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size); void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename,
hwaddr mem_base, int mem_size);
/* arm_boot.c */ /* arm_boot.c */
struct arm_boot_info { struct arm_boot_info {

View File

@ -975,6 +975,7 @@ struct ArchCPU {
uint32_t id_mmfr2; uint32_t id_mmfr2;
uint32_t id_mmfr3; uint32_t id_mmfr3;
uint32_t id_mmfr4; uint32_t id_mmfr4;
uint32_t id_mmfr5;
uint32_t id_pfr0; uint32_t id_pfr0;
uint32_t id_pfr1; uint32_t id_pfr1;
uint32_t id_pfr2; uint32_t id_pfr2;
@ -982,6 +983,7 @@ struct ArchCPU {
uint32_t mvfr1; uint32_t mvfr1;
uint32_t mvfr2; uint32_t mvfr2;
uint32_t id_dfr0; uint32_t id_dfr0;
uint32_t id_dfr1;
uint32_t dbgdidr; uint32_t dbgdidr;
uint32_t dbgdevid; uint32_t dbgdevid;
uint32_t dbgdevid1; uint32_t dbgdevid1;
@ -1332,6 +1334,9 @@ FIELD(CPTR_EL3, TTA, 20, 1)
FIELD(CPTR_EL3, TAM, 30, 1) FIELD(CPTR_EL3, TAM, 30, 1)
FIELD(CPTR_EL3, TCPAC, 31, 1) FIELD(CPTR_EL3, TCPAC, 31, 1)
#define MDCR_HLP (1U << 26) /* MDCR_EL2 */
#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */
#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */
#define MDCR_EPMAD (1U << 21) #define MDCR_EPMAD (1U << 21)
#define MDCR_EDAD (1U << 20) #define MDCR_EDAD (1U << 20)
#define MDCR_SPME (1U << 17) /* MDCR_EL3 */ #define MDCR_SPME (1U << 17) /* MDCR_EL3 */
@ -3710,20 +3715,27 @@ static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id)
return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2;
} }
static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id)
{ {
/* 0xf means "non-standard IMPDEF PMU" */ /* 0xf means "non-standard IMPDEF PMU" */
return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 &&
FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
} }
static inline bool isar_feature_aa32_pmu_8_4(const ARMISARegisters *id) static inline bool isar_feature_aa32_pmuv3p4(const ARMISARegisters *id)
{ {
/* 0xf means "non-standard IMPDEF PMU" */ /* 0xf means "non-standard IMPDEF PMU" */
return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 && return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 &&
FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
} }
static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id)
{
/* 0xf means "non-standard IMPDEF PMU" */
return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 6 &&
FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
}
static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id)
{ {
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0; return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0;
@ -4036,18 +4048,24 @@ static inline bool isar_feature_aa64_sme(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0; return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0;
} }
static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
} }
static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id) static inline bool isar_feature_aa64_pmuv3p4(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
} }
static inline bool isar_feature_aa64_pmuv3p5(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 6 &&
FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
}
static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
@ -4211,14 +4229,19 @@ static inline bool isar_feature_any_predinv(const ARMISARegisters *id)
return isar_feature_aa64_predinv(id) || isar_feature_aa32_predinv(id); return isar_feature_aa64_predinv(id) || isar_feature_aa32_predinv(id);
} }
static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) static inline bool isar_feature_any_pmuv3p1(const ARMISARegisters *id)
{ {
return isar_feature_aa64_pmu_8_1(id) || isar_feature_aa32_pmu_8_1(id); return isar_feature_aa64_pmuv3p1(id) || isar_feature_aa32_pmuv3p1(id);
} }
static inline bool isar_feature_any_pmu_8_4(const ARMISARegisters *id) static inline bool isar_feature_any_pmuv3p4(const ARMISARegisters *id)
{ {
return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id); return isar_feature_aa64_pmuv3p4(id) || isar_feature_aa32_pmuv3p4(id);
}
static inline bool isar_feature_any_pmuv3p5(const ARMISARegisters *id)
{
return isar_feature_aa64_pmuv3p5(id) || isar_feature_aa32_pmuv3p5(id);
} }
static inline bool isar_feature_any_ccidx(const ARMISARegisters *id) static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)

View File

@ -36,6 +36,85 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "internals.h" #include "internals.h"
static void aarch64_a35_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu->dtb_compatible = "arm,cortex-a35";
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_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);
/* From B2.2 AArch64 identification registers. */
cpu->midr = 0x411fd040;
cpu->revidr = 0;
cpu->ctr = 0x84448004;
cpu->isar.id_pfr0 = 0x00000131;
cpu->isar.id_pfr1 = 0x00011011;
cpu->isar.id_dfr0 = 0x03010066;
cpu->id_afr0 = 0;
cpu->isar.id_mmfr0 = 0x10201105;
cpu->isar.id_mmfr1 = 0x40000000;
cpu->isar.id_mmfr2 = 0x01260000;
cpu->isar.id_mmfr3 = 0x02102211;
cpu->isar.id_isar0 = 0x02101110;
cpu->isar.id_isar1 = 0x13112111;
cpu->isar.id_isar2 = 0x21232042;
cpu->isar.id_isar3 = 0x01112131;
cpu->isar.id_isar4 = 0x00011142;
cpu->isar.id_isar5 = 0x00011121;
cpu->isar.id_aa64pfr0 = 0x00002222;
cpu->isar.id_aa64pfr1 = 0;
cpu->isar.id_aa64dfr0 = 0x10305106;
cpu->isar.id_aa64dfr1 = 0;
cpu->isar.id_aa64isar0 = 0x00011120;
cpu->isar.id_aa64isar1 = 0;
cpu->isar.id_aa64mmfr0 = 0x00101122;
cpu->isar.id_aa64mmfr1 = 0;
cpu->clidr = 0x0a200023;
cpu->dcz_blocksize = 4;
/* From B2.4 AArch64 Virtual Memory control registers */
cpu->reset_sctlr = 0x00c50838;
/* From B2.10 AArch64 performance monitor registers */
cpu->isar.reset_pmcr_el0 = 0x410a3000;
/* From B2.29 Cache ID registers */
cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */
/* From B3.5 VGIC Type register */
cpu->gic_num_lrs = 4;
cpu->gic_vpribits = 5;
cpu->gic_vprebits = 5;
cpu->gic_pribits = 5;
/* From C6.4 Debug ID Register */
cpu->isar.dbgdidr = 0x3516d000;
/* From C6.5 Debug Device ID Register */
cpu->isar.dbgdevid = 0x00110f13;
/* From C6.6 Debug Device ID Register 1 */
cpu->isar.dbgdevid1 = 0x2;
/* From Cortex-A35 SIMD and Floating-point Support r1p0 */
/* From 3.2 AArch32 register summary */
cpu->reset_fpsid = 0x41034043;
/* From 2.2 AArch64 register summary */
cpu->isar.mvfr0 = 0x10110222;
cpu->isar.mvfr1 = 0x12111111;
cpu->isar.mvfr2 = 0x00000043;
/* These values are the same with A53/A57/A72. */
define_cortex_a72_a57_a53_cp_reginfo(cpu);
}
static void aarch64_a57_initfn(Object *obj) static void aarch64_a57_initfn(Object *obj)
{ {
@ -1043,6 +1122,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */
t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* FEAT_PAN2 */ t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* FEAT_PAN2 */
t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */
t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1); /* FEAT_ETS */
t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */
cpu->isar.id_aa64mmfr1 = t; cpu->isar.id_aa64mmfr1 = t;
@ -1072,7 +1152,7 @@ static void aarch64_max_initfn(Object *obj)
t = cpu->isar.id_aa64dfr0; t = cpu->isar.id_aa64dfr0;
t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */
t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */
cpu->isar.id_aa64dfr0 = t; cpu->isar.id_aa64dfr0 = t;
t = cpu->isar.id_aa64smfr0; t = cpu->isar.id_aa64smfr0;
@ -1158,6 +1238,7 @@ static void aarch64_a64fx_initfn(Object *obj)
} }
static const ARMCPUInfo aarch64_cpus[] = { static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "cortex-a35", .initfn = aarch64_a35_initfn },
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a57", .initfn = aarch64_a57_initfn },
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn },
{ .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn },

View File

@ -64,9 +64,13 @@ void aa32_max_features(ARMCPU *cpu)
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* FEAT_AA32HPD */ t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* FEAT_AA32HPD */
t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ 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, CNP, 1); /* FEAT_TTCNP */
t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX*/ t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */
cpu->isar.id_mmfr4 = t; cpu->isar.id_mmfr4 = t;
t = cpu->isar.id_mmfr5;
t = FIELD_DP32(t, ID_MMFR5, ETS, 1); /* FEAT_ETS */
cpu->isar.id_mmfr5 = t;
t = cpu->isar.id_pfr0; t = cpu->isar.id_pfr0;
t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */
t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */
@ -81,7 +85,7 @@ void aa32_max_features(ARMCPU *cpu)
t = cpu->isar.id_dfr0; t = cpu->isar.id_dfr0;
t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */
t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */
t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* FEAT_PMUv3p4 */ t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */
cpu->isar.id_dfr0 = t; cpu->isar.id_dfr0 = t;
} }

View File

@ -879,16 +879,16 @@ static int64_t instructions_ns_per(uint64_t icount)
} }
#endif #endif
static bool pmu_8_1_events_supported(CPUARMState *env) static bool pmuv3p1_events_supported(CPUARMState *env)
{ {
/* For events which are supported in any v8.1 PMU */ /* For events which are supported in any v8.1 PMU */
return cpu_isar_feature(any_pmu_8_1, env_archcpu(env)); return cpu_isar_feature(any_pmuv3p1, env_archcpu(env));
} }
static bool pmu_8_4_events_supported(CPUARMState *env) static bool pmuv3p4_events_supported(CPUARMState *env)
{ {
/* For events which are supported in any v8.1 PMU */ /* For events which are supported in any v8.1 PMU */
return cpu_isar_feature(any_pmu_8_4, env_archcpu(env)); return cpu_isar_feature(any_pmuv3p4, env_archcpu(env));
} }
static uint64_t zero_event_get_count(CPUARMState *env) static uint64_t zero_event_get_count(CPUARMState *env)
@ -922,17 +922,17 @@ static const pm_event pm_events[] = {
}, },
#endif #endif
{ .number = 0x023, /* STALL_FRONTEND */ { .number = 0x023, /* STALL_FRONTEND */
.supported = pmu_8_1_events_supported, .supported = pmuv3p1_events_supported,
.get_count = zero_event_get_count, .get_count = zero_event_get_count,
.ns_per_count = zero_event_ns_per, .ns_per_count = zero_event_ns_per,
}, },
{ .number = 0x024, /* STALL_BACKEND */ { .number = 0x024, /* STALL_BACKEND */
.supported = pmu_8_1_events_supported, .supported = pmuv3p1_events_supported,
.get_count = zero_event_get_count, .get_count = zero_event_get_count,
.ns_per_count = zero_event_ns_per, .ns_per_count = zero_event_ns_per,
}, },
{ .number = 0x03c, /* STALL */ { .number = 0x03c, /* STALL */
.supported = pmu_8_4_events_supported, .supported = pmuv3p4_events_supported,
.get_count = zero_event_get_count, .get_count = zero_event_get_count,
.ns_per_count = zero_event_ns_per, .ns_per_count = zero_event_ns_per,
}, },
@ -1079,6 +1079,15 @@ static CPAccessResult pmreg_access_ccntr(CPUARMState *env,
return pmreg_access(env, ri, isread); return pmreg_access(env, ri, isread);
} }
/*
* Bits in MDCR_EL2 and MDCR_EL3 which pmu_counter_enabled() looks at.
* We use these to decide whether we need to wrap a write to MDCR_EL2
* or MDCR_EL3 in pmu_op_start()/pmu_op_finish() calls.
*/
#define MDCR_EL2_PMU_ENABLE_BITS \
(MDCR_HPME | MDCR_HPMD | MDCR_HPMN | MDCR_HCCD | MDCR_HLP)
#define MDCR_EL3_PMU_ENABLE_BITS (MDCR_SPME | MDCR_SCCD)
/* Returns true if the counter (pass 31 for PMCCNTR) should count events using /* Returns true if the counter (pass 31 for PMCCNTR) should count events using
* the current EL, security state, and register configuration. * the current EL, security state, and register configuration.
*/ */
@ -1086,7 +1095,7 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
{ {
uint64_t filter; uint64_t filter;
bool e, p, u, nsk, nsu, nsh, m; bool e, p, u, nsk, nsu, nsh, m;
bool enabled, prohibited, filtered; bool enabled, prohibited = false, filtered;
bool secure = arm_is_secure(env); bool secure = arm_is_secure(env);
int el = arm_current_el(env); int el = arm_current_el(env);
uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
@ -1104,19 +1113,29 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
} }
enabled = e && (env->cp15.c9_pmcnten & (1 << counter)); enabled = e && (env->cp15.c9_pmcnten & (1 << counter));
if (!secure) { /* Is event counting prohibited? */
if (el == 2 && (counter < hpmn || counter == 31)) { if (el == 2 && (counter < hpmn || counter == 31)) {
prohibited = mdcr_el2 & MDCR_HPMD; prohibited = mdcr_el2 & MDCR_HPMD;
} else { }
prohibited = false; if (secure) {
} prohibited = prohibited || !(env->cp15.mdcr_el3 & MDCR_SPME);
} else {
prohibited = arm_feature(env, ARM_FEATURE_EL3) &&
!(env->cp15.mdcr_el3 & MDCR_SPME);
} }
if (prohibited && counter == 31) { if (counter == 31) {
prohibited = env->cp15.c9_pmcr & PMCRDP; /*
* The cycle counter defaults to running. PMCR.DP says "disable
* the cycle counter when event counting is prohibited".
* Some MDCR bits disable the cycle counter specifically.
*/
prohibited = prohibited && env->cp15.c9_pmcr & PMCRDP;
if (cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) {
if (secure) {
prohibited = prohibited || (env->cp15.mdcr_el3 & MDCR_SCCD);
}
if (el == 2) {
prohibited = prohibited || (mdcr_el2 & MDCR_HCCD);
}
}
} }
if (counter == 31) { if (counter == 31) {
@ -1164,6 +1183,43 @@ static void pmu_update_irq(CPUARMState *env)
(env->cp15.c9_pminten & env->cp15.c9_pmovsr)); (env->cp15.c9_pminten & env->cp15.c9_pmovsr));
} }
static bool pmccntr_clockdiv_enabled(CPUARMState *env)
{
/*
* Return true if the clock divider is enabled and the cycle counter
* is supposed to tick only once every 64 clock cycles. This is
* controlled by PMCR.D, but if PMCR.LC is set to enable the long
* (64-bit) cycle counter PMCR.D has no effect.
*/
return (env->cp15.c9_pmcr & (PMCRD | PMCRLC)) == PMCRD;
}
static bool pmevcntr_is_64_bit(CPUARMState *env, int counter)
{
/* Return true if the specified event counter is configured to be 64 bit */
/* This isn't intended to be used with the cycle counter */
assert(counter < 31);
if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) {
return false;
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
/*
* MDCR_EL2.HLP still applies even when EL2 is disabled in the
* current security state, so we don't use arm_mdcr_el2_eff() here.
*/
bool hlp = env->cp15.mdcr_el2 & MDCR_HLP;
int hpmn = env->cp15.mdcr_el2 & MDCR_HPMN;
if (hpmn != 0 && counter >= hpmn) {
return hlp;
}
}
return env->cp15.c9_pmcr & PMCRLP;
}
/* /*
* Ensure c15_ccnt is the guest-visible count so that operations such as * Ensure c15_ccnt is the guest-visible count so that operations such as
* enabling/disabling the counter or filtering, modifying the count itself, * enabling/disabling the counter or filtering, modifying the count itself,
@ -1176,8 +1232,7 @@ static void pmccntr_op_start(CPUARMState *env)
if (pmu_counter_enabled(env, 31)) { if (pmu_counter_enabled(env, 31)) {
uint64_t eff_cycles = cycles; uint64_t eff_cycles = cycles;
if (env->cp15.c9_pmcr & PMCRD) { if (pmccntr_clockdiv_enabled(env)) {
/* Increment once every 64 processor clock cycles */
eff_cycles /= 64; eff_cycles /= 64;
} }
@ -1186,7 +1241,7 @@ static void pmccntr_op_start(CPUARMState *env)
uint64_t overflow_mask = env->cp15.c9_pmcr & PMCRLC ? \ uint64_t overflow_mask = env->cp15.c9_pmcr & PMCRLC ? \
1ull << 63 : 1ull << 31; 1ull << 63 : 1ull << 31;
if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) { if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) {
env->cp15.c9_pmovsr |= (1 << 31); env->cp15.c9_pmovsr |= (1ULL << 31);
pmu_update_irq(env); pmu_update_irq(env);
} }
@ -1212,16 +1267,18 @@ static void pmccntr_op_finish(CPUARMState *env)
int64_t overflow_in = cycles_ns_per(remaining_cycles); int64_t overflow_in = cycles_ns_per(remaining_cycles);
if (overflow_in > 0) { if (overflow_in > 0) {
int64_t overflow_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + int64_t overflow_at;
overflow_in;
ARMCPU *cpu = env_archcpu(env); if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); overflow_in, &overflow_at)) {
ARMCPU *cpu = env_archcpu(env);
timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at);
}
} }
#endif #endif
uint64_t prev_cycles = env->cp15.c15_ccnt_delta; uint64_t prev_cycles = env->cp15.c15_ccnt_delta;
if (env->cp15.c9_pmcr & PMCRD) { if (pmccntr_clockdiv_enabled(env)) {
/* Increment once every 64 processor clock cycles */
prev_cycles /= 64; prev_cycles /= 64;
} }
env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt; env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt;
@ -1239,9 +1296,11 @@ static void pmevcntr_op_start(CPUARMState *env, uint8_t counter)
} }
if (pmu_counter_enabled(env, counter)) { if (pmu_counter_enabled(env, counter)) {
uint32_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter]; uint64_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter];
uint64_t overflow_mask = pmevcntr_is_64_bit(env, counter) ?
1ULL << 63 : 1ULL << 31;
if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & INT32_MIN) { if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & overflow_mask) {
env->cp15.c9_pmovsr |= (1 << counter); env->cp15.c9_pmovsr |= (1 << counter);
pmu_update_irq(env); pmu_update_irq(env);
} }
@ -1256,15 +1315,22 @@ static void pmevcntr_op_finish(CPUARMState *env, uint8_t counter)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
uint16_t event = env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCOUNT; uint16_t event = env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCOUNT;
uint16_t event_idx = supported_event_map[event]; uint16_t event_idx = supported_event_map[event];
uint64_t delta = UINT32_MAX - uint64_t delta = -(env->cp15.c14_pmevcntr[counter] + 1);
(uint32_t)env->cp15.c14_pmevcntr[counter] + 1; int64_t overflow_in;
int64_t overflow_in = pm_events[event_idx].ns_per_count(delta);
if (!pmevcntr_is_64_bit(env, counter)) {
delta = (uint32_t)delta;
}
overflow_in = pm_events[event_idx].ns_per_count(delta);
if (overflow_in > 0) { if (overflow_in > 0) {
int64_t overflow_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + int64_t overflow_at;
overflow_in;
ARMCPU *cpu = env_archcpu(env); if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); overflow_in, &overflow_at)) {
ARMCPU *cpu = env_archcpu(env);
timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at);
}
} }
#endif #endif
@ -1342,6 +1408,8 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
unsigned int i; unsigned int i;
uint64_t overflow_mask, new_pmswinc;
for (i = 0; i < pmu_num_counters(env); i++) { for (i = 0; i < pmu_num_counters(env); i++) {
/* Increment a counter's count iff: */ /* Increment a counter's count iff: */
if ((value & (1 << i)) && /* counter's bit is set */ if ((value & (1 << i)) && /* counter's bit is set */
@ -1355,9 +1423,12 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri,
* Detect if this write causes an overflow since we can't predict * Detect if this write causes an overflow since we can't predict
* PMSWINC overflows like we can for other events * PMSWINC overflows like we can for other events
*/ */
uint32_t new_pmswinc = env->cp15.c14_pmevcntr[i] + 1; new_pmswinc = env->cp15.c14_pmevcntr[i] + 1;
if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) { overflow_mask = pmevcntr_is_64_bit(env, i) ?
1ULL << 63 : 1ULL << 31;
if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & overflow_mask) {
env->cp15.c9_pmovsr |= (1 << i); env->cp15.c9_pmovsr |= (1 << i);
pmu_update_irq(env); pmu_update_irq(env);
} }
@ -1432,15 +1503,19 @@ static uint64_t pmccfiltr_read_a32(CPUARMState *env, const ARMCPRegInfo *ri)
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
pmu_op_start(env);
value &= pmu_counter_mask(env); value &= pmu_counter_mask(env);
env->cp15.c9_pmcnten |= value; env->cp15.c9_pmcnten |= value;
pmu_op_finish(env);
} }
static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
pmu_op_start(env);
value &= pmu_counter_mask(env); value &= pmu_counter_mask(env);
env->cp15.c9_pmcnten &= ~value; env->cp15.c9_pmcnten &= ~value;
pmu_op_finish(env);
} }
static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -1560,6 +1635,10 @@ static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri)
static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value, uint8_t counter) uint64_t value, uint8_t counter)
{ {
if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) {
/* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */
value &= MAKE_64BIT_MASK(0, 32);
}
if (counter < pmu_num_counters(env)) { if (counter < pmu_num_counters(env)) {
pmevcntr_op_start(env, counter); pmevcntr_op_start(env, counter);
env->cp15.c14_pmevcntr[counter] = value; env->cp15.c14_pmevcntr[counter] = value;
@ -1579,6 +1658,10 @@ static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri,
pmevcntr_op_start(env, counter); pmevcntr_op_start(env, counter);
ret = env->cp15.c14_pmevcntr[counter]; ret = env->cp15.c14_pmevcntr[counter];
pmevcntr_op_finish(env, counter); pmevcntr_op_finish(env, counter);
if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) {
/* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */
ret &= MAKE_64BIT_MASK(0, 32);
}
return ret; return ret;
} else { } else {
/* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR /* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR
@ -4681,7 +4764,39 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static void sdcr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void sdcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
/*
* Some MDCR_EL3 bits affect whether PMU counters are running:
* if we are trying to change any of those then we must
* bracket this update with PMU start/finish calls.
*/
bool pmu_op = (env->cp15.mdcr_el3 ^ value) & MDCR_EL3_PMU_ENABLE_BITS;
if (pmu_op) {
pmu_op_start(env);
}
env->cp15.mdcr_el3 = value & SDCR_VALID_MASK; env->cp15.mdcr_el3 = value & SDCR_VALID_MASK;
if (pmu_op) {
pmu_op_finish(env);
}
}
static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/*
* Some MDCR_EL2 bits affect whether PMU counters are running:
* if we are trying to change any of those then we must
* bracket this update with PMU start/finish calls.
*/
bool pmu_op = (env->cp15.mdcr_el2 ^ value) & MDCR_EL2_PMU_ENABLE_BITS;
if (pmu_op) {
pmu_op_start(env);
}
env->cp15.mdcr_el2 = value;
if (pmu_op) {
pmu_op_finish(env);
}
} }
static const ARMCPRegInfo v8_cp_reginfo[] = { static const ARMCPRegInfo v8_cp_reginfo[] = {
@ -6344,7 +6459,7 @@ static void define_pmu_regs(ARMCPU *cpu)
g_free(pmevtyper_name); g_free(pmevtyper_name);
g_free(pmevtyper_el0_name); g_free(pmevtyper_el0_name);
} }
if (cpu_isar_feature(aa32_pmu_8_1, cpu)) { if (cpu_isar_feature(aa32_pmuv3p1, cpu)) {
ARMCPRegInfo v81_pmu_regs[] = { ARMCPRegInfo v81_pmu_regs[] = {
{ .name = "PMCEID2", .state = ARM_CP_STATE_AA32, { .name = "PMCEID2", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4, .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4,
@ -6357,7 +6472,7 @@ static void define_pmu_regs(ARMCPU *cpu)
}; };
define_arm_cp_regs(cpu, v81_pmu_regs); define_arm_cp_regs(cpu, v81_pmu_regs);
} }
if (cpu_isar_feature(any_pmu_8_4, cpu)) { if (cpu_isar_feature(any_pmuv3p4, cpu)) {
static const ARMCPRegInfo v84_pmmir = { static const ARMCPRegInfo v84_pmmir = {
.name = "PMMIR_EL1", .state = ARM_CP_STATE_BOTH, .name = "PMMIR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 6, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 6,
@ -7345,11 +7460,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, not_v7_cp_reginfo); define_arm_cp_regs(cpu, not_v7_cp_reginfo);
} }
if (arm_feature(env, ARM_FEATURE_V8)) { if (arm_feature(env, ARM_FEATURE_V8)) {
/* AArch64 ID registers, which all have impdef reset values. /*
* v8 ID registers, which all have impdef reset values.
* Note that within the ID register ranges the unused slots * Note that within the ID register ranges the unused slots
* must all RAZ, not UNDEF; future architecture versions may * must all RAZ, not UNDEF; future architecture versions may
* define new registers here. * define new registers here.
* ID registers which are AArch64 views of the AArch32 ID registers
* which already existed in v6 and v7 are handled elsewhere,
* in v6_idregs[].
*/ */
int i;
ARMCPRegInfo v8_idregs[] = { ARMCPRegInfo v8_idregs[] = {
/* /*
* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system * ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system
@ -7539,7 +7659,34 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
.resetvalue = cpu->isar.mvfr2 }, .resetvalue = cpu->isar.mvfr2 },
{ .name = "MVFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, /*
* "0, c0, c3, {0,1,2}" are the encodings corresponding to
* AArch64 MVFR[012]_EL1. Define the STATE_AA32 encoding
* as RAZ, since it is in the "reserved for future ID
* registers, RAZ" part of the AArch32 encoding space.
*/
{ .name = "RES_0_C0_C3_0", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0,
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3,
.resetvalue = 0 },
{ .name = "RES_0_C0_C3_1", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3,
.resetvalue = 0 },
{ .name = "RES_0_C0_C3_2", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3,
.resetvalue = 0 },
/*
* Other encodings in "0, c0, c3, ..." are STATE_BOTH because
* they're also RAZ for AArch64, and in v8 are gradually
* being filled with AArch64-view-of-AArch32-ID-register
* for new ID registers.
*/
{ .name = "RES_0_C0_C3_3", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3,
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
@ -7549,17 +7696,17 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
.resetvalue = cpu->isar.id_pfr2 }, .resetvalue = cpu->isar.id_pfr2 },
{ .name = "MVFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, { .name = "ID_DFR1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5,
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
.resetvalue = 0 }, .resetvalue = cpu->isar.id_dfr1 },
{ .name = "MVFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, { .name = "ID_MMFR5", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6,
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
.resetvalue = 0 }, .resetvalue = cpu->isar.id_mmfr5 },
{ .name = "MVFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64, { .name = "RES_0_C0_C3_7", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7,
.access = PL1_R, .type = ARM_CP_CONST, .access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3, .accessfn = access_aa64_tid3,
@ -7625,6 +7772,29 @@ void register_cp_regs_for_features(ARMCPU *cpu)
} }
define_arm_cp_regs(cpu, v8_idregs); define_arm_cp_regs(cpu, v8_idregs);
define_arm_cp_regs(cpu, v8_cp_reginfo); define_arm_cp_regs(cpu, v8_cp_reginfo);
for (i = 4; i < 16; i++) {
/*
* Encodings in "0, c0, {c4-c7}, {0-7}" are RAZ for AArch32.
* For pre-v8 cores there are RAZ patterns for these in
* id_pre_v8_midr_cp_reginfo[]; for v8 we do that here.
* v8 extends the "must RAZ" part of the ID register space
* to also cover c0, 0, c{8-15}, {0-7}.
* These are STATE_AA32 because in the AArch64 sysreg space
* c4-c7 is where the AArch64 ID registers live (and we've
* already defined those in v8_idregs[]), and c8-c15 are not
* "must RAZ" for AArch64.
*/
g_autofree char *name = g_strdup_printf("RES_0_C0_C%d_X", i);
ARMCPRegInfo v8_aa32_raz_idregs = {
.name = name,
.state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 0, .crm = i, .opc2 = CP_ANY,
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid3,
.resetvalue = 0 };
define_one_arm_cp_reg(cpu, &v8_aa32_raz_idregs);
}
} }
/* /*
@ -7669,6 +7839,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
ARMCPRegInfo mdcr_el2 = { ARMCPRegInfo mdcr_el2 = {
.name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
.writefn = mdcr_el2_write,
.access = PL2_RW, .resetvalue = pmu_num_counters(env), .access = PL2_RW, .resetvalue = pmu_num_counters(env),
.fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2),
}; };

View File

@ -1256,6 +1256,7 @@ enum MVEECIState {
/* Definitions for the PMU registers */ /* Definitions for the PMU registers */
#define PMCRN_MASK 0xf800 #define PMCRN_MASK 0xf800
#define PMCRN_SHIFT 11 #define PMCRN_SHIFT 11
#define PMCRLP 0x80
#define PMCRLC 0x40 #define PMCRLC 0x40
#define PMCRDP 0x20 #define PMCRDP 0x20
#define PMCRX 0x10 #define PMCRX 0x10
@ -1267,7 +1268,7 @@ enum MVEECIState {
* Mask of PMCR bits writable by guest (not including WO bits like C, P, * Mask of PMCR bits writable by guest (not including WO bits like C, P,
* which can be written as 1 to trigger behaviour but which stay RAZ). * which can be written as 1 to trigger behaviour but which stay RAZ).
*/ */
#define PMCR_WRITABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) #define PMCR_WRITABLE_MASK (PMCRLP | PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE)
#define PMXEVTYPER_P 0x80000000 #define PMXEVTYPER_P 0x80000000
#define PMXEVTYPER_U 0x40000000 #define PMXEVTYPER_U 0x40000000
@ -1296,7 +1297,7 @@ static inline uint32_t pmu_num_counters(CPUARMState *env)
/* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */ /* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */
static inline uint64_t pmu_counter_mask(CPUARMState *env) static inline uint64_t pmu_counter_mask(CPUARMState *env)
{ {
return (1 << 31) | ((1 << pmu_num_counters(env)) - 1); return (1ULL << 31) | ((1ULL << pmu_num_counters(env)) - 1);
} }
#ifdef TARGET_AARCH64 #ifdef TARGET_AARCH64

View File

@ -608,8 +608,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
ARM64_SYS_REG(3, 0, 0, 1, 0)); ARM64_SYS_REG(3, 0, 0, 1, 0));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1, err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1,
ARM64_SYS_REG(3, 0, 0, 1, 1)); ARM64_SYS_REG(3, 0, 0, 1, 1));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
ARM64_SYS_REG(3, 0, 0, 3, 4));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0,
ARM64_SYS_REG(3, 0, 0, 1, 2)); ARM64_SYS_REG(3, 0, 0, 1, 2));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0,
@ -643,6 +641,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
ARM64_SYS_REG(3, 0, 0, 3, 1)); ARM64_SYS_REG(3, 0, 0, 3, 1));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2,
ARM64_SYS_REG(3, 0, 0, 3, 2)); ARM64_SYS_REG(3, 0, 0, 3, 2));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
ARM64_SYS_REG(3, 0, 0, 3, 4));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1,
ARM64_SYS_REG(3, 0, 0, 3, 5));
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5,
ARM64_SYS_REG(3, 0, 0, 3, 6));
/* /*
* DBGDIDR is a bit complicated because the kernel doesn't * DBGDIDR is a bit complicated because the kernel doesn't