Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: ARM: Add support for Cortex-A7

This patch adds support for running Cortex-A7 guests on Cortex-A7 hosts.

As Cortex-A7 is architecturally compatible with A15, this patch is largely just
generalising existing code. Areas where 'implementation defined' behaviour
is identical for A7 and A15 is moved to allow it to be used by both cores.

The check to ensure that coprocessor register tables are sorted correctly is
also moved in to 'common' code to avoid each new cpu doing its own check
(and possibly forgetting to do so!)

Signed-off-by: Jonathan Austin <jonathan.austin@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

authored by

Jonathan Austin and committed by
Christoffer Dall
e8c2d99f 5e497046

+184 -124
+1 -1
arch/arm/include/asm/kvm_asm.h
··· 39 39 #define c6_IFAR 17 /* Instruction Fault Address Register */ 40 40 #define c7_PAR 18 /* Physical Address Register */ 41 41 #define c7_PAR_high 19 /* PAR top 32 bits */ 42 - #define c9_L2CTLR 20 /* Cortex A15 L2 Control Register */ 42 + #define c9_L2CTLR 20 /* Cortex A15/A7 L2 Control Register */ 43 43 #define c10_PRRR 21 /* Primary Region Remap Register */ 44 44 #define c10_NMRR 22 /* Normal Memory Remap Register */ 45 45 #define c12_VBAR 23 /* Vector Base Address Register */
+2 -1
arch/arm/include/uapi/asm/kvm.h
··· 63 63 64 64 /* Supported Processor Types */ 65 65 #define KVM_ARM_TARGET_CORTEX_A15 0 66 - #define KVM_ARM_NUM_TARGETS 1 66 + #define KVM_ARM_TARGET_CORTEX_A7 1 67 + #define KVM_ARM_NUM_TARGETS 2 67 68 68 69 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ 69 70 #define KVM_ARM_DEVICE_TYPE_SHIFT 0
+1 -1
arch/arm/kvm/Makefile
··· 19 19 20 20 obj-y += kvm-arm.o init.o interrupts.o 21 21 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o 22 - obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o 22 + obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o 23 23 obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o 24 24 obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
+114
arch/arm/kvm/coproc.c
··· 71 71 return 1; 72 72 } 73 73 74 + static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 75 + { 76 + /* 77 + * Compute guest MPIDR. No need to mess around with different clusters 78 + * but we read the 'U' bit from the underlying hardware directly. 79 + */ 80 + vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & MPIDR_SMP_BITMASK) 81 + | vcpu->vcpu_id; 82 + } 83 + 84 + /* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */ 85 + static bool access_actlr(struct kvm_vcpu *vcpu, 86 + const struct coproc_params *p, 87 + const struct coproc_reg *r) 88 + { 89 + if (p->is_write) 90 + return ignore_write(vcpu, p); 91 + 92 + *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR]; 93 + return true; 94 + } 95 + 96 + /* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */ 97 + static bool access_cbar(struct kvm_vcpu *vcpu, 98 + const struct coproc_params *p, 99 + const struct coproc_reg *r) 100 + { 101 + if (p->is_write) 102 + return write_to_read_only(vcpu, p); 103 + return read_zero(vcpu, p); 104 + } 105 + 106 + /* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */ 107 + static bool access_l2ctlr(struct kvm_vcpu *vcpu, 108 + const struct coproc_params *p, 109 + const struct coproc_reg *r) 110 + { 111 + if (p->is_write) 112 + return ignore_write(vcpu, p); 113 + 114 + *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR]; 115 + return true; 116 + } 117 + 118 + static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 119 + { 120 + u32 l2ctlr, ncores; 121 + 122 + asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); 123 + l2ctlr &= ~(3 << 24); 124 + ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1; 125 + l2ctlr |= (ncores & 3) << 24; 126 + 127 + vcpu->arch.cp15[c9_L2CTLR] = l2ctlr; 128 + } 129 + 130 + static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 131 + { 132 + u32 actlr; 133 + 134 + /* ACTLR contains SMP bit: make sure you create all cpus first! */ 135 + asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr)); 136 + /* Make the SMP bit consistent with the guest configuration */ 137 + if (atomic_read(&vcpu->kvm->online_vcpus) > 1) 138 + actlr |= 1U << 6; 139 + else 140 + actlr &= ~(1U << 6); 141 + 142 + vcpu->arch.cp15[c1_ACTLR] = actlr; 143 + } 144 + 145 + /* 146 + * TRM entries: A7:4.3.50, A15:4.3.49 147 + * R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). 148 + */ 149 + static bool access_l2ectlr(struct kvm_vcpu *vcpu, 150 + const struct coproc_params *p, 151 + const struct coproc_reg *r) 152 + { 153 + if (p->is_write) 154 + return ignore_write(vcpu, p); 155 + 156 + *vcpu_reg(vcpu, p->Rt1) = 0; 157 + return true; 158 + } 159 + 74 160 /* See note at ARM ARM B1.14.4 */ 75 161 static bool access_dcsw(struct kvm_vcpu *vcpu, 76 162 const struct coproc_params *p, ··· 239 153 * registers preceding 32-bit ones. 240 154 */ 241 155 static const struct coproc_reg cp15_regs[] = { 156 + /* MPIDR: we use VMPIDR for guest access. */ 157 + { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32, 158 + NULL, reset_mpidr, c0_MPIDR }, 159 + 242 160 /* CSSELR: swapped by interrupt.S. */ 243 161 { CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32, 244 162 NULL, reset_unknown, c0_CSSELR }, 163 + 164 + /* ACTLR: trapped by HCR.TAC bit. */ 165 + { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32, 166 + access_actlr, reset_actlr, c1_ACTLR }, 167 + 168 + /* CPACR: swapped by interrupt.S. */ 169 + { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32, 170 + NULL, reset_val, c1_CPACR, 0x00000000 }, 245 171 246 172 /* TTBR0/TTBR1: swapped by interrupt.S. */ 247 173 { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 }, ··· 292 194 { CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw}, 293 195 { CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw}, 294 196 { CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw}, 197 + /* 198 + * L2CTLR access (guest wants to know #CPUs). 199 + */ 200 + { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, 201 + access_l2ctlr, reset_l2ctlr, c9_L2CTLR }, 202 + { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr}, 203 + 295 204 /* 296 205 * Dummy performance monitor implementation. 297 206 */ ··· 339 234 /* CNTKCTL: swapped by interrupt.S. */ 340 235 { CRn(14), CRm( 1), Op1( 0), Op2( 0), is32, 341 236 NULL, reset_val, c14_CNTKCTL, 0x00000000 }, 237 + 238 + /* The Configuration Base Address Register. */ 239 + { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar}, 342 240 }; 343 241 344 242 /* Target specific emulation tables */ ··· 349 241 350 242 void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table) 351 243 { 244 + unsigned int i; 245 + 246 + for (i = 1; i < table->num; i++) 247 + BUG_ON(cmp_reg(&table->table[i-1], 248 + &table->table[i]) >= 0); 249 + 352 250 target_tables[table->target] = table; 353 251 } 354 252
+1 -113
arch/arm/kvm/coproc_a15.c
··· 17 17 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 18 */ 19 19 #include <linux/kvm_host.h> 20 - #include <asm/cputype.h> 21 - #include <asm/kvm_arm.h> 22 - #include <asm/kvm_host.h> 23 - #include <asm/kvm_emulate.h> 24 20 #include <asm/kvm_coproc.h> 21 + #include <asm/kvm_emulate.h> 25 22 #include <linux/init.h> 26 23 27 - static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 28 - { 29 - /* 30 - * Compute guest MPIDR. No need to mess around with different clusters 31 - * but we read the 'U' bit from the underlying hardware directly. 32 - */ 33 - vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & MPIDR_SMP_BITMASK) 34 - | vcpu->vcpu_id; 35 - } 36 - 37 24 #include "coproc.h" 38 - 39 - /* A15 TRM 4.3.28: RO WI */ 40 - static bool access_actlr(struct kvm_vcpu *vcpu, 41 - const struct coproc_params *p, 42 - const struct coproc_reg *r) 43 - { 44 - if (p->is_write) 45 - return ignore_write(vcpu, p); 46 - 47 - *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR]; 48 - return true; 49 - } 50 - 51 - /* A15 TRM 4.3.60: R/O. */ 52 - static bool access_cbar(struct kvm_vcpu *vcpu, 53 - const struct coproc_params *p, 54 - const struct coproc_reg *r) 55 - { 56 - if (p->is_write) 57 - return write_to_read_only(vcpu, p); 58 - return read_zero(vcpu, p); 59 - } 60 - 61 - /* A15 TRM 4.3.48: R/O WI. */ 62 - static bool access_l2ctlr(struct kvm_vcpu *vcpu, 63 - const struct coproc_params *p, 64 - const struct coproc_reg *r) 65 - { 66 - if (p->is_write) 67 - return ignore_write(vcpu, p); 68 - 69 - *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR]; 70 - return true; 71 - } 72 - 73 - static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 74 - { 75 - u32 l2ctlr, ncores; 76 - 77 - asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); 78 - l2ctlr &= ~(3 << 24); 79 - ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1; 80 - l2ctlr |= (ncores & 3) << 24; 81 - 82 - vcpu->arch.cp15[c9_L2CTLR] = l2ctlr; 83 - } 84 - 85 - static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) 86 - { 87 - u32 actlr; 88 - 89 - /* ACTLR contains SMP bit: make sure you create all cpus first! */ 90 - asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr)); 91 - /* Make the SMP bit consistent with the guest configuration */ 92 - if (atomic_read(&vcpu->kvm->online_vcpus) > 1) 93 - actlr |= 1U << 6; 94 - else 95 - actlr &= ~(1U << 6); 96 - 97 - vcpu->arch.cp15[c1_ACTLR] = actlr; 98 - } 99 - 100 - /* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */ 101 - static bool access_l2ectlr(struct kvm_vcpu *vcpu, 102 - const struct coproc_params *p, 103 - const struct coproc_reg *r) 104 - { 105 - if (p->is_write) 106 - return ignore_write(vcpu, p); 107 - 108 - *vcpu_reg(vcpu, p->Rt1) = 0; 109 - return true; 110 - } 111 25 112 26 /* 113 27 * A15-specific CP15 registers. ··· 32 118 * registers preceding 32-bit ones. 33 119 */ 34 120 static const struct coproc_reg a15_regs[] = { 35 - /* MPIDR: we use VMPIDR for guest access. */ 36 - { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32, 37 - NULL, reset_mpidr, c0_MPIDR }, 38 - 39 121 /* SCTLR: swapped by interrupt.S. */ 40 122 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, 41 123 NULL, reset_val, c1_SCTLR, 0x00C50078 }, 42 - /* ACTLR: trapped by HCR.TAC bit. */ 43 - { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32, 44 - access_actlr, reset_actlr, c1_ACTLR }, 45 - /* CPACR: swapped by interrupt.S. */ 46 - { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32, 47 - NULL, reset_val, c1_CPACR, 0x00000000 }, 48 - 49 - /* 50 - * L2CTLR access (guest wants to know #CPUs). 51 - */ 52 - { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, 53 - access_l2ctlr, reset_l2ctlr, c9_L2CTLR }, 54 - { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr}, 55 - 56 - /* The Configuration Base Address Register. */ 57 - { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar}, 58 124 }; 59 125 60 126 static struct kvm_coproc_target_table a15_target_table = { ··· 45 151 46 152 static int __init coproc_a15_init(void) 47 153 { 48 - unsigned int i; 49 - 50 - for (i = 1; i < ARRAY_SIZE(a15_regs); i++) 51 - BUG_ON(cmp_reg(&a15_regs[i-1], 52 - &a15_regs[i]) >= 0); 53 - 54 154 kvm_register_target_coproc_table(&a15_target_table); 55 155 return 0; 56 156 }
+54
arch/arm/kvm/coproc_a7.c
··· 1 + /* 2 + * Copyright (C) 2012 - Virtual Open Systems and Columbia University 3 + * Copyright (C) 2013 - ARM Ltd 4 + * 5 + * Authors: Rusty Russell <rusty@rustcorp.au> 6 + * Christoffer Dall <c.dall@virtualopensystems.com> 7 + * Jonathan Austin <jonathan.austin@arm.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License, version 2, as 11 + * published by the Free Software Foundation. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 + */ 22 + #include <linux/kvm_host.h> 23 + #include <asm/kvm_coproc.h> 24 + #include <asm/kvm_emulate.h> 25 + #include <linux/init.h> 26 + 27 + #include "coproc.h" 28 + 29 + /* 30 + * Cortex-A7 specific CP15 registers. 31 + * CRn denotes the primary register number, but is copied to the CRm in the 32 + * user space API for 64-bit register access in line with the terminology used 33 + * in the ARM ARM. 34 + * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit 35 + * registers preceding 32-bit ones. 36 + */ 37 + static const struct coproc_reg a7_regs[] = { 38 + /* SCTLR: swapped by interrupt.S. */ 39 + { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, 40 + NULL, reset_val, c1_SCTLR, 0x00C50878 }, 41 + }; 42 + 43 + static struct kvm_coproc_target_table a7_target_table = { 44 + .target = KVM_ARM_TARGET_CORTEX_A7, 45 + .table = a7_regs, 46 + .num = ARRAY_SIZE(a7_regs), 47 + }; 48 + 49 + static int __init coproc_a7_init(void) 50 + { 51 + kvm_register_target_coproc_table(&a7_target_table); 52 + return 0; 53 + } 54 + late_initcall(coproc_a7_init);
+3 -1
arch/arm/kvm/guest.c
··· 190 190 return -EINVAL; 191 191 192 192 switch (part_number) { 193 + case ARM_CPU_PART_CORTEX_A7: 194 + return KVM_ARM_TARGET_CORTEX_A7; 193 195 case ARM_CPU_PART_CORTEX_A15: 194 196 return KVM_ARM_TARGET_CORTEX_A15; 195 197 default: ··· 204 202 { 205 203 unsigned int i; 206 204 207 - /* We can only do a cortex A15 for now. */ 205 + /* We can only cope with guest==host and only on A15/A7 (for now). */ 208 206 if (init->target != kvm_target_cpu()) 209 207 return -EINVAL; 210 208
+8 -7
arch/arm/kvm/reset.c
··· 30 30 #include <kvm/arm_arch_timer.h> 31 31 32 32 /****************************************************************************** 33 - * Cortex-A15 Reset Values 33 + * Cortex-A15 and Cortex-A7 Reset Values 34 34 */ 35 35 36 - static const int a15_max_cpu_idx = 3; 36 + static const int cortexa_max_cpu_idx = 3; 37 37 38 - static struct kvm_regs a15_regs_reset = { 38 + static struct kvm_regs cortexa_regs_reset = { 39 39 .usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT, 40 40 }; 41 41 42 - static const struct kvm_irq_level a15_vtimer_irq = { 42 + static const struct kvm_irq_level cortexa_vtimer_irq = { 43 43 { .irq = 27 }, 44 44 .level = 1, 45 45 }; ··· 62 62 const struct kvm_irq_level *cpu_vtimer_irq; 63 63 64 64 switch (vcpu->arch.target) { 65 + case KVM_ARM_TARGET_CORTEX_A7: 65 66 case KVM_ARM_TARGET_CORTEX_A15: 66 - if (vcpu->vcpu_id > a15_max_cpu_idx) 67 + if (vcpu->vcpu_id > cortexa_max_cpu_idx) 67 68 return -EINVAL; 68 - cpu_reset = &a15_regs_reset; 69 + cpu_reset = &cortexa_regs_reset; 69 70 vcpu->arch.midr = read_cpuid_id(); 70 - cpu_vtimer_irq = &a15_vtimer_irq; 71 + cpu_vtimer_irq = &cortexa_vtimer_irq; 71 72 break; 72 73 default: 73 74 return -ENODEV;