aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/virtual/kvm/api.txt5
-rw-r--r--arch/arm/include/asm/kvm_coproc.h9
-rw-r--r--arch/arm/include/asm/kvm_host.h4
-rw-r--r--arch/arm/kvm/coproc.c327
-rw-r--r--arch/arm/kvm/guest.c9
5 files changed, 350 insertions, 4 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 505049299298..0e2287406464 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1799,6 +1799,11 @@ is the register group type, or coprocessor number:
1799ARM core registers have the following id bit patterns: 1799ARM core registers have the following id bit patterns:
1800 0x4002 0000 0010 <index into the kvm_regs struct:16> 1800 0x4002 0000 0010 <index into the kvm_regs struct:16>
1801 1801
1802ARM 32-bit CP15 registers have the following id bit patterns:
1803 0x4002 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>
1804
1805ARM 64-bit CP15 registers have the following id bit patterns:
1806 0x4003 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>
1802 1807
1803 1808
18044.69 KVM_GET_ONE_REG 18094.69 KVM_GET_ONE_REG
diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h
index bd1ace030495..4917c2f7e459 100644
--- a/arch/arm/include/asm/kvm_coproc.h
+++ b/arch/arm/include/asm/kvm_coproc.h
@@ -34,5 +34,14 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
34int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); 34int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
35int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); 35int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
36int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); 36int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
37
38unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu);
39int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices);
37void kvm_coproc_table_init(void); 40void kvm_coproc_table_init(void);
41
42struct kvm_one_reg;
43int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
44int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
45int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
46unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
38#endif /* __ARM_KVM_COPROC_H__ */ 47#endif /* __ARM_KVM_COPROC_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index e1d4168d4f19..ed79043d7921 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
27#define KVM_MEMORY_SLOTS 32 27#define KVM_MEMORY_SLOTS 32
28#define KVM_PRIVATE_MEM_SLOTS 4 28#define KVM_PRIVATE_MEM_SLOTS 4
29#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 29#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
30#define KVM_HAVE_ONE_REG
30 31
31#define KVM_VCPU_MAX_FEATURES 0 32#define KVM_VCPU_MAX_FEATURES 0
32 33
@@ -137,6 +138,9 @@ int kvm_unmap_hva_range(struct kvm *kvm,
137 unsigned long start, unsigned long end); 138 unsigned long start, unsigned long end);
138void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); 139void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
139 140
141unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
142int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
143
140/* We do not have shadow page tables, hence the empty hooks */ 144/* We do not have shadow page tables, hence the empty hooks */
141static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva) 145static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
142{ 146{
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 722efe3b1675..95a0f5e5c1fc 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -18,6 +18,7 @@
18 */ 18 */
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/kvm_host.h> 20#include <linux/kvm_host.h>
21#include <linux/uaccess.h>
21#include <asm/kvm_arm.h> 22#include <asm/kvm_arm.h>
22#include <asm/kvm_host.h> 23#include <asm/kvm_host.h>
23#include <asm/kvm_emulate.h> 24#include <asm/kvm_emulate.h>
@@ -347,6 +348,328 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
347 return emulate_cp15(vcpu, &params); 348 return emulate_cp15(vcpu, &params);
348} 349}
349 350
351/******************************************************************************
352 * Userspace API
353 *****************************************************************************/
354
355static bool index_to_params(u64 id, struct coproc_params *params)
356{
357 switch (id & KVM_REG_SIZE_MASK) {
358 case KVM_REG_SIZE_U32:
359 /* Any unused index bits means it's not valid. */
360 if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
361 | KVM_REG_ARM_COPROC_MASK
362 | KVM_REG_ARM_32_CRN_MASK
363 | KVM_REG_ARM_CRM_MASK
364 | KVM_REG_ARM_OPC1_MASK
365 | KVM_REG_ARM_32_OPC2_MASK))
366 return false;
367
368 params->is_64bit = false;
369 params->CRn = ((id & KVM_REG_ARM_32_CRN_MASK)
370 >> KVM_REG_ARM_32_CRN_SHIFT);
371 params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
372 >> KVM_REG_ARM_CRM_SHIFT);
373 params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
374 >> KVM_REG_ARM_OPC1_SHIFT);
375 params->Op2 = ((id & KVM_REG_ARM_32_OPC2_MASK)
376 >> KVM_REG_ARM_32_OPC2_SHIFT);
377 return true;
378 case KVM_REG_SIZE_U64:
379 /* Any unused index bits means it's not valid. */
380 if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
381 | KVM_REG_ARM_COPROC_MASK
382 | KVM_REG_ARM_CRM_MASK
383 | KVM_REG_ARM_OPC1_MASK))
384 return false;
385 params->is_64bit = true;
386 params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
387 >> KVM_REG_ARM_CRM_SHIFT);
388 params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
389 >> KVM_REG_ARM_OPC1_SHIFT);
390 params->Op2 = 0;
391 params->CRn = 0;
392 return true;
393 default:
394 return false;
395 }
396}
397
398/* Decode an index value, and find the cp15 coproc_reg entry. */
399static const struct coproc_reg *index_to_coproc_reg(struct kvm_vcpu *vcpu,
400 u64 id)
401{
402 size_t num;
403 const struct coproc_reg *table, *r;
404 struct coproc_params params;
405
406 /* We only do cp15 for now. */
407 if ((id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT != 15)
408 return NULL;
409
410 if (!index_to_params(id, &params))
411 return NULL;
412
413 table = get_target_table(vcpu->arch.target, &num);
414 r = find_reg(&params, table, num);
415 if (!r)
416 r = find_reg(&params, cp15_regs, ARRAY_SIZE(cp15_regs));
417
418 /* Not saved in the cp15 array? */
419 if (r && !r->reg)
420 r = NULL;
421
422 return r;
423}
424
425/*
426 * These are the invariant cp15 registers: we let the guest see the host
427 * versions of these, so they're part of the guest state.
428 *
429 * A future CPU may provide a mechanism to present different values to
430 * the guest, or a future kvm may trap them.
431 */
432/* Unfortunately, there's no register-argument for mrc, so generate. */
433#define FUNCTION_FOR32(crn, crm, op1, op2, name) \
434 static void get_##name(struct kvm_vcpu *v, \
435 const struct coproc_reg *r) \
436 { \
437 u32 val; \
438 \
439 asm volatile("mrc p15, " __stringify(op1) \
440 ", %0, c" __stringify(crn) \
441 ", c" __stringify(crm) \
442 ", " __stringify(op2) "\n" : "=r" (val)); \
443 ((struct coproc_reg *)r)->val = val; \
444 }
445
446FUNCTION_FOR32(0, 0, 0, 0, MIDR)
447FUNCTION_FOR32(0, 0, 0, 1, CTR)
448FUNCTION_FOR32(0, 0, 0, 2, TCMTR)
449FUNCTION_FOR32(0, 0, 0, 3, TLBTR)
450FUNCTION_FOR32(0, 0, 0, 6, REVIDR)
451FUNCTION_FOR32(0, 1, 0, 0, ID_PFR0)
452FUNCTION_FOR32(0, 1, 0, 1, ID_PFR1)
453FUNCTION_FOR32(0, 1, 0, 2, ID_DFR0)
454FUNCTION_FOR32(0, 1, 0, 3, ID_AFR0)
455FUNCTION_FOR32(0, 1, 0, 4, ID_MMFR0)
456FUNCTION_FOR32(0, 1, 0, 5, ID_MMFR1)
457FUNCTION_FOR32(0, 1, 0, 6, ID_MMFR2)
458FUNCTION_FOR32(0, 1, 0, 7, ID_MMFR3)
459FUNCTION_FOR32(0, 2, 0, 0, ID_ISAR0)
460FUNCTION_FOR32(0, 2, 0, 1, ID_ISAR1)
461FUNCTION_FOR32(0, 2, 0, 2, ID_ISAR2)
462FUNCTION_FOR32(0, 2, 0, 3, ID_ISAR3)
463FUNCTION_FOR32(0, 2, 0, 4, ID_ISAR4)
464FUNCTION_FOR32(0, 2, 0, 5, ID_ISAR5)