From: "Mian M. Hamayun" <m.hamayun@xxxxxxxxxxxxxxxxxxxxxx> The cpu init function tries to initialize with all possible cpu types, as KVM does not provide a means to detect the real cpu type and simply refuses to initialize on cpu type mis-match. By using the loop based init function, we avoid the need to modify code if the underlying platform is different, such as Fast Models instead of Foundation Models. Get and Put Registers deal with the basic state of Aarch64 CPUs for the moment. Signed-off-by: Mian M. Hamayun <m.hamayun@xxxxxxxxxxxxxxxxxxxxxx> Conflicts: target-arm/kvm.c Conflicts: target-arm/cpu.c --- linux-headers/linux/kvm.h | 1 + target-arm/kvm.c | 125 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index c614070..4df5292 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -783,6 +783,7 @@ struct kvm_dirty_tlb { #define KVM_REG_IA64 0x3000000000000000ULL #define KVM_REG_ARM 0x4000000000000000ULL #define KVM_REG_S390 0x5000000000000000ULL +#define KVM_REG_ARM64 0x6000000000000000ULL #define KVM_REG_SIZE_SHIFT 52 #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL diff --git a/target-arm/kvm.c b/target-arm/kvm.c index b92e00d..c96b871 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -32,6 +32,11 @@ #error mismatch between cpu.h and KVM header definitions #endif +#ifdef TARGET_AARCH64 +#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) +#endif + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -50,6 +55,33 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) return cpu->cpu_index; } +#ifdef TARGET_AARCH64 +static uint32_t kvm_arm_targets[KVM_ARM_NUM_TARGETS] = { + KVM_ARM_TARGET_AEM_V8, + KVM_ARM_TARGET_FOUNDATION_V8, + KVM_ARM_TARGET_CORTEX_A57 +}; + +int kvm_arch_init_vcpu(CPUState *cs) +{ + struct kvm_vcpu_init init; + int ret, i; + + memset(init.features, 0, sizeof(init.features)); + /* Find an appropriate target CPU type. + * KVM does not provide means to detect the host CPU type on aarch64, + * and simply refuses to initialize, if the CPU type mis-matches; + * so we try each possible CPU type on aarch64 before giving up! */ + for (i = 0; i < KVM_ARM_NUM_TARGETS; ++i) { + init.target = kvm_arm_targets[i]; + ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); + if (!ret) + break; + } + + return ret; +} +#else static bool reg_syncs_via_tuple_list(uint64_t regidx) { /* Return true if the regidx is a register we should synchronize @@ -173,6 +205,7 @@ out: g_free(rlp); return ret; } +#endif /* We track all the KVM devices which need their memory addresses * passing to the kernel in a list of these structures. @@ -339,6 +372,7 @@ typedef struct Reg { int offset; } Reg; +#ifndef TARGET_AARCH64 #define COREREG(KERNELNAME, QEMUFIELD) \ { \ KVM_REG_ARM | KVM_REG_SIZE_U32 | \ @@ -402,7 +436,52 @@ static const Reg regs[] = { VFPSYSREG(FPINST), VFPSYSREG(FPINST2), }; +#endif +#ifdef TARGET_AARCH64 +int kvm_arch_put_registers(CPUState *cs, int level) +{ + struct kvm_one_reg reg; + int i; + int ret; + + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + for (i = 0; i < ARRAY_SIZE(env->xregs); i++) { + reg.id = AARCH64_CORE_REG(regs.regs[i]); + reg.addr = (uintptr_t) &env->xregs[i]; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + reg.id = AARCH64_CORE_REG(regs.sp); + reg.addr = (uintptr_t) &env->xregs[31]; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + + reg.id = AARCH64_CORE_REG(regs.pstate); + reg.addr = (uintptr_t) &env->pstate; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + + reg.id = AARCH64_CORE_REG(regs.pc); + reg.addr = (uintptr_t) &env->pc; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + + /* TODO: Set Rest of Registers */ + return ret; +} +#else int kvm_arch_put_registers(CPUState *cs, int level) { ARMCPU *cpu = ARM_CPU(cs); @@ -488,7 +567,52 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } +#endif +#ifdef TARGET_AARCH64 +int kvm_arch_get_registers(CPUState *cs) +{ + struct kvm_one_reg reg; + int i; + int ret; + + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + for (i = 0; i < ARRAY_SIZE(env->xregs); i++) { + reg.id = AARCH64_CORE_REG(regs.regs[i]); + reg.addr = (uintptr_t) &env->xregs[i]; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + reg.id = AARCH64_CORE_REG(regs.sp); + reg.addr = (uintptr_t) &env->xregs[31]; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } + + reg.id = AARCH64_CORE_REG(regs.pstate); + reg.addr = (uintptr_t) &env->pstate; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } + + reg.id = AARCH64_CORE_REG(regs.pc); + reg.addr = (uintptr_t) &env->pc; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } + + /* TODO: Set Rest of Registers */ + return ret; +} +#else int kvm_arch_get_registers(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -559,6 +683,7 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } +#endif void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { -- 1.7.9.5 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm