* [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64
@ 2019-01-28 17:39 Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 1/4] target/arm: relax permission checks for HWCAP_CPUID registers Alex Bennée
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 17:39 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Alex Bennée
Hi,
I posted a series to expose some of the CPU registers to user-space.
The counter registers got merged at the time but the HW_CPUID had some
comments that needed addressing. I've re-spun the series and cleaned
it up, hopefully addressing the comments at the same time. The test
case has been expanded.
The ABI is described in the kernel document:
https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
but from QEMU's point of view we just need to ensure the correct
values are reported for CONFIG_USER_ONLY.
Alex Bennée (4):
target/arm: relax permission checks for HWCAP_CPUID registers
target/arm: expose CPUID registers to userspace
linux-user/elfload: enable HWCAP_CPUID for AArch64
tests/tcg/aarch64: userspace system register test
linux-user/elfload.c | 1 +
target/arm/cpu.h | 12 +++
target/arm/helper.c | 57 ++++++++++----
tests/tcg/aarch64/Makefile.target | 2 +-
tests/tcg/aarch64/sysregs.c | 120 ++++++++++++++++++++++++++++++
5 files changed, 175 insertions(+), 17 deletions(-)
create mode 100644 tests/tcg/aarch64/sysregs.c
--
2.17.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v1 1/4] target/arm: relax permission checks for HWCAP_CPUID registers
2019-01-28 17:39 [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64 Alex Bennée
@ 2019-01-28 17:39 ` Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace Alex Bennée
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 17:39 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Alex Bennée, Peter Maydell
Although technically not visible to userspace the kernel does make
them visible via a trap and emulate ABI. We provide a new permission
mask (PL0U_R) which maps to PL0_R for CONFIG_USER builds and adjust
the minimum permission check accordingly.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/cpu.h | 12 ++++++++++++
target/arm/helper.c | 6 +++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index ff81db420d..3b3c359cca 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2202,6 +2202,18 @@ static inline bool cptype_valid(int cptype)
#define PL0_R (0x02 | PL1_R)
#define PL0_W (0x01 | PL1_W)
+/*
+ * For user-mode some registers are accessible to EL0 via a kernel
+ * trap-and-emulate ABI. In this case we define the read permissions
+ * as actually being PL0_R. However some bits of any given register
+ * may still be masked.
+ */
+#ifdef CONFIG_USER_ONLY
+#define PL0U_R PL0_R
+#else
+#define PL0U_R PL1_R
+#endif
+
#define PL3_RW (PL3_R | PL3_W)
#define PL2_RW (PL2_R | PL2_W)
#define PL1_RW (PL1_R | PL1_W)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 92666e5208..42c1c0b144 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6731,7 +6731,11 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
if (r->state != ARM_CP_STATE_AA32) {
int mask = 0;
switch (r->opc1) {
- case 0: case 1: case 2:
+ case 0:
+ /* min_EL EL1, but some accessible to EL0 via kernel ABI */
+ mask = PL0U_R | PL1_RW;
+ break;
+ case 1: case 2:
/* min_EL EL1 */
mask = PL1_RW;
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace
2019-01-28 17:39 [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64 Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 1/4] target/arm: relax permission checks for HWCAP_CPUID registers Alex Bennée
@ 2019-01-28 17:39 ` Alex Bennée
2019-02-04 14:05 ` Peter Maydell
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64 Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test Alex Bennée
3 siblings, 1 reply; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 17:39 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Alex Bennée, Peter Maydell
A number of CPUID registers are exposed to userspace by modern Linux
kernels thanks to the "ARM64 CPU Feature Registers" ABI. For QEMU's
user-mode emulation we don't need to emulate the kernels trap but just
return the value the trap would have done. For this we use the PL0U_R
permission mask which allows this access in CONFIG_USER mode.
Some registers only return a subset of their contents so we need
specific CONFIG_USER_ONLY logic to do this.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v4
- tweak commit message
- use PL0U_R instead of PL1U_R to be less confusing
- more CONFIG_USER logic for special cases
- mask a bunch of bits for some registers
---
target/arm/helper.c | 51 ++++++++++++++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 15 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 42c1c0b144..68808e7293 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3543,7 +3543,7 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
static const ARMCPRegInfo mpidr_cp_reginfo[] = {
{ .name = "MPIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
- .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
+ .access = PL0U_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
REGINFO_SENTINEL
};
@@ -5488,6 +5488,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
return pfr1;
}
+#ifndef CONFIG_USER_ONLY
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@@ -5498,6 +5499,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
return pfr0;
}
+#endif
/* Shared logic between LORID and the rest of the LOR* registers.
* Secure state has already been delt with.
@@ -5799,18 +5801,26 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* define new registers here.
*/
ARMCPRegInfo v8_idregs[] = {
- /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
- * know the right value for the GIC field until after we
- * define these regs.
+ /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST for system
+ * emulation because we don't know the right value for the
+ * GIC field until after we define these regs. For
+ * user-mode HWCAP_CPUID emulation the GIC bits are masked
+ * anyway.
*/
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
+#ifndef CONFIG_USER_ONLY
.access = PL1_R, .type = ARM_CP_NO_RAW,
.readfn = id_aa64pfr0_read,
- .writefn = arm_cp_write_ignore },
+ .writefn = arm_cp_write_ignore
+#else
+ .access = PL0U_R, .type = ARM_CP_CONST,
+ .resetvalue = cpu->isar.id_aa64pfr0 & 0x000f000f0ff0000ULL
+#endif
+ },
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->isar.id_aa64pfr1},
{ .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2,
@@ -5839,11 +5849,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.resetvalue = 0 },
{ .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->id_aa64dfr0 },
{ .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->id_aa64dfr1 },
{ .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2,
@@ -5871,11 +5881,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.resetvalue = 0 },
{ .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_CONST,
- .resetvalue = cpu->isar.id_aa64isar0 },
+ .access = PL0U_R, .type = ARM_CP_CONST,
+#ifdef CONFIG_USER_ONLY
+ .resetvalue = cpu->isar.id_aa64isar0 & 0x000fffffff0ffff0ULL
+#else
+ .resetvalue = cpu->isar.id_aa64isar0
+#endif
+ },
{ .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->isar.id_aa64isar1 },
{ .name = "ID_AA64ISAR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2,
@@ -5903,11 +5918,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.resetvalue = 0 },
{ .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->isar.id_aa64mmfr0 },
{ .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1,
- .access = PL1_R, .type = ARM_CP_CONST,
+ .access = PL0U_R, .type = ARM_CP_CONST,
.resetvalue = cpu->isar.id_aa64mmfr1 },
{ .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2,
@@ -6211,7 +6226,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
{ .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr,
+ .access = PL0U_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr,
.fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid),
.readfn = midr_read },
/* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */
@@ -6223,7 +6238,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.access = PL1_R, .resetvalue = cpu->midr },
{ .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
- .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr },
+#ifdef CONFIG_USER_ONLY
+ .access = PL0U_R, .type = ARM_CP_CONST,
+ .resetvalue = 0 /* HW_CPUID IMPDEF fields are 0 */ },
+#else
+ .access = PL1_R, .type = ARM_CP_CONST,
+ .resetvalue = cpu->revidr },
+#endif
REGINFO_SENTINEL
};
ARMCPRegInfo id_cp_reginfo[] = {
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64
2019-01-28 17:39 [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64 Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 1/4] target/arm: relax permission checks for HWCAP_CPUID registers Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace Alex Bennée
@ 2019-01-28 17:39 ` Alex Bennée
2019-01-28 17:49 ` Laurent Vivier
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test Alex Bennée
3 siblings, 1 reply; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 17:39 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Alex Bennée, Riku Voipio, Laurent Vivier
Userspace programs should (in theory) query the ELF HWCAP before
probing these registers. Now we have implemented them all make it
public.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/elfload.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4cff9e1a31..e95c162097 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -571,6 +571,7 @@ static uint32_t get_elf_hwcap(void)
hwcaps |= ARM_HWCAP_A64_FP;
hwcaps |= ARM_HWCAP_A64_ASIMD;
+ hwcaps |= ARM_HWCAP_A64_CPUID;
/* probe for the extra features */
#define GET_FEATURE_ID(feat, hwcap) \
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test
2019-01-28 17:39 [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64 Alex Bennée
` (2 preceding siblings ...)
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64 Alex Bennée
@ 2019-01-28 17:39 ` Alex Bennée
2019-01-28 22:03 ` Alex Bennée
2019-02-04 13:52 ` Peter Maydell
3 siblings, 2 replies; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 17:39 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Alex Bennée, Peter Maydell
This tests a bunch of registers that the kernel allows userspace to
read including the CPUID registers.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v4
- also test for extra bits that shouldn't be exposed
---
tests/tcg/aarch64/Makefile.target | 2 +-
tests/tcg/aarch64/sysregs.c | 120 ++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+), 1 deletion(-)
create mode 100644 tests/tcg/aarch64/sysregs.c
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 08c45b8470..cc1a7eb486 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -7,7 +7,7 @@ VPATH += $(AARCH64_SRC)
# we don't build any of the ARM tests
AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS))
-AARCH64_TESTS+=fcvt
+AARCH64_TESTS+=fcvt sysregs
TESTS:=$(AARCH64_TESTS)
fcvt: LDFLAGS+=-lm
diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c
new file mode 100644
index 0000000000..8e11288ee3
--- /dev/null
+++ b/tests/tcg/aarch64/sysregs.c
@@ -0,0 +1,120 @@
+/*
+ * Check emulated system register access for linux-user mode.
+ *
+ * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
+ */
+
+#include <asm/hwcap.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+
+int failed_mask_count;
+
+#define get_cpu_reg(id) ({ \
+ unsigned long __val = 0xdeadbeef; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ printf("%-20s: 0x%016lx\n", #id, __val); \
+ __val; \
+ })
+
+#define get_cpu_reg_check_mask(id, mask) ({ \
+ unsigned long __cval = get_cpu_reg(id); \
+ unsigned long __extra = __cval & ~mask; \
+ if (__extra) { \
+ printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
+ failed_mask_count++; \
+ } \
+})
+
+bool should_fail;
+int should_fail_count;
+int should_not_fail_count;
+uintptr_t failed_pc[10];
+
+void sigill_handler(int signo, siginfo_t *si, void *data)
+{
+ ucontext_t *uc = (ucontext_t *)data;
+
+ if (should_fail) {
+ should_fail_count++;
+ } else {
+ uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
+ failed_pc[should_not_fail_count++] = pc;
+ }
+ uc->uc_mcontext.pc += 4;
+}
+
+int main(void)
+{
+ struct sigaction sa;
+
+ /* Hook in a SIGILL handler */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = &sigill_handler;
+ sigemptyset(&sa.sa_mask);
+
+ if (sigaction(SIGILL, &sa, 0) != 0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* since 4.12 */
+ printf("Checking CNT registers\n");
+
+ get_cpu_reg(ctr_el0);
+ get_cpu_reg(cntvct_el0);
+ get_cpu_reg(cntfrq_el0);
+
+ /* when (getauxval(AT_HWCAP) & HWCAP_CPUID), since 4.11*/
+ if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
+ printf("CPUID registers unavailable\n");
+ return 1;
+ } else {
+ printf("Checking CPUID registers\n");
+ }
+
+ /*
+ * Some registers only expose some bits to user-space. Anything
+ * that is IMDEF is exported as 0 to user-space.
+ */
+ get_cpu_reg_check_mask(id_aa64isar0_el1, 0x000fffffff0ffff0ULL);
+ get_cpu_reg_check_mask(id_aa64isar1_el1, 0x00000000ffffffffULL);
+ get_cpu_reg(id_aa64mmfr0_el1);
+ get_cpu_reg(id_aa64mmfr1_el1);
+ get_cpu_reg_check_mask(id_aa64pfr0_el1, 0x000f000f0ff0000ULL);
+ get_cpu_reg(id_aa64pfr1_el1);
+ get_cpu_reg(id_aa64dfr0_el1);
+ get_cpu_reg(id_aa64dfr1_el1);
+
+ get_cpu_reg_check_mask(midr_el1, 0x00000000ffffffffULL);
+ get_cpu_reg(mpidr_el1);
+ /* REVIDR is all IMPDEF so should be all zeros to user-space */
+ get_cpu_reg_check_mask(revidr_el1, 0x0);
+
+ printf("Remaining registers should fail\n");
+ should_fail = true;
+
+ /* Unexposed register access causes SIGILL */
+ get_cpu_reg(id_mmfr0_el1);
+
+ if (should_not_fail_count > 0) {
+ int i;
+ for (i = 0; i < should_not_fail_count; i++) {
+ uintptr_t pc = failed_pc[i];
+ uint32_t insn = *(uint32_t *) pc;
+ printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
+ }
+ return 1;
+ }
+
+ if (failed_mask_count > 0) {
+ printf("Extra information leaked to user-space!\n");
+ return 1;
+ }
+
+ return should_fail_count == 1 ? 0 : 1;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64 Alex Bennée
@ 2019-01-28 17:49 ` Laurent Vivier
0 siblings, 0 replies; 11+ messages in thread
From: Laurent Vivier @ 2019-01-28 17:49 UTC (permalink / raw)
To: Alex Bennée, qemu-devel; +Cc: qemu-arm, Riku Voipio
On 28/01/2019 18:39, Alex Bennée wrote:
> Userspace programs should (in theory) query the ELF HWCAP before
> probing these registers. Now we have implemented them all make it
> public.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/elfload.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 4cff9e1a31..e95c162097 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -571,6 +571,7 @@ static uint32_t get_elf_hwcap(void)
>
> hwcaps |= ARM_HWCAP_A64_FP;
> hwcaps |= ARM_HWCAP_A64_ASIMD;
> + hwcaps |= ARM_HWCAP_A64_CPUID;
>
> /* probe for the extra features */
> #define GET_FEATURE_ID(feat, hwcap) \
>
Acked-by: Laurent Vivier <laurent@vivier.eu>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test Alex Bennée
@ 2019-01-28 22:03 ` Alex Bennée
2019-02-04 13:52 ` Peter Maydell
1 sibling, 0 replies; 11+ messages in thread
From: Alex Bennée @ 2019-01-28 22:03 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell
Alex Bennée <alex.bennee@linaro.org> writes:
> This tests a bunch of registers that the kernel allows userspace to
> read including the CPUID registers.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
I'll also merge the following fix:
modified tests/tcg/aarch64/sysregs.c
@@ -11,6 +11,10 @@
#include <string.h>
#include <stdbool.h>
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+
int failed_mask_count;
#define get_cpu_reg(id) ({ \
>
> ---
> v4
> - also test for extra bits that shouldn't be exposed
> ---
> tests/tcg/aarch64/Makefile.target | 2 +-
> tests/tcg/aarch64/sysregs.c | 120 ++++++++++++++++++++++++++++++
> 2 files changed, 121 insertions(+), 1 deletion(-)
> create mode 100644 tests/tcg/aarch64/sysregs.c
>
> diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
> index 08c45b8470..cc1a7eb486 100644
> --- a/tests/tcg/aarch64/Makefile.target
> +++ b/tests/tcg/aarch64/Makefile.target
> @@ -7,7 +7,7 @@ VPATH += $(AARCH64_SRC)
>
> # we don't build any of the ARM tests
> AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS))
> -AARCH64_TESTS+=fcvt
> +AARCH64_TESTS+=fcvt sysregs
> TESTS:=$(AARCH64_TESTS)
>
> fcvt: LDFLAGS+=-lm
> diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c
> new file mode 100644
> index 0000000000..8e11288ee3
> --- /dev/null
> +++ b/tests/tcg/aarch64/sysregs.c
> @@ -0,0 +1,120 @@
> +/*
> + * Check emulated system register access for linux-user mode.
> + *
> + * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
> + */
> +
> +#include <asm/hwcap.h>
> +#include <stdio.h>
> +#include <sys/auxv.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <stdbool.h>
> +
> +int failed_mask_count;
> +
> +#define get_cpu_reg(id) ({ \
> + unsigned long __val = 0xdeadbeef; \
> + asm("mrs %0, "#id : "=r" (__val)); \
> + printf("%-20s: 0x%016lx\n", #id, __val); \
> + __val; \
> + })
> +
> +#define get_cpu_reg_check_mask(id, mask) ({ \
> + unsigned long __cval = get_cpu_reg(id); \
> + unsigned long __extra = __cval & ~mask; \
> + if (__extra) { \
> + printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
> + failed_mask_count++; \
> + } \
> +})
> +
> +bool should_fail;
> +int should_fail_count;
> +int should_not_fail_count;
> +uintptr_t failed_pc[10];
> +
> +void sigill_handler(int signo, siginfo_t *si, void *data)
> +{
> + ucontext_t *uc = (ucontext_t *)data;
> +
> + if (should_fail) {
> + should_fail_count++;
> + } else {
> + uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
> + failed_pc[should_not_fail_count++] = pc;
> + }
> + uc->uc_mcontext.pc += 4;
> +}
> +
> +int main(void)
> +{
> + struct sigaction sa;
> +
> + /* Hook in a SIGILL handler */
> + memset(&sa, 0, sizeof(struct sigaction));
> + sa.sa_flags = SA_SIGINFO;
> + sa.sa_sigaction = &sigill_handler;
> + sigemptyset(&sa.sa_mask);
> +
> + if (sigaction(SIGILL, &sa, 0) != 0) {
> + perror("sigaction");
> + return 1;
> + }
> +
> + /* since 4.12 */
> + printf("Checking CNT registers\n");
> +
> + get_cpu_reg(ctr_el0);
> + get_cpu_reg(cntvct_el0);
> + get_cpu_reg(cntfrq_el0);
> +
> + /* when (getauxval(AT_HWCAP) & HWCAP_CPUID), since 4.11*/
> + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
> + printf("CPUID registers unavailable\n");
> + return 1;
> + } else {
> + printf("Checking CPUID registers\n");
> + }
> +
> + /*
> + * Some registers only expose some bits to user-space. Anything
> + * that is IMDEF is exported as 0 to user-space.
> + */
> + get_cpu_reg_check_mask(id_aa64isar0_el1, 0x000fffffff0ffff0ULL);
> + get_cpu_reg_check_mask(id_aa64isar1_el1, 0x00000000ffffffffULL);
> + get_cpu_reg(id_aa64mmfr0_el1);
> + get_cpu_reg(id_aa64mmfr1_el1);
> + get_cpu_reg_check_mask(id_aa64pfr0_el1, 0x000f000f0ff0000ULL);
> + get_cpu_reg(id_aa64pfr1_el1);
> + get_cpu_reg(id_aa64dfr0_el1);
> + get_cpu_reg(id_aa64dfr1_el1);
> +
> + get_cpu_reg_check_mask(midr_el1, 0x00000000ffffffffULL);
> + get_cpu_reg(mpidr_el1);
> + /* REVIDR is all IMPDEF so should be all zeros to user-space */
> + get_cpu_reg_check_mask(revidr_el1, 0x0);
> +
> + printf("Remaining registers should fail\n");
> + should_fail = true;
> +
> + /* Unexposed register access causes SIGILL */
> + get_cpu_reg(id_mmfr0_el1);
> +
> + if (should_not_fail_count > 0) {
> + int i;
> + for (i = 0; i < should_not_fail_count; i++) {
> + uintptr_t pc = failed_pc[i];
> + uint32_t insn = *(uint32_t *) pc;
> + printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
> + }
> + return 1;
> + }
> +
> + if (failed_mask_count > 0) {
> + printf("Extra information leaked to user-space!\n");
> + return 1;
> + }
> +
> + return should_fail_count == 1 ? 0 : 1;
> +}
--
Alex Bennée
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test Alex Bennée
2019-01-28 22:03 ` Alex Bennée
@ 2019-02-04 13:52 ` Peter Maydell
1 sibling, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-02-04 13:52 UTC (permalink / raw)
To: Alex Bennée; +Cc: QEMU Developers, qemu-arm
On Mon, 28 Jan 2019 at 17:39, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> This tests a bunch of registers that the kernel allows userspace to
> read including the CPUID registers.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v4
> - also test for extra bits that shouldn't be exposed
> ---
> tests/tcg/aarch64/Makefile.target | 2 +-
> tests/tcg/aarch64/sysregs.c | 120 ++++++++++++++++++++++++++++++
> 2 files changed, 121 insertions(+), 1 deletion(-)
> create mode 100644 tests/tcg/aarch64/sysregs.c
>
> diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
> index 08c45b8470..cc1a7eb486 100644
> --- a/tests/tcg/aarch64/Makefile.target
> +++ b/tests/tcg/aarch64/Makefile.target
> @@ -7,7 +7,7 @@ VPATH += $(AARCH64_SRC)
>
> # we don't build any of the ARM tests
> AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS))
> -AARCH64_TESTS+=fcvt
> +AARCH64_TESTS+=fcvt sysregs
> TESTS:=$(AARCH64_TESTS)
>
> fcvt: LDFLAGS+=-lm
> diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c
> new file mode 100644
> index 0000000000..8e11288ee3
> --- /dev/null
> +++ b/tests/tcg/aarch64/sysregs.c
> @@ -0,0 +1,120 @@
> +/*
> + * Check emulated system register access for linux-user mode.
> + *
> + * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
> + */
This needs the usual copyright line and license statement.
> +
> +#include <asm/hwcap.h>
> +#include <stdio.h>
> +#include <sys/auxv.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <stdbool.h>
> +
> +int failed_mask_count;
> +
> +#define get_cpu_reg(id) ({ \
> + unsigned long __val = 0xdeadbeef; \
> + asm("mrs %0, "#id : "=r" (__val)); \
> + printf("%-20s: 0x%016lx\n", #id, __val); \
> + __val; \
> + })
> +
> +#define get_cpu_reg_check_mask(id, mask) ({ \
> + unsigned long __cval = get_cpu_reg(id); \
> + unsigned long __extra = __cval & ~mask; \
> + if (__extra) { \
> + printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
> + failed_mask_count++; \
> + } \
> +})
A brief comment describing what the arguments to these macros
do would be helpful if we ever have to add more registers in future.
> +
> +bool should_fail;
> +int should_fail_count;
> +int should_not_fail_count;
> +uintptr_t failed_pc[10];
> +
> +void sigill_handler(int signo, siginfo_t *si, void *data)
> +{
> + ucontext_t *uc = (ucontext_t *)data;
> +
> + if (should_fail) {
> + should_fail_count++;
> + } else {
> + uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
> + failed_pc[should_not_fail_count++] = pc;
> + }
> + uc->uc_mcontext.pc += 4;
> +}
> +
> +int main(void)
> +{
> + struct sigaction sa;
> +
> + /* Hook in a SIGILL handler */
> + memset(&sa, 0, sizeof(struct sigaction));
> + sa.sa_flags = SA_SIGINFO;
> + sa.sa_sigaction = &sigill_handler;
> + sigemptyset(&sa.sa_mask);
> +
> + if (sigaction(SIGILL, &sa, 0) != 0) {
> + perror("sigaction");
> + return 1;
> + }
> +
> + /* since 4.12 */
This is a rather cryptic comment.
> + printf("Checking CNT registers\n");
> +
> + get_cpu_reg(ctr_el0);
> + get_cpu_reg(cntvct_el0);
> + get_cpu_reg(cntfrq_el0);
> +
> + /* when (getauxval(AT_HWCAP) & HWCAP_CPUID), since 4.11*/
Missing space before "*/".
> + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
> + printf("CPUID registers unavailable\n");
> + return 1;
> + } else {
> + printf("Checking CPUID registers\n");
> + }
> +
> + /*
> + * Some registers only expose some bits to user-space. Anything
> + * that is IMDEF is exported as 0 to user-space.
IMPDEF
> + */
> + get_cpu_reg_check_mask(id_aa64isar0_el1, 0x000fffffff0ffff0ULL);
I can't make sense of this mask value. Presumably it's supposed to be
1s where the value is visible, but the docs say that the visible
bits for ID_AA64ISAR0_EL1 are [23..4] and [55..28], whereas the
mask value here has 1s in [51..24] and [20..4], unless I've miscounted.
> + get_cpu_reg_check_mask(id_aa64isar1_el1, 0x00000000ffffffffULL);
> + get_cpu_reg(id_aa64mmfr0_el1);
> + get_cpu_reg(id_aa64mmfr1_el1);
> + get_cpu_reg_check_mask(id_aa64pfr0_el1, 0x000f000f0ff0000ULL);
This seems to have [31..28] set but not [35..32]. The bits that
should be [51..48] are also in the wrong place, and the whole
number has one hex digit too few to be 64 bits.
> + get_cpu_reg(id_aa64pfr1_el1);
> + get_cpu_reg(id_aa64dfr0_el1);
> + get_cpu_reg(id_aa64dfr1_el1);
> +
> + get_cpu_reg_check_mask(midr_el1, 0x00000000ffffffffULL);
> + get_cpu_reg(mpidr_el1);
> + /* REVIDR is all IMPDEF so should be all zeros to user-space */
> + get_cpu_reg_check_mask(revidr_el1, 0x0);
Missing check of the mask value for ID_AA64MMFR2_EL1 ? Should have
bits [35..32] visible.
Missing checks for:
ID_AA64ZFR0_EL1
ID_AA64AFR0_EL1
ID_AA64AFR1_EL1
Missing checks for all the parts of the ID space that are currently
unallocated (and which should be exposed as RAZ/WI).
Missing checks for registers which are exposed but with all
features hidden, eg ID_PFR0_EL1 and the other aarch32 ID regs.
The kernel returns some value, ie does not fault, all the
architecturally defined registers in Op0=3, Op1=0, CRn=0,
CRm=0,4,5,6,7. For CRm = 0 only op2 = {0,5,6} [MIDR_EL1,
MPIDR_EL1, REVIDR_EL1] are valid, but for CRm = {4,5,6,7}
the whole set of op2 = {0..7} are defined (and RAZ if not
yet given some meaning).
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace Alex Bennée
@ 2019-02-04 14:05 ` Peter Maydell
2019-02-04 15:33 ` Alex Bennée
0 siblings, 1 reply; 11+ messages in thread
From: Peter Maydell @ 2019-02-04 14:05 UTC (permalink / raw)
To: Alex Bennée; +Cc: QEMU Developers, qemu-arm
On Mon, 28 Jan 2019 at 17:39, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> A number of CPUID registers are exposed to userspace by modern Linux
> kernels thanks to the "ARM64 CPU Feature Registers" ABI. For QEMU's
> user-mode emulation we don't need to emulate the kernels trap but just
> return the value the trap would have done. For this we use the PL0U_R
> permission mask which allows this access in CONFIG_USER mode.
>
> Some registers only return a subset of their contents so we need
> specific CONFIG_USER_ONLY logic to do this.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v4
> - tweak commit message
> - use PL0U_R instead of PL1U_R to be less confusing
> - more CONFIG_USER logic for special cases
> - mask a bunch of bits for some registers
> ---
> target/arm/helper.c | 51 ++++++++++++++++++++++++++++++++-------------
> 1 file changed, 36 insertions(+), 15 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 42c1c0b144..68808e7293 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -3543,7 +3543,7 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> static const ARMCPRegInfo mpidr_cp_reginfo[] = {
> { .name = "MPIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
> - .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
> + .access = PL0U_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
> REGINFO_SENTINEL
> };
>
> @@ -5488,6 +5488,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
> return pfr1;
> }
>
> +#ifndef CONFIG_USER_ONLY
> static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
> @@ -5498,6 +5499,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> }
> return pfr0;
> }
> +#endif
>
> /* Shared logic between LORID and the rest of the LOR* registers.
> * Secure state has already been delt with.
> @@ -5799,18 +5801,26 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> * define new registers here.
> */
> ARMCPRegInfo v8_idregs[] = {
> - /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
> - * know the right value for the GIC field until after we
> - * define these regs.
> + /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST for system
> + * emulation because we don't know the right value for the
> + * GIC field until after we define these regs. For
> + * user-mode HWCAP_CPUID emulation the GIC bits are masked
> + * anyway.
> */
> { .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
> +#ifndef CONFIG_USER_ONLY
> .access = PL1_R, .type = ARM_CP_NO_RAW,
> .readfn = id_aa64pfr0_read,
> - .writefn = arm_cp_write_ignore },
> + .writefn = arm_cp_write_ignore
> +#else
> + .access = PL0U_R, .type = ARM_CP_CONST,
> + .resetvalue = cpu->isar.id_aa64pfr0 & 0x000f000f0ff0000ULL
> +#endif
> + },
> { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
> - .access = PL1_R, .type = ARM_CP_CONST,
> + .access = PL0U_R, .type = ARM_CP_CONST,
> .resetvalue = cpu->isar.id_aa64pfr1},
> { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2,
> @@ -5839,11 +5849,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> .resetvalue = 0 },
> { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
> - .access = PL1_R, .type = ARM_CP_CONST,
> + .access = PL0U_R, .type = ARM_CP_CONST,
> .resetvalue = cpu->id_aa64dfr0 },
This doesn't seem right -- I think ID_AA64DFR0_EL1 should be exposed
as zero, not whatever the underlying register value is.
More generally, this ifdeffing of "maybe mask the values" doesn't
seem very future-proof. If we add something to one of the cpu-id_*
values, that should be masked out to zero by default for linux-user,
not defaulting to passed through.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace
2019-02-04 14:05 ` Peter Maydell
@ 2019-02-04 15:33 ` Alex Bennée
2019-02-04 15:55 ` Peter Maydell
0 siblings, 1 reply; 11+ messages in thread
From: Alex Bennée @ 2019-02-04 15:33 UTC (permalink / raw)
To: Peter Maydell; +Cc: QEMU Developers, qemu-arm
Peter Maydell <peter.maydell@linaro.org> writes:
> On Mon, 28 Jan 2019 at 17:39, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> A number of CPUID registers are exposed to userspace by modern Linux
>> kernels thanks to the "ARM64 CPU Feature Registers" ABI. For QEMU's
>> user-mode emulation we don't need to emulate the kernels trap but just
>> return the value the trap would have done. For this we use the PL0U_R
>> permission mask which allows this access in CONFIG_USER mode.
>>
>> Some registers only return a subset of their contents so we need
>> specific CONFIG_USER_ONLY logic to do this.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>
>> ---
>> v4
>> - tweak commit message
>> - use PL0U_R instead of PL1U_R to be less confusing
>> - more CONFIG_USER logic for special cases
>> - mask a bunch of bits for some registers
>> ---
>> target/arm/helper.c | 51 ++++++++++++++++++++++++++++++++-------------
>> 1 file changed, 36 insertions(+), 15 deletions(-)
>>
>> diff --git a/target/arm/helper.c b/target/arm/helper.c
>> index 42c1c0b144..68808e7293 100644
>> --- a/target/arm/helper.c
>> +++ b/target/arm/helper.c
>> @@ -3543,7 +3543,7 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> static const ARMCPRegInfo mpidr_cp_reginfo[] = {
>> { .name = "MPIDR", .state = ARM_CP_STATE_BOTH,
>> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
>> - .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
>> + .access = PL0U_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
>> REGINFO_SENTINEL
>> };
>>
>> @@ -5488,6 +5488,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> return pfr1;
>> }
>>
>> +#ifndef CONFIG_USER_ONLY
>> static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> {
>> ARMCPU *cpu = arm_env_get_cpu(env);
>> @@ -5498,6 +5499,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> }
>> return pfr0;
>> }
>> +#endif
>>
>> /* Shared logic between LORID and the rest of the LOR* registers.
>> * Secure state has already been delt with.
>> @@ -5799,18 +5801,26 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>> * define new registers here.
>> */
>> ARMCPRegInfo v8_idregs[] = {
>> - /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
>> - * know the right value for the GIC field until after we
>> - * define these regs.
>> + /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST for system
>> + * emulation because we don't know the right value for the
>> + * GIC field until after we define these regs. For
>> + * user-mode HWCAP_CPUID emulation the GIC bits are masked
>> + * anyway.
>> */
>> { .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
>> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
>> +#ifndef CONFIG_USER_ONLY
>> .access = PL1_R, .type = ARM_CP_NO_RAW,
>> .readfn = id_aa64pfr0_read,
>> - .writefn = arm_cp_write_ignore },
>> + .writefn = arm_cp_write_ignore
>> +#else
>> + .access = PL0U_R, .type = ARM_CP_CONST,
>> + .resetvalue = cpu->isar.id_aa64pfr0 & 0x000f000f0ff0000ULL
>> +#endif
>> + },
>> { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
>> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
>> - .access = PL1_R, .type = ARM_CP_CONST,
>> + .access = PL0U_R, .type = ARM_CP_CONST,
>> .resetvalue = cpu->isar.id_aa64pfr1},
>> { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
>> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2,
>> @@ -5839,11 +5849,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>> .resetvalue = 0 },
>> { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
>> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
>> - .access = PL1_R, .type = ARM_CP_CONST,
>> + .access = PL0U_R, .type = ARM_CP_CONST,
>> .resetvalue = cpu->id_aa64dfr0 },
>
> This doesn't seem right -- I think ID_AA64DFR0_EL1 should be exposed
> as zero, not whatever the underlying register value is.
Under a kernel I'm seeing numbers reported so I don't think it's totally
squashed:
id_aa64dfr0_el1 : 0x0000000000000006
id_aa64dfr1_el1 : 0x0000000000000000
Confusingly the kernel does:
static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 36, 28, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_PMSVER_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
/*
* We can instantiate multiple PMU instances with different levels
* of support.
*/
S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
ARM64_FTR_END,
};
So I'm not sure if that is intentional as the line:
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6)
implies the DEBUGVER is hidden but actually 0x6?
> More generally, this ifdeffing of "maybe mask the values" doesn't
> seem very future-proof. If we add something to one of the cpu-id_*
> values, that should be masked out to zero by default for linux-user,
> not defaulting to passed through.
Do you mean setting cpu->id_foo during cpu_init? I wasn't sure if that
might interact badly with the recent changes to base our features off
what's actually set in them.
>
> thanks
> -- PMM
--
Alex Bennée
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace
2019-02-04 15:33 ` Alex Bennée
@ 2019-02-04 15:55 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-02-04 15:55 UTC (permalink / raw)
To: Alex Bennée; +Cc: QEMU Developers, qemu-arm
On Mon, 4 Feb 2019 at 15:33, Alex Bennée <alex.bennee@linaro.org> wrote:
> Peter Maydell <peter.maydell@linaro.org> writes:
> > This doesn't seem right -- I think ID_AA64DFR0_EL1 should be exposed
> > as zero, not whatever the underlying register value is.
>
> Under a kernel I'm seeing numbers reported so I don't think it's totally
> squashed:
>
> id_aa64dfr0_el1 : 0x0000000000000006
> id_aa64dfr1_el1 : 0x0000000000000000
>
> Confusingly the kernel does:
>
> static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 36, 28, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_PMSVER_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
> /*
> * We can instantiate multiple PMU instances with different levels
> * of support.
> */
> S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
> ARM64_FTR_END,
> };
>
> So I'm not sure if that is intentional as the line:
>
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6)
>
> implies the DEBUGVER is hidden but actually 0x6?
I think this is because the field in the register is architecturally
defined to have a restricted set of permitted values, of which 0 is
not one. (6 means "ARMv8 debug architecture" so is the effective minimum.)
> > More generally, this ifdeffing of "maybe mask the values" doesn't
> > seem very future-proof. If we add something to one of the cpu-id_*
> > values, that should be masked out to zero by default for linux-user,
> > not defaulting to passed through.
>
> Do you mean setting cpu->id_foo during cpu_init? I wasn't sure if that
> might interact badly with the recent changes to base our features off
> what's actually set in them.
No, I meant having something where we either:
(a) have a separate set of cpreg structs for the userspace visible versions,
or (b) have some code which modifies the cpreg structs in v8_idregs[] (it's
not const) before handing it to define_arm_cp_regs().
(b) sounds better to me -- the ideal here I think would be something where we:
* mark all the regs in the space the kernel covers as PL0U_R with a bit
of code rather than by changing all the cpreg structs
* default them to "no bits of the real value are exposed, all bits 0"
* have a hopefully short list of overrides, probably defined in a special
purpose array with entries like
{ /* ID_AA64DFR0_EL1 */, .crm = 5, .opc2 = 0, .passbits = 0x0,
.fixedbits = 0x6 },
Or we could match the override entries with cpreg values by register name,
which would let you say
{ "ID_AA64DFR0_EL1", .passbits = 0x0, .fixedbits = 0x6 },
and avoid having to repeat the encoding values, which might be neater.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2019-02-04 15:56 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-28 17:39 [Qemu-devel] [PATCH v1 0/4] HWCAP_CPUID registers for aarch64 Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 1/4] target/arm: relax permission checks for HWCAP_CPUID registers Alex Bennée
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 2/4] target/arm: expose CPUID registers to userspace Alex Bennée
2019-02-04 14:05 ` Peter Maydell
2019-02-04 15:33 ` Alex Bennée
2019-02-04 15:55 ` Peter Maydell
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 3/4] linux-user/elfload: enable HWCAP_CPUID for AArch64 Alex Bennée
2019-01-28 17:49 ` Laurent Vivier
2019-01-28 17:39 ` [Qemu-devel] [PATCH v1 4/4] tests/tcg/aarch64: userspace system register test Alex Bennée
2019-01-28 22:03 ` Alex Bennée
2019-02-04 13:52 ` Peter Maydell
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.