diff options
| -rw-r--r-- | Documentation/virtual/kvm/api.txt | 5 | ||||
| -rw-r--r-- | arch/arm/include/asm/kvm_coproc.h | 9 | ||||
| -rw-r--r-- | arch/arm/include/asm/kvm_host.h | 4 | ||||
| -rw-r--r-- | arch/arm/kvm/coproc.c | 327 | ||||
| -rw-r--r-- | arch/arm/kvm/guest.c | 9 |
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: | |||
| 1799 | ARM core registers have the following id bit patterns: | 1799 | ARM 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 | ||
| 1802 | ARM 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 | |||
| 1805 | ARM 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 | ||
| 1804 | 4.69 KVM_GET_ONE_REG | 1809 | 4.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); | |||
| 34 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); | 34 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); |
| 35 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); | 35 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); |
| 36 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); | 36 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); |
| 37 | |||
| 38 | unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu); | ||
| 39 | int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices); | ||
| 37 | void kvm_coproc_table_init(void); | 40 | void kvm_coproc_table_init(void); |
| 41 | |||
| 42 | struct kvm_one_reg; | ||
| 43 | int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); | ||
| 44 | int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); | ||
| 45 | int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); | ||
| 46 | unsigned 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); |
| 138 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); | 139 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); |
| 139 | 140 | ||
| 141 | unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); | ||
| 142 | int 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 */ |
| 141 | static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva) | 145 | static 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, ¶ms); | 348 | return emulate_cp15(vcpu, ¶ms); |
| 348 | } | 349 | } |
| 349 | 350 | ||
| 351 | /****************************************************************************** | ||
| 352 | * Userspace API | ||
| 353 | *****************************************************************************/ | ||
| 354 | |||
| 355 | static 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. */ | ||
| 399 | static 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, ¶ms)) | ||
| 411 | return NULL; | ||
| 412 | |||
| 413 | table = get_target_table(vcpu->arch.target, &num); | ||
| 414 | r = find_reg(¶ms, table, num); | ||
| 415 | if (!r) | ||
| 416 | r = find_reg(¶ms, 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 | |||
| 446 | FUNCTION_FOR32(0, 0, 0, 0, MIDR) | ||
| 447 | FUNCTION_FOR32(0, 0, 0, 1, CTR) | ||
| 448 | FUNCTION_FOR32(0, 0, 0, 2, TCMTR) | ||
| 449 | FUNCTION_FOR32(0, 0, 0, 3, TLBTR) | ||
| 450 | FUNCTION_FOR32(0, 0, 0, 6, REVIDR) | ||
| 451 | FUNCTION_FOR32(0, 1, 0, 0, ID_PFR0) | ||
| 452 | FUNCTION_FOR32(0, 1, 0, 1, ID_PFR1) | ||
| 453 | FUNCTION_FOR32(0, 1, 0, 2, ID_DFR0) | ||
| 454 | FUNCTION_FOR32(0, 1, 0, 3, ID_AFR0) | ||
| 455 | FUNCTION_FOR32(0, 1, 0, 4, ID_MMFR0) | ||
| 456 | FUNCTION_FOR32(0, 1, 0, 5, ID_MMFR1) | ||
| 457 | FUNCTION_FOR32(0, 1, 0, 6, ID_MMFR2) | ||
| 458 | FUNCTION_FOR32(0, 1, 0, 7, ID_MMFR3) | ||
| 459 | FUNCTION_FOR32(0, 2, 0, 0, ID_ISAR0) | ||
| 460 | FUNCTION_FOR32(0, 2, 0, 1, ID_ISAR1) | ||
| 461 | FUNCTION_FOR32(0, 2, 0, 2, ID_ISAR2) | ||
| 462 | FUNCTION_FOR32(0, 2, 0, 3, ID_ISAR3) | ||
| 463 | FUNCTION_FOR32(0, 2, 0, 4, ID_ISAR4) | ||
| 464 | FUNCTION_FOR32(0, 2, 0, 5, ID_ISAR5) | ||
