diff options
author | Alex Bennée | 2019-02-15 10:56:38 +0100 |
---|---|---|
committer | Peter Maydell | 2019-02-15 10:56:38 +0100 |
commit | 6c5c0fec29bbfe36c64eca1edfd8455be46b77c6 (patch) | |
tree | c4a444a50fe3ae3bd222b422c3bf9245ee07860d /target/arm/helper.c | |
parent | target/arm: relax permission checks for HWCAP_CPUID registers (diff) | |
download | qemu-6c5c0fec29bbfe36c64eca1edfd8455be46b77c6.tar.gz qemu-6c5c0fec29bbfe36c64eca1edfd8455be46b77c6.tar.xz qemu-6c5c0fec29bbfe36c64eca1edfd8455be46b77c6.zip |
target/arm: expose CPUID registers to userspace
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. To avoid too much #ifdef
hackery we process ARMCPRegInfo with a new helper (modify_arm_cp_regs)
before defining the registers. The modify routine is driven by a
simple data structure which describes which bits are exported and
which are fixed.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20190205190224.2198-3-alex.bennee@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r-- | target/arm/helper.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 88cf497603..b2abaf5b22 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6109,6 +6109,30 @@ void register_cp_regs_for_features(ARMCPU *cpu) .resetvalue = cpu->pmceid1 }, REGINFO_SENTINEL }; +#ifdef CONFIG_USER_ONLY + ARMCPRegUserSpaceInfo v8_user_idregs[] = { + { .name = "ID_AA64PFR0_EL1", + .exported_bits = 0x000f000f00ff0000, + .fixed_bits = 0x0000000000000011 }, + { .name = "ID_AA64PFR1_EL1", + .exported_bits = 0x00000000000000f0 }, + { .name = "ID_AA64ZFR0_EL1" }, + { .name = "ID_AA64MMFR0_EL1", + .fixed_bits = 0x00000000ff000000 }, + { .name = "ID_AA64MMFR1_EL1" }, + { .name = "ID_AA64DFR0_EL1", + .fixed_bits = 0x0000000000000006 }, + { .name = "ID_AA64DFR1_EL1" }, + { .name = "ID_AA64AFR0_EL1" }, + { .name = "ID_AA64AFR1_EL1" }, + { .name = "ID_AA64ISAR0_EL1", + .exported_bits = 0x00fffffff0fffff0 }, + { .name = "ID_AA64ISAR1_EL1", + .exported_bits = 0x000000f0ffffffff }, + REGUSERINFO_SENTINEL + }; + modify_arm_cp_regs(v8_idregs, v8_user_idregs); +#endif /* RVBAR_EL1 is only implemented if EL1 is the highest EL */ if (!arm_feature(env, ARM_FEATURE_EL3) && !arm_feature(env, ARM_FEATURE_EL2)) { @@ -6385,6 +6409,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_OVERRIDE }; +#ifdef CONFIG_USER_ONLY + ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = { + { .name = "MIDR_EL1", + .exported_bits = 0x00000000ffffffff }, + { .name = "REVIDR_EL1" }, + REGUSERINFO_SENTINEL + }; + modify_arm_cp_regs(id_v8_midr_cp_reginfo, id_v8_user_midr_cp_reginfo); +#endif if (arm_feature(env, ARM_FEATURE_OMAPCP) || arm_feature(env, ARM_FEATURE_STRONGARM)) { ARMCPRegInfo *r; @@ -6966,6 +6999,32 @@ void define_arm_cp_regs_with_opaque(ARMCPU *cpu, } } +/* + * Modify ARMCPRegInfo for access from userspace. + * + * This is a data driven modification directed by + * ARMCPRegUserSpaceInfo. All registers become ARM_CP_CONST as + * user-space cannot alter any values and dynamic values pertaining to + * execution state are hidden from user space view anyway. + */ +void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods) +{ + const ARMCPRegUserSpaceInfo *m; + ARMCPRegInfo *r; + + for (m = mods; m->name; m++) { + for (r = regs; r->type != ARM_CP_SENTINEL; r++) { + if (strcmp(r->name, m->name) == 0) { + r->type = ARM_CP_CONST; + r->access = PL0U_R; + r->resetvalue &= m->exported_bits; + r->resetvalue |= m->fixed_bits; + break; + } + } + } +} + const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp) { return g_hash_table_lookup(cpregs, &encoded_cp); |