diff options
author | James Hogan <james.hogan@imgtec.com> | 2016-09-10 18:56:46 -0400 |
---|---|---|
committer | James Hogan <james.hogan@imgtec.com> | 2017-02-03 10:20:53 -0500 |
commit | a7cfa7ac1236937dac431845596a39ba27364a00 (patch) | |
tree | 38a785ddc708a46158c709f726eac63dbe2f0a00 | |
parent | 29b500b54ef379f1f3227b633dd477a4dd3cd62b (diff) |
KVM: MIPS: Add fast path TLB refill handler
Use functions from the general MIPS TLB exception vector generation code
(tlbex.c) to construct a fast path TLB refill handler similar to the
general one, but cut down and capable of preserving K0 and K1.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
-rw-r--r-- | arch/mips/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/mips/kvm/entry.c | 78 | ||||
-rw-r--r-- | arch/mips/kvm/mips.c | 8 |
3 files changed, 84 insertions, 3 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index fea538fc5331..80928ffa0150 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h | |||
@@ -554,6 +554,7 @@ extern int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu); | |||
554 | /* Building of entry/exception code */ | 554 | /* Building of entry/exception code */ |
555 | int kvm_mips_entry_setup(void); | 555 | int kvm_mips_entry_setup(void); |
556 | void *kvm_mips_build_vcpu_run(void *addr); | 556 | void *kvm_mips_build_vcpu_run(void *addr); |
557 | void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler); | ||
557 | void *kvm_mips_build_exception(void *addr, void *handler); | 558 | void *kvm_mips_build_exception(void *addr, void *handler); |
558 | void *kvm_mips_build_exit(void *addr); | 559 | void *kvm_mips_build_exit(void *addr); |
559 | 560 | ||
diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c index 7424d3d566ff..1ae33e0e675c 100644 --- a/arch/mips/kvm/entry.c +++ b/arch/mips/kvm/entry.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/mmu_context.h> | 16 | #include <asm/mmu_context.h> |
17 | #include <asm/msa.h> | 17 | #include <asm/msa.h> |
18 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
19 | #include <asm/tlbex.h> | ||
19 | #include <asm/uasm.h> | 20 | #include <asm/uasm.h> |
20 | 21 | ||
21 | /* Register names */ | 22 | /* Register names */ |
@@ -122,6 +123,9 @@ int kvm_mips_entry_setup(void) | |||
122 | */ | 123 | */ |
123 | unsigned int kscratch_mask = cpu_data[0].kscratch_mask; | 124 | unsigned int kscratch_mask = cpu_data[0].kscratch_mask; |
124 | 125 | ||
126 | if (pgd_reg != -1) | ||
127 | kscratch_mask &= ~BIT(pgd_reg); | ||
128 | |||
125 | /* Pick a scratch register for storing VCPU */ | 129 | /* Pick a scratch register for storing VCPU */ |
126 | if (kscratch_mask) { | 130 | if (kscratch_mask) { |
127 | scratch_vcpu[0] = c0_kscratch(); | 131 | scratch_vcpu[0] = c0_kscratch(); |
@@ -381,6 +385,80 @@ static void *kvm_mips_build_enter_guest(void *addr) | |||
381 | } | 385 | } |
382 | 386 | ||
383 | /** | 387 | /** |
388 | * kvm_mips_build_tlb_refill_exception() - Assemble TLB refill handler. | ||
389 | * @addr: Address to start writing code. | ||
390 | * @handler: Address of common handler (within range of @addr). | ||
391 | * | ||
392 | * Assemble TLB refill exception fast path handler for guest execution. | ||
393 | * | ||
394 | * Returns: Next address after end of written function. | ||
395 | */ | ||
396 | void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler) | ||
397 | { | ||
398 | u32 *p = addr; | ||
399 | struct uasm_label labels[2]; | ||
400 | struct uasm_reloc relocs[2]; | ||
401 | struct uasm_label *l = labels; | ||
402 | struct uasm_reloc *r = relocs; | ||
403 | |||
404 | memset(labels, 0, sizeof(labels)); | ||
405 | memset(relocs, 0, sizeof(relocs)); | ||
406 | |||
407 | /* Save guest k1 into scratch register */ | ||
408 | UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]); | ||
409 | |||
410 | /* Get the VCPU pointer from the VCPU scratch register */ | ||
411 | UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]); | ||
412 | |||
413 | /* Save guest k0 into VCPU structure */ | ||
414 | UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1); | ||
415 | |||
416 | /* | ||
417 | * Some of the common tlbex code uses current_cpu_type(). For KVM we | ||
418 | * assume symmetry and just disable preemption to silence the warning. | ||
419 | */ | ||
420 | preempt_disable(); | ||
421 | |||
422 | /* | ||
423 | * Now for the actual refill bit. A lot of this can be common with the | ||
424 | * Linux TLB refill handler, however we don't need to handle so many | ||
425 | * cases. We only need to handle user mode refills, and user mode runs | ||
426 | * with 32-bit addressing. | ||
427 | * | ||
428 | * Therefore the branch to label_vmalloc generated by build_get_pmde64() | ||
429 | * that isn't resolved should never actually get taken and is harmless | ||
430 | * to leave in place for now. | ||
431 | */ | ||
432 | |||
433 | #ifdef CONFIG_64BIT | ||
434 | build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ | ||
435 | #else | ||
436 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ | ||
437 | #endif | ||
438 | |||
439 | /* we don't support huge pages yet */ | ||
440 | |||
441 | build_get_ptep(&p, K0, K1); | ||
442 | build_update_entries(&p, K0, K1); | ||
443 | build_tlb_write_entry(&p, &l, &r, tlb_random); | ||
444 | |||
445 | preempt_enable(); | ||
446 | |||
447 | /* Get the VCPU pointer from the VCPU scratch register again */ | ||
448 | UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]); | ||
449 | |||
450 | /* Restore the guest's k0/k1 registers */ | ||
451 | UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1); | ||
452 | uasm_i_ehb(&p); | ||
453 | UASM_i_MFC0(&p, K1, scratch_tmp[0], scratch_tmp[1]); | ||
454 | |||
455 | /* Jump to guest */ | ||
456 | uasm_i_eret(&p); | ||
457 | |||
458 | return p; | ||
459 | } | ||
460 | |||
461 | /** | ||
384 | * kvm_mips_build_exception() - Assemble first level guest exception handler. | 462 | * kvm_mips_build_exception() - Assemble first level guest exception handler. |
385 | * @addr: Address to start writing code. | 463 | * @addr: Address to start writing code. |
386 | * @handler: Address of common handler (within range of @addr). | 464 | * @handler: Address of common handler (within range of @addr). |
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 7cf85fa1f658..a687864de428 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c | |||
@@ -264,7 +264,7 @@ static inline void dump_handler(const char *symbol, void *start, void *end) | |||
264 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | 264 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) |
265 | { | 265 | { |
266 | int err, size; | 266 | int err, size; |
267 | void *gebase, *p, *handler; | 267 | void *gebase, *p, *handler, *refill_start, *refill_end; |
268 | int i; | 268 | int i; |
269 | 269 | ||
270 | struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); | 270 | struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); |
@@ -317,8 +317,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | |||
317 | /* Build guest exception vectors dynamically in unmapped memory */ | 317 | /* Build guest exception vectors dynamically in unmapped memory */ |
318 | handler = gebase + 0x2000; | 318 | handler = gebase + 0x2000; |
319 | 319 | ||
320 | /* TLB Refill, EXL = 0 */ | 320 | /* TLB refill */ |
321 | kvm_mips_build_exception(gebase, handler); | 321 | refill_start = gebase; |
322 | refill_end = kvm_mips_build_tlb_refill_exception(refill_start, handler); | ||
322 | 323 | ||
323 | /* General Exception Entry point */ | 324 | /* General Exception Entry point */ |
324 | kvm_mips_build_exception(gebase + 0x180, handler); | 325 | kvm_mips_build_exception(gebase + 0x180, handler); |
@@ -344,6 +345,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | |||
344 | pr_debug("#include <asm/regdef.h>\n"); | 345 | pr_debug("#include <asm/regdef.h>\n"); |
345 | pr_debug("\n"); | 346 | pr_debug("\n"); |
346 | dump_handler("kvm_vcpu_run", vcpu->arch.vcpu_run, p); | 347 | dump_handler("kvm_vcpu_run", vcpu->arch.vcpu_run, p); |
348 | dump_handler("kvm_tlb_refill", refill_start, refill_end); | ||
347 | dump_handler("kvm_gen_exc", gebase + 0x180, gebase + 0x200); | 349 | dump_handler("kvm_gen_exc", gebase + 0x180, gebase + 0x200); |
348 | dump_handler("kvm_exit", gebase + 0x2000, vcpu->arch.vcpu_run); | 350 | dump_handler("kvm_exit", gebase + 0x2000, vcpu->arch.vcpu_run); |
349 | 351 | ||