aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2018-11-19 15:29:07 +0000
committerPeter Maydell <peter.maydell@linaro.org>2018-11-19 15:29:07 +0000
commit9d60dea960fd3a1438f01bc07f1967daba24067d (patch)
tree158d8737ef5040f2656a348724f8a5c65fa0270e
parent4674097c32e22df0b6769e62ad455258a3444991 (diff)
target/arm: Fill in ARMISARegisters for kvm64
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20181113180154.17903-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--target/arm/kvm64.c90
1 files changed, 88 insertions, 2 deletions
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 46fbe6d8ff..0a502091e7 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -456,17 +456,40 @@ static inline void unset_feature(uint64_t *features, int feature)
*features &= ~(1ULL << feature);
}
+static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id)
+{
+ uint64_t ret;
+ struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)&ret };
+ int err;
+
+ assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
+ err = ioctl(fd, KVM_GET_ONE_REG, &idreg);
+ if (err < 0) {
+ return -1;
+ }
+ *pret = ret;
+ return 0;
+}
+
+static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id)
+{
+ struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)pret };
+
+ assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
+ return ioctl(fd, KVM_GET_ONE_REG, &idreg);
+}
+
bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
{
/* Identify the feature bits corresponding to the host CPU, and
* fill out the ARMHostCPUClass fields accordingly. To do this
* we have to create a scratch VM, create a single CPU inside it,
* and then query that CPU for the relevant ID registers.
- * For AArch64 we currently don't care about ID registers at
- * all; we just want to know the CPU type.
*/
int fdarray[3];
uint64_t features = 0;
+ int err;
+
/* Old kernels may not know about the PREFERRED_TARGET ioctl: however
* we know these will only support creating one kind of guest CPU,
* which is its preferred CPU type. Fortunately these old kernels
@@ -487,8 +510,71 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
ahcf->target = init.target;
ahcf->dtb_compatible = "arm,arm-v8";
+ err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
+ ARM64_SYS_REG(3, 0, 0, 4, 0));
+ if (unlikely(err < 0)) {
+ /*
+ * Before v4.15, the kernel only exposed a limited number of system
+ * registers, not including any of the interesting AArch64 ID regs.
+ * For the most part we could leave these fields as zero with minimal
+ * effect, since this does not affect the values seen by the guest.
+ *
+ * However, it could cause problems down the line for QEMU,
+ * so provide a minimal v8.0 default.
+ *
+ * ??? Could read MIDR and use knowledge from cpu64.c.
+ * ??? Could map a page of memory into our temp guest and
+ * run the tiniest of hand-crafted kernels to extract
+ * the values seen by the guest.
+ * ??? Either of these sounds like too much effort just
+ * to work around running a modern host kernel.
+ */
+ ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */
+ err = 0;
+ } else {
+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
+ ARM64_SYS_REG(3, 0, 0, 4, 1));
+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0,
+ ARM64_SYS_REG(3, 0, 0, 6, 0));
+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1,
+ ARM64_SYS_REG(3, 0, 0, 6, 1));
+
+ /*
+ * Note that if AArch32 support is not present in the host,
+ * the AArch32 sysregs are present to be read, but will
+ * return UNKNOWN values. This is neither better nor worse
+ * than skipping the reads and leaving 0, as we must avoid
+ * considering the values in every case.
+ */
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0,
+ ARM64_SYS_REG(3, 0, 0, 2, 0));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1,
+ ARM64_SYS_REG(3, 0, 0, 2, 1));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2,
+ ARM64_SYS_REG(3, 0, 0, 2, 2));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3,
+ ARM64_SYS_REG(3, 0, 0, 2, 3));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4,
+ ARM64_SYS_REG(3, 0, 0, 2, 4));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5,
+ ARM64_SYS_REG(3, 0, 0, 2, 5));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6,
+ ARM64_SYS_REG(3, 0, 0, 2, 7));
+
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0,
+ ARM64_SYS_REG(3, 0, 0, 3, 0));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1,
+ ARM64_SYS_REG(3, 0, 0, 3, 1));
+ err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2,
+ ARM64_SYS_REG(3, 0, 0, 3, 2));
+ }
+
kvm_arm_destroy_scratch_host_vcpu(fdarray);
+ if (err < 0) {
+ return false;
+ }
+
/* We can assume any KVM supporting CPU is at least a v8
* with VFPv4+Neon; this in turn implies most of the other
* feature bits.