Reset all core and cp15 registers to their architecturally defined reset values at VCPU init time. Signed-off-by: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx> --- arch/arm/include/asm/kvm_arm.h | 6 ++ arch/arm/kvm/exports.c | 2 + arch/arm/kvm/reset.c | 100 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index c5bbef0..2f9d28e 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h @@ -19,4 +19,10 @@ #ifndef __ARM_KVM_ARM_H__ #define __ARM_KVM_ARM_H__ +/* Supported Processor Types */ +#define CORTEX_A15 (0xC0F) + +/* Multiprocessor Affinity Register */ +#define MPIDR_CPUID (0x3 << 0) + #endif /* __ARM_KVM_ARM_H__ */ diff --git a/arch/arm/kvm/exports.c b/arch/arm/kvm/exports.c index 01a2e41..3e38c95 100644 --- a/arch/arm/kvm/exports.c +++ b/arch/arm/kvm/exports.c @@ -17,3 +17,5 @@ */ #include <linux/module.h> + +EXPORT_SYMBOL_GPL(smp_send_reschedule); diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c index c250024..78488be 100644 --- a/arch/arm/kvm/reset.c +++ b/arch/arm/kvm/reset.c @@ -15,6 +15,73 @@ * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kvm_host.h> +#include <linux/kvm.h> + +#include <asm/unified.h> +#include <asm/ptrace.h> +#include <asm/cputype.h> +#include <asm/kvm_arm.h> + +#define CT_ASSERT(expr, name) extern char name[(expr) ? 1 : -1] +#define CP15_REGS_ASSERT(_array, _name) \ + CT_ASSERT((sizeof(_array) / sizeof(_array[0])) == nr_cp15_regs, _name) +#define UNKNOWN 0xdecafbad + +/****************************************************************************** + * Cortex-A15 Register Reset Values + */ + +static const int a15_max_cpu_idx = 3; + +static struct kvm_vcpu_regs a15_regs_reset = { + .cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT, +}; + +static u32 a15_cp15_regs_reset[][2] = { + { c0_MIDR, 0x412FC0F0 }, + { c0_MPIDR, 0x00000000 }, /* see kvm_arch_vcpu_init */ + { c1_SCTLR, 0x00C50078 }, + { c1_ACTLR, 0x00000000 }, + { c1_CPACR, 0x00000000 }, + { c2_TTBR0, UNKNOWN }, + { c2_TTBR0_high, UNKNOWN }, + { c2_TTBR1, UNKNOWN }, + { c2_TTBR1_high, UNKNOWN }, + { c2_TTBCR, 0x00000000 }, + { c3_DACR, UNKNOWN }, + { c5_DFSR, UNKNOWN }, + { c5_IFSR, UNKNOWN }, + { c5_ADFSR, UNKNOWN }, + { c5_AIFSR, UNKNOWN }, + { c6_DFAR, UNKNOWN }, + { c6_IFAR, UNKNOWN }, + { c10_PRRR, 0x00098AA4 }, + { c10_NMRR, 0x44E048E0 }, + { c12_VBAR, 0x00000000 }, + { c13_CID, 0x00000000 }, + { c13_TID_URW, UNKNOWN }, + { c13_TID_URO, UNKNOWN }, + { c13_TID_PRIV, UNKNOWN }, +}; +CP15_REGS_ASSERT(a15_cp15_regs_reset, a15_cp15_regs_reset_init); + +static void a15_reset_vcpu(struct kvm_vcpu *vcpu) +{ + /* + * Compute guest MPIDR: + * (Even if we present only one VCPU to the guest on an SMP + * host we don't set the U bit in the MPIDR, or vice versa, as + * revealing the underlying hardware properties is likely to + * be the best choice). + */ + vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & ~MPIDR_CPUID) + | (vcpu->vcpu_id & MPIDR_CPUID); +} + /******************************************************************************* * Exported reset function @@ -29,5 +96,38 @@ */ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) { + unsigned int i; + struct kvm_vcpu_regs *cpu_reset; + u32 (*cp15_reset)[2]; + void (*cpu_reset_vcpu)(struct kvm_vcpu *vcpu); + + switch (kvm_target_cpu()) { + case CORTEX_A15: + if (vcpu->vcpu_id > a15_max_cpu_idx) + return -EINVAL; + cpu_reset = &a15_regs_reset; + cp15_reset = a15_cp15_regs_reset; + cpu_reset_vcpu = a15_reset_vcpu; + break; + default: + return -ENODEV; + } + + /* Reset core registers */ + memcpy(&vcpu->arch.regs, cpu_reset, sizeof(vcpu->arch.regs)); + + /* Reset CP15 registers */ + for (i = 0; i < nr_cp15_regs; i++) { + if (cp15_reset[i][0] != i) { + kvm_err("CP15 field %d is %d, expected %d\n", + i, cp15_reset[i][0], i); + return -ENXIO; + } + vcpu->arch.cp15[i] = cp15_reset[i][1]; + } + + /* Physical CPU specific runtime reset operations */ + cpu_reset_vcpu(vcpu); + return 0; } -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html