| /* | 
 |  * ARM implementation of KVM hooks, 64 bit specific code | 
 |  * | 
 |  * Copyright Mian-M. Hamayun 2013, Virtual Open Systems | 
 |  * | 
 |  * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
 |  * See the COPYING file in the top-level directory. | 
 |  * | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <sys/types.h> | 
 | #include <sys/ioctl.h> | 
 | #include <sys/mman.h> | 
 |  | 
 | #include <linux/kvm.h> | 
 |  | 
 | #include "qemu-common.h" | 
 | #include "qemu/timer.h" | 
 | #include "sysemu/sysemu.h" | 
 | #include "sysemu/kvm.h" | 
 | #include "kvm_arm.h" | 
 | #include "cpu.h" | 
 | #include "hw/arm/arm.h" | 
 |  | 
 | static inline void set_feature(uint64_t *features, int feature) | 
 | { | 
 |     *features |= 1ULL << feature; | 
 | } | 
 |  | 
 | bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) | 
 | { | 
 |     /* 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; | 
 |     /* 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 | 
 |      * support only a very limited number of CPUs. | 
 |      */ | 
 |     static const uint32_t cpus_to_try[] = { | 
 |         KVM_ARM_TARGET_AEM_V8, | 
 |         KVM_ARM_TARGET_FOUNDATION_V8, | 
 |         KVM_ARM_TARGET_CORTEX_A57, | 
 |         QEMU_KVM_ARM_TARGET_NONE | 
 |     }; | 
 |     struct kvm_vcpu_init init; | 
 |  | 
 |     if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     ahcc->target = init.target; | 
 |     ahcc->dtb_compatible = "arm,arm-v8"; | 
 |  | 
 |     kvm_arm_destroy_scratch_host_vcpu(fdarray); | 
 |  | 
 |    /* 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. | 
 |      */ | 
 |     set_feature(&features, ARM_FEATURE_V8); | 
 |     set_feature(&features, ARM_FEATURE_VFP4); | 
 |     set_feature(&features, ARM_FEATURE_NEON); | 
 |     set_feature(&features, ARM_FEATURE_AARCH64); | 
 |  | 
 |     ahcc->features = features; | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | int kvm_arch_init_vcpu(CPUState *cs) | 
 | { | 
 |     int ret; | 
 |     ARMCPU *cpu = ARM_CPU(cs); | 
 |  | 
 |     if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE || | 
 |         !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { | 
 |         fprintf(stderr, "KVM is not supported for this guest CPU type\n"); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     /* Determine init features for this CPU */ | 
 |     memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); | 
 |     if (cpu->start_powered_off) { | 
 |         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF; | 
 |     } | 
 |     if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) { | 
 |         cpu->psci_version = 2; | 
 |         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; | 
 |     } | 
 |  | 
 |     /* Do KVM_ARM_VCPU_INIT ioctl */ | 
 |     ret = kvm_arm_vcpu_init(cs); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     /* TODO : support for save/restore/reset of system regs via tuple list */ | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | #define AARCH64_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ | 
 |                  KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) | 
 |  | 
 | int kvm_arch_put_registers(CPUState *cs, int level) | 
 | { | 
 |     struct kvm_one_reg reg; | 
 |     uint64_t val; | 
 |     int i; | 
 |     int ret; | 
 |  | 
 |     ARMCPU *cpu = ARM_CPU(cs); | 
 |     CPUARMState *env = &cpu->env; | 
 |  | 
 |     for (i = 0; i < 31; 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; | 
 |         } | 
 |     } | 
 |  | 
 |     /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the | 
 |      * QEMU side we keep the current SP in xregs[31] as well. | 
 |      */ | 
 |     if (env->pstate & PSTATE_SP) { | 
 |         env->sp_el[1] = env->xregs[31]; | 
 |     } else { | 
 |         env->sp_el[0] = env->xregs[31]; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(regs.sp); | 
 |     reg.addr = (uintptr_t) &env->sp_el[0]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(sp_el1); | 
 |     reg.addr = (uintptr_t) &env->sp_el[1]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */ | 
 |     val = pstate_read(env); | 
 |     reg.id = AARCH64_CORE_REG(regs.pstate); | 
 |     reg.addr = (uintptr_t) &val; | 
 |     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; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(elr_el1); | 
 |     reg.addr = (uintptr_t) &env->elr_el[1]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     for (i = 0; i < KVM_NR_SPSR; i++) { | 
 |         reg.id = AARCH64_CORE_REG(spsr[i]); | 
 |         reg.addr = (uintptr_t) &env->banked_spsr[i - 1]; | 
 |         ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); | 
 |         if (ret) { | 
 |             return ret; | 
 |         } | 
 |     } | 
 |  | 
 |     /* TODO: | 
 |      * FP state | 
 |      * system registers | 
 |      */ | 
 |     return ret; | 
 | } | 
 |  | 
 | int kvm_arch_get_registers(CPUState *cs) | 
 | { | 
 |     struct kvm_one_reg reg; | 
 |     uint64_t val; | 
 |     int i; | 
 |     int ret; | 
 |  | 
 |     ARMCPU *cpu = ARM_CPU(cs); | 
 |     CPUARMState *env = &cpu->env; | 
 |  | 
 |     for (i = 0; i < 31; 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->sp_el[0]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(sp_el1); | 
 |     reg.addr = (uintptr_t) &env->sp_el[1]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(regs.pstate); | 
 |     reg.addr = (uintptr_t) &val; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |     pstate_write(env, val); | 
 |  | 
 |     /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the | 
 |      * QEMU side we keep the current SP in xregs[31] as well. | 
 |      */ | 
 |     if (env->pstate & PSTATE_SP) { | 
 |         env->xregs[31] = env->sp_el[1]; | 
 |     } else { | 
 |         env->xregs[31] = env->sp_el[0]; | 
 |     } | 
 |  | 
 |     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; | 
 |     } | 
 |  | 
 |     reg.id = AARCH64_CORE_REG(elr_el1); | 
 |     reg.addr = (uintptr_t) &env->elr_el[1]; | 
 |     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); | 
 |     if (ret) { | 
 |         return ret; | 
 |     } | 
 |  | 
 |     for (i = 0; i < KVM_NR_SPSR; i++) { | 
 |         reg.id = AARCH64_CORE_REG(spsr[i]); | 
 |         reg.addr = (uintptr_t) &env->banked_spsr[i - 1]; | 
 |         ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); | 
 |         if (ret) { | 
 |             return ret; | 
 |         } | 
 |     } | 
 |  | 
 |     /* TODO: other registers */ | 
 |     return ret; | 
 | } | 
 |  | 
 | void kvm_arm_reset_vcpu(ARMCPU *cpu) | 
 | { | 
 |     /* Re-init VCPU so that all registers are set to | 
 |      * their respective reset values. | 
 |      */ | 
 |     kvm_arm_vcpu_init(CPU(cpu)); | 
 | } |