diff --git a/.mailmap b/.mailmap index 2976a675ea..8c326709cf 100644 --- a/.mailmap +++ b/.mailmap @@ -62,7 +62,8 @@ Greg Kurz Huacai Chen Huacai Chen James Hogan -Leif Lindholm +Leif Lindholm +Leif Lindholm Radoslaw Biernacki Paul Burton Paul Burton diff --git a/MAINTAINERS b/MAINTAINERS index aee6d623b7..571556d279 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -886,7 +886,7 @@ F: include/hw/ssi/imx_spi.h SBSA-REF M: Radoslaw Biernacki M: Peter Maydell -R: Leif Lindholm +R: Leif Lindholm L: qemu-arm@nongnu.org S: Maintained F: hw/arm/sbsa-ref.c diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index c3bd0676a8..8ed466bf68 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -12,8 +12,16 @@ the following architecture extensions: - FEAT_BBM at level 2 (Translation table break-before-make levels) - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) +- FEAT_CSV2 (Cache speculation variant 2) +- FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1) +- FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) +- FEAT_CSV2_2 (Cache speculation variant 2, version 2) +- FEAT_CSV3 (Cache speculation variant 3) +- FEAT_DGH (Data gathering hint) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) +- FEAT_Debugv8p2 (Debug changes for v8.2) +- FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) @@ -23,6 +31,7 @@ the following architecture extensions: - FEAT_FlagM2 (Enhancements to flag manipulation instructions) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) +- FEAT_IESB (Implicit error synchronization event) - FEAT_JSCVT (JavaScript conversion instructions) - FEAT_LOR (Limited ordering regions) - FEAT_LPA (Large Physical Address space) @@ -40,6 +49,7 @@ the following architecture extensions: - FEAT_PMULL (PMULL, PMULL2 instructions) - FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p4 (PMU Extensions v3.4) +- FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RNG (Random number generator) - FEAT_SB (Speculation Barrier) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 5fe045cbf0..3d1058a80c 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -55,8 +55,10 @@ Supported guest CPU types: - ``cortex-a53`` (64-bit) - ``cortex-a57`` (64-bit) - ``cortex-a72`` (64-bit) +- ``cortex-a76`` (64-bit) - ``a64fx`` (64-bit) - ``host`` (with KVM only) +- ``neoverse-n1`` (64-bit) - ``max`` (same as ``host`` for KVM; best possible emulation with TCG) Note that the default is ``cortex-a15``, so for an AArch64 guest you must diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 4086879ebf..e6bfac95c7 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2002,86 +2002,71 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, const char *oem_id, const char *oem_table_id) { MachineClass *mc = MACHINE_GET_CLASS(ms); - GQueue *list = g_queue_new(); - guint pptt_start = table_data->len; - guint parent_offset; - guint length, i; - int uid = 0; - int socket; + CPUArchIdList *cpus = ms->possible_cpus; + int64_t socket_id = -1, cluster_id = -1, core_id = -1; + uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0; + uint32_t pptt_start = table_data->len; + int n; AcpiTable table = { .sig = "PPTT", .rev = 2, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(&table, table_data); - for (socket = 0; socket < ms->smp.sockets; socket++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - /* - * Physical package - represents the boundary - * of a physical package - */ - (1 << 0), - 0, socket, NULL, 0); - } - - if (mc->smp_props.clusters_supported) { - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int cluster; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (cluster = 0; cluster < ms->smp.clusters; cluster++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, cluster, NULL, 0); - } + /* + * This works with the assumption that cpus[n].props.*_id has been + * sorted from top to down levels in mc->possible_cpu_arch_ids(). + * Otherwise, the unexpected and duplicated containers will be + * created. + */ + for (n = 0; n < cpus->len; n++) { + if (cpus->cpus[n].props.socket_id != socket_id) { + assert(cpus->cpus[n].props.socket_id > socket_id); + socket_id = cpus->cpus[n].props.socket_id; + cluster_id = -1; + core_id = -1; + socket_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (1 << 0), /* Physical package */ + 0, socket_id, NULL, 0); } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int core; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (core = 0; core < ms->smp.cores; core++) { - if (ms->smp.threads > 1) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, core, NULL, 0); - } else { - build_processor_hierarchy_node( - table_data, - (1 << 1) | /* ACPI Processor ID valid */ - (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + if (mc->smp_props.clusters_supported) { + if (cpus->cpus[n].props.cluster_id != cluster_id) { + assert(cpus->cpus[n].props.cluster_id > cluster_id); + cluster_id = cpus->cpus[n].props.cluster_id; + core_id = -1; + cluster_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + socket_offset, cluster_id, NULL, 0); } + } else { + cluster_offset = socket_offset; } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int thread; + if (ms->smp.threads == 1) { + build_processor_hierarchy_node(table_data, + (1 << 1) | /* ACPI Processor ID valid */ + (1 << 3), /* Node is a Leaf */ + cluster_offset, n, NULL, 0); + } else { + if (cpus->cpus[n].props.core_id != core_id) { + assert(cpus->cpus[n].props.core_id > core_id); + core_id = cpus->cpus[n].props.core_id; + core_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + cluster_offset, core_id, NULL, 0); + } - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (thread = 0; thread < ms->smp.threads; thread++) { - build_processor_hierarchy_node( - table_data, + build_processor_hierarchy_node(table_data, (1 << 1) | /* ACPI Processor ID valid */ (1 << 2) | /* Processor is a Thread */ (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + core_offset, n, NULL, 0); } } - g_queue_free(list); acpi_table_end(linker, &table); } diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 2387401963..4bb444684f 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -145,6 +145,8 @@ static const int sbsa_ref_irqmap[] = { static const char * const valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("max"), }; @@ -190,6 +192,20 @@ static void create_fdt(SBSAMachineState *sms) qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); + /* + * This versioning scheme is for informing platform fw only. It is neither: + * - A QEMU versioned machine type; a given version of QEMU will emulate + * a given version of the platform. + * - A reflection of level of SBSA (now SystemReady SR) support provided. + * + * machine-version-major: updated when changes breaking fw compatibility + * are introduced. + * machine-version-minor: updated when features are added that don't break + * fw compatibility. + */ + qemu_fdt_setprop_cell(fdt, "/", "machine-version-major", 0); + qemu_fdt_setprop_cell(fdt, "/", "machine-version-minor", 0); + if (ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); uint32_t *matrix = g_malloc0(size); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index f94278935f..1a45f44435 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -202,7 +202,9 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("a64fx"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), }; @@ -2552,7 +2554,9 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx % ms->numa_state->num_nodes; + int64_t socket_id = ms->possible_cpus->cpus[idx].props.socket_id; + + return socket_id % ms->numa_state->num_nodes; } static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) @@ -2560,6 +2564,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) int n; unsigned int max_cpus = ms->smp.max_cpus; VirtMachineState *vms = VIRT_MACHINE(ms); + MachineClass *mc = MACHINE_GET_CLASS(vms); if (ms->possible_cpus) { assert(ms->possible_cpus->len == max_cpus); @@ -2573,8 +2578,20 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) ms->possible_cpus->cpus[n].type = ms->cpu_type; ms->possible_cpus->cpus[n].arch_id = virt_cpu_mp_affinity(vms, n); + + assert(!mc->smp_props.dies_supported); + ms->possible_cpus->cpus[n].props.has_socket_id = true; + ms->possible_cpus->cpus[n].props.socket_id = + n / (ms->smp.clusters * ms->smp.cores * ms->smp.threads); + ms->possible_cpus->cpus[n].props.has_cluster_id = true; + ms->possible_cpus->cpus[n].props.cluster_id = + (n / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters; + ms->possible_cpus->cpus[n].props.has_core_id = true; + ms->possible_cpus->cpus[n].props.core_id = + (n / ms->smp.threads) % ms->smp.cores; ms->possible_cpus->cpus[n].props.has_thread_id = true; - ms->possible_cpus->cpus[n].props.thread_id = n; + ms->possible_cpus->cpus[n].props.thread_id = + n % ms->smp.threads; } return ms->possible_cpus; } diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 4e2f319aeb..5cb5eecbfc 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -77,6 +77,10 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) if (c->has_die_id) { monitor_printf(mon, " die-id: \"%" PRIu64 "\"\n", c->die_id); } + if (c->has_cluster_id) { + monitor_printf(mon, " cluster-id: \"%" PRIu64 "\"\n", + c->cluster_id); + } if (c->has_core_id) { monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id); } diff --git a/hw/core/machine.c b/hw/core/machine.c index cb9bbc844d..700c1e76b8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -682,6 +682,11 @@ void machine_set_cpu_numa_node(MachineState *machine, return; } + if (props->has_cluster_id && !slot->props.has_cluster_id) { + error_setg(errp, "cluster-id is not supported"); + return; + } + if (props->has_socket_id && !slot->props.has_socket_id) { error_setg(errp, "socket-id is not supported"); return; @@ -701,6 +706,11 @@ void machine_set_cpu_numa_node(MachineState *machine, continue; } + if (props->has_cluster_id && + props->cluster_id != slot->props.cluster_id) { + continue; + } + if (props->has_die_id && props->die_id != slot->props.die_id) { continue; } @@ -995,6 +1005,12 @@ static char *cpu_slot_to_string(const CPUArchId *cpu) } g_string_append_printf(s, "die-id: %"PRId64, cpu->props.die_id); } + if (cpu->props.has_cluster_id) { + if (s->len) { + g_string_append_printf(s, ", "); + } + g_string_append_printf(s, "cluster-id: %"PRId64, cpu->props.cluster_id); + } if (cpu->props.has_core_id) { if (s->len) { g_string_append_printf(s, ", "); diff --git a/qapi/machine.json b/qapi/machine.json index d25a481ce4..4c417e32a5 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -868,10 +868,11 @@ # @node-id: NUMA node ID the CPU belongs to # @socket-id: socket number within node/board the CPU belongs to # @die-id: die number within socket the CPU belongs to (since 4.1) -# @core-id: core number within die the CPU belongs to +# @cluster-id: cluster number within die the CPU belongs to (since 7.1) +# @core-id: core number within cluster the CPU belongs to # @thread-id: thread number within core the CPU belongs to # -# Note: currently there are 5 properties that could be present +# Note: currently there are 6 properties that could be present # but management should be prepared to pass through other # properties with device_add command to allow for future # interface extension. This also requires the filed names to be kept in @@ -883,6 +884,7 @@ 'data': { '*node-id': 'int', '*socket-id': 'int', '*die-id': 'int', + '*cluster-id': 'int', '*core-id': 'int', '*thread-id': 'int' } diff --git a/target/arm/a32.decode b/target/arm/a32.decode index fcd8cd4f7d..f2ca480949 100644 --- a/target/arm/a32.decode +++ b/target/arm/a32.decode @@ -187,13 +187,17 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn { { - YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 - WFE ---- 0011 0010 0000 1111 ---- 0000 0010 - WFI ---- 0011 0010 0000 1111 ---- 0000 0011 + [ + YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 + WFE ---- 0011 0010 0000 1111 ---- 0000 0010 + WFI ---- 0011 0010 0000 1111 ---- 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 - # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 + # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + + ESB ---- 0011 0010 0000 1111 ---- 0001 0000 + ] # The canonical nop ends in 00000000, but the whole of the # rest of the space executes as nop if otherwise unsupported. diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 73984549d2..db03d6a7e1 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -102,6 +102,17 @@ enum { ARM_CP_SVE = 1 << 14, /* Flag: Do not expose in gdb sysreg xml. */ ARM_CP_NO_GDB = 1 << 15, + /* + * Flags: If EL3 but not EL2... + * - UNDEF: discard the cpreg, + * - KEEP: retain the cpreg as is, + * - C_NZ: set const on the cpreg, but retain resetvalue, + * - else: set const on the cpreg, zero resetvalue, aka RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + ARM_CP_EL3_NO_EL2_UNDEF = 1 << 16, + ARM_CP_EL3_NO_EL2_KEEP = 1 << 17, + ARM_CP_EL3_NO_EL2_C_NZ = 1 << 18, }; /* diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 16fb5f9c12..029f644768 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -85,7 +85,7 @@ static bool arm_cpu_has_work(CPUState *cs) return (cpu->power_state != PSCI_OFF) && cs->interrupt_request & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD - | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ + | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR | CPU_INTERRUPT_EXITTB); } @@ -230,6 +230,11 @@ static void arm_cpu_reset(DeviceState *dev) */ env->cp15.gcr_el1 = 0x1ffff; } + /* + * Disable access to SCXTNUM_EL0 from CSV2_1p2. + * This is not yet exposed from the Linux kernel in any way. + */ + env->cp15.sctlr_el[1] |= SCTLR_TSCXT; #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) { @@ -511,6 +516,12 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, return false; } return !(env->daif & PSTATE_I); + case EXCP_VSERR: + if (!(hcr_el2 & HCR_AMO) || (hcr_el2 & HCR_TGE)) { + /* VIRQs are only taken when hypervized. */ + return false; + } + return !(env->daif & PSTATE_A); default: g_assert_not_reached(); } @@ -632,6 +643,17 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) goto found; } } + if (interrupt_request & CPU_INTERRUPT_VSERR) { + excp_idx = EXCP_VSERR; + target_el = 1; + if (arm_excp_unmasked(cs, excp_idx, target_el, + cur_el, secure, hcr_el2)) { + /* Taking a virtual abort clears HCR_EL2.VSE */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + goto found; + } + } return false; found: @@ -684,6 +706,25 @@ void arm_cpu_update_vfiq(ARMCPU *cpu) } } +void arm_cpu_update_vserr(ARMCPU *cpu) +{ + /* + * Update the interrupt level for VSERR, which is the HCR_EL2.VSE bit. + */ + CPUARMState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + bool new_state = env->cp15.hcr_el2 & HCR_VSE; + + if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VSERR) != 0)) { + if (new_state) { + cpu_interrupt(cs, CPU_INTERRUPT_VSERR); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + } + } +} + #ifndef CONFIG_USER_ONLY static void arm_cpu_set_irq(void *opaque, int irq, int level) { @@ -1793,11 +1834,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) */ unset_feature(env, ARM_FEATURE_EL3); - /* Disable the security extension feature bits in the processor feature - * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. + /* + * Disable the security extension feature bits in the processor + * feature registers as well. */ - cpu->isar.id_pfr1 &= ~0xf0; - cpu->isar.id_aa64pfr0 &= ~0xf000; + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL3, 0); } if (!cpu->has_el2) { @@ -1828,12 +1872,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } if (!arm_feature(env, ARM_FEATURE_EL2)) { - /* Disable the hypervisor feature bits in the processor feature - * registers if we don't have EL2. These are id_pfr1[15:12] and - * id_aa64pfr0_el1[11:8]. + /* + * Disable the hypervisor feature bits in the processor feature + * registers if we don't have EL2. */ - cpu->isar.id_aa64pfr0 &= ~0xf00; - cpu->isar.id_pfr1 &= ~0xf000; + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL2, 0); + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, + ID_PFR1, VIRTUALIZATION, 0); } #ifndef CONFIG_USER_ONLY diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ca01f909a8..18ca61e8e2 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -56,6 +56,7 @@ #define EXCP_LSERR 21 /* v8M LSERR SecureFault */ #define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */ #define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */ +#define EXCP_VSERR 24 /* NB: add new EXCP_ defines to the array in arm_log_exception() too */ #define ARMV7M_EXCP_RESET 1 @@ -89,6 +90,7 @@ enum { #define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1 #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2 #define CPU_INTERRUPT_VFIQ CPU_INTERRUPT_TGT_EXT_3 +#define CPU_INTERRUPT_VSERR CPU_INTERRUPT_TGT_INT_0 /* The usual mapping for an AArch64 system register to its AArch32 * counterpart is for the 32 bit world to have access to the lower @@ -525,6 +527,11 @@ typedef struct CPUArchState { uint64_t tfsr_el[4]; /* tfsre0_el1 is index 0. */ uint64_t gcr_el1; uint64_t rgsr_el1; + + /* Minimal RAS registers */ + uint64_t disr_el1; + uint64_t vdisr_el2; + uint64_t vsesr_el2; } cp15; struct { @@ -681,6 +688,8 @@ typedef struct CPUArchState { ARMPACKey apdb; ARMPACKey apga; } keys; + + uint64_t scxtnum_el[4]; #endif #if defined(CONFIG_USER_ONLY) @@ -1204,6 +1213,7 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_WXN (1U << 19) #define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */ #define SCTLR_UWXN (1U << 20) /* v7 onward, AArch32 only */ +#define SCTLR_TSCXT (1U << 20) /* FEAT_CSV2_1p2, AArch64 only */ #define SCTLR_FI (1U << 21) /* up to v7, v8 RES0 */ #define SCTLR_IESB (1U << 21) /* v8.2-IESB, AArch64 only */ #define SCTLR_U (1U << 22) /* up to v6, RAO in v7 */ @@ -4015,6 +4025,19 @@ static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; } +static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) +{ + int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2); + if (key >= 2) { + return true; /* FEAT_CSV2_2 */ + } + if (key == 1) { + key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC); + return key >= 2; /* FEAT_CSV2_1p2 */ + } + return false; +} + static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index c841d55d0e..04427e073f 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -34,65 +34,9 @@ #include "hvf_arm.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" -#include "cpregs.h" +#include "internals.h" -#ifndef CONFIG_USER_ONLY -static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - ARMCPU *cpu = env_archcpu(env); - - /* Number of cores is in [25:24]; otherwise we RAZ */ - return (cpu->core_count - 1) << 24; -} -#endif - -static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { -#ifndef CONFIG_USER_ONLY - { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, - { .name = "L2CTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, -#endif - { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ECTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR", - .cp = 15, .opc1 = 0, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUECTLR", - .cp = 15, .opc1 = 1, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUMERRSR", - .cp = 15, .opc1 = 2, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2MERRSR", - .cp = 15, .opc1 = 3, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, -}; - static void aarch64_a57_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -143,7 +87,7 @@ static void aarch64_a57_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); } static void aarch64_a53_initfn(Object *obj) @@ -196,7 +140,7 @@ static void aarch64_a53_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); } static void aarch64_a72_initfn(Object *obj) @@ -247,7 +191,137 @@ static void aarch64_a72_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void aarch64_a76_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a76"; + 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); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0b1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.18 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ + + /* From B2.93 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +} + +static void aarch64_neoverse_n1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,neoverse-n1"; + 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); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0c1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ + + /* From B2.98 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; } void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) @@ -738,7 +812,6 @@ static void aarch64_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint64_t t; - uint32_t u; if (kvm_enabled() || hvf_enabled()) { /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ @@ -770,51 +843,56 @@ static void aarch64_max_initfn(Object *obj) cpu->midr = t; t = cpu->isar.id_aa64isar0; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ cpu->isar.id_aa64isar1 = t; t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 1); /* FEAT_RAS */ t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ /* * Begin with full support for MTE. This will be downgraded to MTE=0 * during realize if the board provides no tag memory, much like * we do for EL2 with the virtualization=on property. */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr0; @@ -826,86 +904,43 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64mmfr0 = t; t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ + 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, XNX, 1); /* FEAT_XNX */ cpu->isar.id_aa64mmfr1 = t; t = cpu->isar.id_aa64mmfr2; - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ - t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ - t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ - t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ + t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ + t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ cpu->isar.id_aa64mmfr2 = t; t = cpu->isar.id_aa64zfr0; t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ cpu->isar.id_aa64zfr0 = t; - /* Replicate the same data to the 32-bit id registers. */ - u = cpu->isar.id_isar5; - u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ - u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); - u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); - u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); - u = FIELD_DP32(u, ID_ISAR5, RDM, 1); - u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = u; - - u = cpu->isar.id_isar6; - u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); - u = FIELD_DP32(u, ID_ISAR6, DP, 1); - u = FIELD_DP32(u, ID_ISAR6, FHM, 1); - u = FIELD_DP32(u, ID_ISAR6, SB, 1); - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - u = FIELD_DP32(u, ID_ISAR6, BF16, 1); - u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = u; - - u = cpu->isar.id_pfr0; - u = FIELD_DP32(u, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = u; - - u = cpu->isar.id_pfr2; - u = FIELD_DP32(u, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = u; - - u = cpu->isar.id_mmfr3; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = u; - - u = cpu->isar.id_mmfr4; - u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ - u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ - u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = u; - t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_aa64dfr0 = t; - u = cpu->isar.id_dfr0; - u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ - cpu->isar.id_dfr0 = u; - - u = cpu->isar.mvfr1; - u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ - u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = u; + /* Replicate the same data to the 32-bit id registers. */ + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* @@ -976,7 +1011,9 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, + { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, #if defined(CONFIG_KVM) || defined(CONFIG_HVF) { .name = "host", .initfn = aarch64_host_initfn }, diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 9338088b22..ea4eccddc3 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -20,6 +20,130 @@ #endif #include "cpregs.h" + +/* Share AArch32 -cpu max features with AArch64. */ +void aa32_max_features(ARMCPU *cpu) +{ + uint32_t t; + + /* Add additional features supported by QEMU */ + t = cpu->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 */ + cpu->isar.id_isar5 = t; + + t = cpu->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 */ + cpu->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; + + t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ + cpu->isar.id_mmfr3 = t; + + t = cpu->isar.id_mmfr4; + 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, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX*/ + cpu->isar.id_mmfr4 = t; + + t = cpu->isar.id_pfr0; + 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, RAS, 1); /* FEAT_RAS */ + cpu->isar.id_pfr0 = t; + + t = cpu->isar.id_pfr2; + t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ + cpu->isar.id_pfr2 = t; + + t = cpu->isar.id_dfr0; + 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, PERFMON, 5); /* FEAT_PMUv3p4 */ + cpu->isar.id_dfr0 = t; +} + +#ifndef CONFIG_USER_ONLY +static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + + /* Number of cores is in [25:24]; otherwise we RAZ */ + return (cpu->core_count - 1) << 24; +} + +static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { + { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2CTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ECTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR", + .cp = 15, .opc1 = 0, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUECTLR", + .cp = 15, .opc1 = 1, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUMERRSR", + .cp = 15, .opc1 = 2, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2MERRSR", + .cp = 15, .opc1 = 3, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, +}; + +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) +{ + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); +} +#endif /* !CONFIG_USER_ONLY */ + /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) @@ -936,70 +1060,55 @@ static void arm_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - cortex_a15_initfn(obj); + /* aarch64_a57_initfn, advertising none of the aarch64 features */ + 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_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + 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; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + 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_isar6 = 0; + cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ + define_cortex_a72_a57_a53_cp_reginfo(cpu); - /* old-style VFP short-vector support */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* - * We don't set these in system emulation mode for the moment, - * since we don't correctly set (all of) the ID registers to - * advertise them. + * 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. */ - set_feature(&cpu->env, ARM_FEATURE_V8); - { - uint32_t t; - - t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = t; - - t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = t; - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-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; - - t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = t; - - t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = t; - - t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = t; - - t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = t; - } -#endif /* CONFIG_USER_ONLY */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +#endif } #endif /* !TARGET_AARCH64 */ diff --git a/target/arm/helper.c b/target/arm/helper.c index b4daf4f076..432bd81919 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1755,6 +1755,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) } valid_mask &= ~SCR_NET; + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= SCR_TERR; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= SCR_TLOR; } @@ -1767,8 +1770,14 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= SCR_ATA; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= SCR_ENSCXT; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); + if (cpu_isar_feature(aa32_ras, cpu)) { + valid_mask |= SCR_TERR; + } } if (!arm_feature(env, ARM_FEATURE_EL2)) { @@ -1857,7 +1866,12 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) } } - /* External aborts are not possible in QEMU so A bit is always clear */ + if (hcr_el2 & HCR_AMO) { + if (cs->interrupt_request & CPU_INTERRUPT_VSERR) { + ret |= CPSR_A; + } + } + return ret; } @@ -5056,16 +5070,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write }, { .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_FPU, + .access = PL2_RW, + .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) }, { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .writefn = dacr_write, .raw_writefn = raw_write, .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) }, { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) }, { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, @@ -5098,124 +5113,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) }, }; -/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */ -static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { - { .name = "VBAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0, - .access = PL2_RW, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore }, - { .name = "HCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HACR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "AMAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HAMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR0_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR1_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTTBR", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 6, .crm = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, - .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HIFAR", .state = ARM_CP_STATE_AA32, - .type = ARM_CP_CONST, - .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 2, - .access = PL2_RW, .resetvalue = 0 }, -}; - -/* Ditto, but for registers which exist in ARMv8 but not v7 */ -static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = { - { .name = "HCR2", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, -}; - static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) { ARMCPU *cpu = env_archcpu(env); @@ -5243,6 +5140,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_vh, cpu)) { valid_mask |= HCR_E2H; } + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= HCR_TERR | HCR_TEA; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= HCR_TLOR; } @@ -5252,6 +5152,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= HCR_ATA | HCR_DCT | HCR_TID5; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= HCR_ENSCXT; + } } /* Clear RES0 bits. */ @@ -5283,6 +5186,7 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) g_assert(qemu_mutex_iothread_locked()); arm_cpu_update_virq(cpu); arm_cpu_update_vfiq(cpu); + arm_cpu_update_vserr(cpu); } static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -5542,27 +5446,27 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .writefn = tlbimva_hyp_is_write }, { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2_write }, { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_VALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_ALLE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, #ifndef CONFIG_USER_ONLY /* Unlike the other EL2-related AT operations, these must @@ -5572,11 +5476,13 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { { .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, { .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, /* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 * with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose @@ -5900,6 +5806,10 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) { K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0), "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte }, + { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7), + "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12", + isar_feature_aa64_scxtnum }, + /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ }; @@ -6076,7 +5986,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0, .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_NOP }, + .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP }, /* Dummy MDCCINT_EL1, since we don't implement the Debug Communications * Channel but Linux may try to access this register. The 32-bit * alias is DBGDCCINT. @@ -6095,6 +6005,87 @@ static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, }; +/* + * Check for traps to RAS registers, which are controlled + * by HCR_EL2.TERR and SCR_EL3.TERR. + */ +static CPAccessResult access_terr(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_TERR)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_TERR)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static uint64_t disr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + return env->cp15.vdisr_el2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return 0; /* RAZ/WI */ + } + return env->cp15.disr_el1; +} + +static void disr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + env->cp15.vdisr_el2 = val; + return; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return; /* RAZ/WI */ + } + env->cp15.disr_el1 = val; +} + +/* + * Minimal RAS implementation with no Error Records. + * Which means that all of the Error Record registers: + * ERXADDR_EL1 + * ERXCTLR_EL1 + * ERXFR_EL1 + * ERXMISC0_EL1 + * ERXMISC1_EL1 + * ERXMISC2_EL1 + * ERXMISC3_EL1 + * ERXPFGCDN_EL1 (RASv1p1) + * ERXPFGCTL_EL1 (RASv1p1) + * ERXPFGF_EL1 (RASv1p1) + * ERXSTATUS_EL1 + * and + * ERRSELR_EL1 + * may generate UNDEFINED, which is the effect we get by not + * listing them at all. + */ +static const ARMCPRegInfo minimal_ras_reginfo[] = { + { .name = "DISR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.disr_el1), + .readfn = disr_read, .writefn = disr_write, .raw_writefn = raw_write }, + { .name = "ERRIDR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 3, .opc2 = 0, + .access = PL1_R, .accessfn = access_terr, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) }, + { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) }, +}; + /* Return the exception level to which exceptions should be taken * via SVEAccessTrap. If an exception should be routed through * AArch64.AdvSIMDFPAccessTrap, return 0; fp_exception_el should @@ -6237,35 +6228,22 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } -static const ARMCPRegInfo zcr_el1_reginfo = { - .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_no_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore -}; - -static const ARMCPRegInfo zcr_el3_reginfo = { - .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL3_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), - .writefn = zcr_write, .raw_writefn = raw_write +static const ARMCPRegInfo zcr_reginfo[] = { + { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL3_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), + .writefn = zcr_write, .raw_writefn = raw_write }, }; void hw_watchpoint_update(ARMCPU *cpu, int n) @@ -6892,11 +6870,11 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2, @@ -6906,19 +6884,19 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVAE3IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 1, @@ -6973,11 +6951,11 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4, @@ -6985,7 +6963,7 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .writefn = tlbi_aa64_alle1is_write }, { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6, @@ -7255,7 +7233,52 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { }, }; -#endif +static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + uint64_t hcr = arm_hcr_el2_eff(env); + int el = arm_current_el(env); + + if (el == 0 && !((hcr & HCR_E2H) && (hcr & HCR_TGE))) { + if (env->cp15.sctlr_el[1] & SCTLR_TSCXT) { + if (hcr & HCR_TGE) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_TRAP; + } + } else if (el < 2 && (env->cp15.sctlr_el[2] & SCTLR_TSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 2 && arm_is_el2_enabled(env) && !(hcr & HCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo scxtnum_reginfo[] = { + { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL0_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) }, + { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL1_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, + { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL2_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[2]) }, + { .name = "SCXTNUM_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL3_RW, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[3]) }, +}; +#endif /* TARGET_AARCH64 */ static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -7374,11 +7397,14 @@ static const ARMCPRegInfo jazelle_regs[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, }; +static const ARMCPRegInfo contextidr_el2 = { + .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) +}; + static const ARMCPRegInfo vhe_reginfo[] = { - { .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL2_RW, - .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) }, { .name = "TTBR1_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 1, .access = PL2_RW, .writefn = vmsa_tcr_ttbr_el2_write, @@ -7899,27 +7925,40 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v8_idregs); define_arm_cp_regs(cpu, v8_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_EL2)) { + + /* + * Register the base EL2 cpregs. + * Pre v8, these registers are implemented only as part of the + * Virtualization Extensions (EL2 present). Beginning with v8, + * if EL2 is missing but EL3 is enabled, mostly these become + * RES0 from EL3, with some specific exceptions. + */ + if (arm_feature(env, ARM_FEATURE_EL2) + || (arm_feature(env, ARM_FEATURE_EL3) + && arm_feature(env, ARM_FEATURE_V8))) { uint64_t vmpidr_def = mpidr_read_val(env); ARMCPRegInfo vpidr_regs[] = { { .name = "VPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = cpu->midr, .type = ARM_CP_ALIAS, + .resetvalue = cpu->midr, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vpidr_el2) }, { .name = "VPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .resetvalue = cpu->midr, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, { .name = "VMPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = vmpidr_def, .type = ARM_CP_ALIAS, + .resetvalue = vmpidr_def, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vmpidr_el2) }, { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, - .resetvalue = vmpidr_def, + .access = PL2_RW, .resetvalue = vmpidr_def, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, }; define_arm_cp_regs(cpu, vpidr_regs); @@ -7940,33 +7979,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &rvbar); } - } else { - /* If EL2 is missing but higher ELs are enabled, we need to - * register the no_el2 reginfos. - */ - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* When EL3 exists but not EL2, VPIDR and VMPIDR take the value - * of MIDR_EL1 and MPIDR_EL1. - */ - ARMCPRegInfo vpidr_regs[] = { - { .name = "VPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = cpu->midr, - .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, - { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_NO_RAW, - .writefn = arm_cp_write_ignore, .readfn = mpidr_read }, - }; - define_arm_cp_regs(cpu, vpidr_regs); - define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo); - if (arm_feature(env, ARM_FEATURE_V8)) { - define_arm_cp_regs(cpu, el3_no_el2_v8_cp_reginfo); - } - } } + + /* Register the base EL3 cpregs. */ if (arm_feature(env, ARM_FEATURE_EL3)) { define_arm_cp_regs(cpu, el3_cp_reginfo); ARMCPRegInfo el3_regs[] = { @@ -8353,21 +8368,20 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_ssbs, cpu)) { define_one_arm_cp_reg(cpu, &ssbs_reginfo); } + if (cpu_isar_feature(any_ras, cpu)) { + define_arm_cp_regs(cpu, minimal_ras_reginfo); + } + if (cpu_isar_feature(aa64_vh, cpu) || + cpu_isar_feature(aa64_debugv8p2, cpu)) { + define_one_arm_cp_reg(cpu, &contextidr_el2); + } if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) { define_arm_cp_regs(cpu, vhe_reginfo); } if (cpu_isar_feature(aa64_sve, cpu)) { - define_one_arm_cp_reg(cpu, &zcr_el1_reginfo); - if (arm_feature(env, ARM_FEATURE_EL2)) { - define_one_arm_cp_reg(cpu, &zcr_el2_reginfo); - } else { - define_one_arm_cp_reg(cpu, &zcr_no_el2_reginfo); - } - if (arm_feature(env, ARM_FEATURE_EL3)) { - define_one_arm_cp_reg(cpu, &zcr_el3_reginfo); - } + define_arm_cp_regs(cpu, zcr_reginfo); } #ifdef TARGET_AARCH64 @@ -8406,6 +8420,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, mte_tco_ro_reginfo); define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } + + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + define_arm_cp_regs(cpu, scxtnum_reginfo); + } #endif if (cpu_isar_feature(any_predinv, cpu)) { @@ -8506,13 +8524,14 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, int crm, int opc1, int opc2, const char *name) { + CPUARMState *env = &cpu->env; uint32_t key; ARMCPRegInfo *r2; bool is64 = r->type & ARM_CP_64BIT; bool ns = secstate & ARM_CP_SECSTATE_NS; int cp = r->cp; - bool isbanked; size_t name_len; + bool make_const; switch (state) { case ARM_CP_STATE_AA32: @@ -8547,6 +8566,32 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } } + /* + * Eliminate registers that are not present because the EL is missing. + * Doing this here makes it easier to put all registers for a given + * feature into the same ARMCPRegInfo array and define them all at once. + */ + make_const = false; + if (arm_feature(env, ARM_FEATURE_EL3)) { + /* + * An EL2 register without EL2 but with EL3 is (usually) RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + int min_el = ctz32(r->access) / 2; + if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) { + if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) { + return; + } + make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP); + } + } else { + CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2) + ? PL2_RW : PL1_RW); + if ((r->access & max_el) == 0) { + return; + } + } + /* Combine cpreg and name into one allocation. */ name_len = strlen(name) + 1; r2 = g_malloc(sizeof(*r2) + name_len); @@ -8567,44 +8612,77 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->opaque = opaque; } - isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; - if (isbanked) { + if (make_const) { + /* This should not have been a very special register to begin. */ + int old_special = r2->type & ARM_CP_SPECIAL_MASK; + assert(old_special == 0 || old_special == ARM_CP_NOP); /* - * Register is banked (using both entries in array). - * Overwriting fieldoffset as the array is only used to define - * banked registers but later only fieldoffset is used. + * Set the special function to CONST, retaining the other flags. + * This is important for e.g. ARM_CP_SVE so that we still + * take the SVE trap if CPTR_EL3.EZ == 0. */ - r2->fieldoffset = r->bank_fieldoffsets[ns]; - } + r2->type = (r2->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST; + /* + * Usually, these registers become RES0, but there are a few + * special cases like VPIDR_EL2 which have a constant non-zero + * value with writes ignored. + */ + if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) { + r2->resetvalue = 0; + } + /* + * ARM_CP_CONST has precedence, so removing the callbacks and + * offsets are not strictly necessary, but it is potentially + * less confusing to debug later. + */ + r2->readfn = NULL; + r2->writefn = NULL; + r2->raw_readfn = NULL; + r2->raw_writefn = NULL; + r2->resetfn = NULL; + r2->fieldoffset = 0; + r2->bank_fieldoffsets[0] = 0; + r2->bank_fieldoffsets[1] = 0; + } else { + bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; - if (state == ARM_CP_STATE_AA32) { if (isbanked) { /* - * If the register is banked then we don't need to migrate or - * reset the 32-bit instance in certain cases: - * - * 1) If the register has both 32-bit and 64-bit instances then we - * can count on the 64-bit instance taking care of the - * non-secure bank. - * 2) If ARMv8 is enabled then we can count on a 64-bit version - * taking care of the secure bank. This requires that separate - * 32 and 64-bit definitions are provided. + * Register is banked (using both entries in array). + * Overwriting fieldoffset as the array is only used to define + * banked registers but later only fieldoffset is used. */ - if ((r->state == ARM_CP_STATE_BOTH && ns) || - (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) { + r2->fieldoffset = r->bank_fieldoffsets[ns]; + } + if (state == ARM_CP_STATE_AA32) { + if (isbanked) { + /* + * If the register is banked then we don't need to migrate or + * reset the 32-bit instance in certain cases: + * + * 1) If the register has both 32-bit and 64-bit instances + * then we can count on the 64-bit instance taking care + * of the non-secure bank. + * 2) If ARMv8 is enabled then we can count on a 64-bit + * version taking care of the secure bank. This requires + * that separate 32 and 64-bit definitions are provided. + */ + if ((r->state == ARM_CP_STATE_BOTH && ns) || + (arm_feature(env, ARM_FEATURE_V8) && !ns)) { + r2->type |= ARM_CP_ALIAS; + } + } else if ((secstate != r->secure) && !ns) { + /* + * The register is not banked so we only want to allow + * migration of the non-secure instance. + */ r2->type |= ARM_CP_ALIAS; } - } else if ((secstate != r->secure) && !ns) { - /* - * The register is not banked so we only want to allow migration - * of the non-secure instance. - */ - r2->type |= ARM_CP_ALIAS; - } - if (HOST_BIG_ENDIAN && - r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); + if (HOST_BIG_ENDIAN && + r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { + r2->fieldoffset += sizeof(uint32_t); + } } } @@ -8615,7 +8693,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * multiple times. Special registers (ie NOP/WFI) are * never migratable and not even raw-accessible. */ - if (r->type & ARM_CP_SPECIAL_MASK) { + if (r2->type & ARM_CP_SPECIAL_MASK) { r2->type |= ARM_CP_NO_RAW; } if (((r->crm == CP_ANY) && crm != 0) || @@ -9318,6 +9396,7 @@ void arm_log_exception(CPUState *cs) [EXCP_LSERR] = "v8M LSERR UsageFault", [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault", [EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault", + [EXCP_VSERR] = "Virtual SERR", }; if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { @@ -9830,6 +9909,31 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) mask = CPSR_A | CPSR_I | CPSR_F; offset = 4; break; + case EXCP_VSERR: + { + /* + * Note that this is reported as a data abort, but the DFAR + * has an UNKNOWN value. Construct the SError syndrome from + * AET and ExT fields. + */ + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal, }; + + if (extended_addresses_enabled(env)) { + env->exception.fsr = arm_fi_to_lfsc(&fi); + } else { + env->exception.fsr = arm_fi_to_sfsc(&fi); + } + env->exception.fsr |= env->cp15.vsesr_el2 & 0xd000; + A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); + qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x\n", + env->exception.fsr); + + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + } + break; case EXCP_SMC: new_mode = ARM_CPU_MODE_MON; addr = 0x08; @@ -10050,6 +10154,12 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) case EXCP_VFIQ: addr += 0x100; break; + case EXCP_VSERR: + addr += 0x180; + /* Construct the SError syndrome from IDS and ISS fields. */ + env->exception.syndrome = syn_serror(env->cp15.vsesr_el2 & 0x1ffffff); + env->cp15.esr_el[new_el] = env->exception.syndrome; + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } diff --git a/target/arm/helper.h b/target/arm/helper.h index b463d9343b..b1334e0c42 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -54,6 +54,7 @@ DEF_HELPER_1(wfe, void, env) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) +DEF_HELPER_1(vesb, void, env) DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_2(cpsr_write_eret, void, env, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index 255833479d..6ca0e95746 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -947,6 +947,14 @@ void arm_cpu_update_virq(ARMCPU *cpu); */ void arm_cpu_update_vfiq(ARMCPU *cpu); +/** + * arm_cpu_update_vserr: Update CPU_INTERRUPT_VSERR bit + * + * Update the CPU_INTERRUPT_VSERR bit in cs->interrupt_request, + * following a change to the HCR_EL2.VSE bit. + */ +void arm_cpu_update_vserr(ARMCPU *cpu); + /** * arm_mmu_idx_el: * @env: The cpu environment @@ -1307,4 +1315,12 @@ int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg); #endif +#ifdef CONFIG_USER_ONLY +static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } +#else +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); +#endif + +void aa32_max_features(ARMCPU *cpu); + #endif diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 76499ffa14..390b6578a8 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -960,3 +960,46 @@ void HELPER(probe_access)(CPUARMState *env, target_ulong ptr, access_type, mmu_idx, ra); } } + +/* + * This function corresponds to AArch64.vESBOperation(). + * Note that the AArch32 version is not functionally different. + */ +void HELPER(vesb)(CPUARMState *env) +{ + /* + * The EL2Enabled() check is done inside arm_hcr_el2_eff, + * and will return HCR_EL2.VSE == 0, so nothing happens. + */ + uint64_t hcr = arm_hcr_el2_eff(env); + bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO); + bool pending = enabled && (hcr & HCR_VSE); + bool masked = (env->daif & PSTATE_A); + + /* If VSE pending and masked, defer the exception. */ + if (pending && masked) { + uint32_t syndrome; + + if (arm_el_is_aa64(env, 1)) { + /* Copy across IDS and ISS from VSESR. */ + syndrome = env->cp15.vsesr_el2 & 0x1ffffff; + } else { + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal }; + + if (extended_addresses_enabled(env)) { + syndrome = arm_fi_to_lfsc(&fi); + } else { + syndrome = arm_fi_to_sfsc(&fi); + } + /* Copy across AET and ExT from VSESR. */ + syndrome |= env->cp15.vsesr_el2 & 0xd000; + } + + /* Set VDISR_EL2.A along with the syndrome. */ + env->cp15.vdisr_el2 = syndrome | (1u << 31); + + /* Clear pending virtual SError */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR); + } +} diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index 8cde8e7243..0cb26dde7d 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -287,4 +287,9 @@ static inline uint32_t syn_pcalignment(void) return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; } +static inline uint32_t syn_serror(uint32_t extra) +{ + return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra; +} + #endif /* TARGET_ARM_SYNDROME_H */ diff --git a/target/arm/t32.decode b/target/arm/t32.decode index 78fadef9d6..f21ad0167a 100644 --- a/target/arm/t32.decode +++ b/target/arm/t32.decode @@ -364,17 +364,17 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm [ # Hints, and CPS { - YIELD 1111 0011 1010 1111 1000 0000 0000 0001 - WFE 1111 0011 1010 1111 1000 0000 0000 0010 - WFI 1111 0011 1010 1111 1000 0000 0000 0011 + [ + YIELD 1111 0011 1010 1111 1000 0000 0000 0001 + WFE 1111 0011 1010 1111 1000 0000 0000 0010 + WFI 1111 0011 1010 1111 1000 0000 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV 1111 0011 1010 1111 1000 0000 0000 0100 - # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV 1111 0011 1010 1111 1000 0000 0000 0100 + # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 - # For M-profile minimal-RAS ESB can be a NOP, which is the - # default behaviour since it is in the hint space. - # ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ] # The canonical nop ends in 0000 0000, but the whole rest # of the space is "reserved hint, behaves as nop". diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index b80313670f..6a27234a5c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1427,6 +1427,7 @@ static void handle_hint(DisasContext *s, uint32_t insn, break; case 0b00100: /* SEV */ case 0b00101: /* SEVL */ + case 0b00110: /* DGH */ /* we treat all as NOP at least for now */ break; case 0b00111: /* XPACLRI */ @@ -1454,6 +1455,23 @@ static void handle_hint(DisasContext *s, uint32_t insn, gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); } break; + case 0b10000: /* ESB */ + /* Without RAS, we must implement this as NOP. */ + if (dc_isar_feature(aa64_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch64.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + break; case 0b11000: /* PACIAZ */ if (s->pauth_active) { gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], diff --git a/target/arm/translate.c b/target/arm/translate.c index 4e19191ed5..87a899d638 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6239,6 +6239,29 @@ static bool trans_WFI(DisasContext *s, arg_WFI *a) return true; } +static bool trans_ESB(DisasContext *s, arg_ESB *a) +{ + /* + * For M-profile, minimal-RAS ESB can be a NOP. + * Without RAS, we must implement this as NOP. + */ + if (!arm_dc_feature(s, ARM_FEATURE_M) && dc_isar_feature(aa32_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch32.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + return true; +} + static bool trans_NOP(DisasContext *s, arg_NOP *a) { return true; diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index 749429dd27..c5eb13f349 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -223,17 +223,18 @@ static void aarch64_numa_cpu(const void *data) QTestState *qts; g_autofree char *cli = NULL; - cli = make_cli(data, "-machine smp.cpus=2 " + cli = make_cli(data, "-machine " + "smp.cpus=2,smp.sockets=2,smp.clusters=1,smp.cores=1,smp.threads=1 " "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 " - "-numa cpu,node-id=1,thread-id=0 " - "-numa cpu,node-id=0,thread-id=1"); + "-numa cpu,node-id=0,socket-id=1,cluster-id=0,core-id=0,thread-id=0 " + "-numa cpu,node-id=1,socket-id=0,cluster-id=0,core-id=0,thread-id=0"); qts = qtest_init(cli); cpus = get_cpus(qts, &resp); g_assert(cpus); while ((e = qlist_pop(cpus))) { QDict *cpu, *props; - int64_t thread, node; + int64_t socket, cluster, core, thread, node; cpu = qobject_to(QDict, e); g_assert(qdict_haskey(cpu, "props")); @@ -241,12 +242,18 @@ static void aarch64_numa_cpu(const void *data) g_assert(qdict_haskey(props, "node-id")); node = qdict_get_int(props, "node-id"); + g_assert(qdict_haskey(props, "socket-id")); + socket = qdict_get_int(props, "socket-id"); + g_assert(qdict_haskey(props, "cluster-id")); + cluster = qdict_get_int(props, "cluster-id"); + g_assert(qdict_haskey(props, "core-id")); + core = qdict_get_int(props, "core-id"); g_assert(qdict_haskey(props, "thread-id")); thread = qdict_get_int(props, "thread-id"); - if (thread == 0) { + if (socket == 0 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 1); - } else if (thread == 1) { + } else if (socket == 1 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 0); } else { g_assert(false);