aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/booke.c
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2008-12-02 16:51:55 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:55:09 -0500
commit7924bd41097ae8991c6d38cef8b1e4058e30d198 (patch)
treeb39629f81598739eb886126c5f3f8705656ce9cd /arch/powerpc/kvm/booke.c
parentc0ca609c5f874f7d6ae8e180afe79317e1943d22 (diff)
KVM: ppc: directly insert shadow mappings into the hardware TLB
Formerly, we used to maintain a per-vcpu shadow TLB and on every entry to the guest would load this array into the hardware TLB. This consumed 1280 bytes of memory (64 entries of 16 bytes plus a struct page pointer each), and also required some assembly to loop over the array on every entry. Instead of saving a copy in memory, we can just store shadow mappings directly into the hardware TLB, accepting that the host kernel will clobber these as part of the normal 440 TLB round robin. When we do that we need less than half the memory, and we have decreased the exit handling time for all guest exits, at the cost of increased number of TLB misses because the host overwrites some guest entries. These savings will be increased on processors with larger TLBs or which implement intelligent flush instructions like tlbivax (which will avoid the need to walk arrays in software). In addition to that and to the code simplification, we have a greater chance of leaving other host userspace mappings in the TLB, instead of forcing all subsequent tasks to re-fault all their mappings. Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kvm/booke.c')
-rw-r--r--arch/powerpc/kvm/booke.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 924c7b4b1107..eb24383c87d2 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -24,10 +24,12 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/vmalloc.h> 25#include <linux/vmalloc.h>
26#include <linux/fs.h> 26#include <linux/fs.h>
27
27#include <asm/cputable.h> 28#include <asm/cputable.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
29#include <asm/kvm_ppc.h> 30#include <asm/kvm_ppc.h>
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
32#include <asm/kvm_44x.h>
31 33
32#include "booke.h" 34#include "booke.h"
33#include "44x_tlb.h" 35#include "44x_tlb.h"
@@ -207,10 +209,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
207 * handled this interrupt the moment we enabled interrupts. 209 * handled this interrupt the moment we enabled interrupts.
208 * Now we just offer it a chance to reschedule the guest. */ 210 * Now we just offer it a chance to reschedule the guest. */
209 211
210 /* XXX At this point the TLB still holds our shadow TLB, so if
211 * we do reschedule the host will fault over it. Perhaps we
212 * should politely restore the host's entries to minimize
213 * misses before ceding control. */
214 vcpu->stat.dec_exits++; 212 vcpu->stat.dec_exits++;
215 if (need_resched()) 213 if (need_resched())
216 cond_resched(); 214 cond_resched();
@@ -281,14 +279,17 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
281 r = RESUME_GUEST; 279 r = RESUME_GUEST;
282 break; 280 break;
283 281
282 /* XXX move to a 440-specific file. */
284 case BOOKE_INTERRUPT_DTLB_MISS: { 283 case BOOKE_INTERRUPT_DTLB_MISS: {
284 struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
285 struct kvmppc_44x_tlbe *gtlbe; 285 struct kvmppc_44x_tlbe *gtlbe;
286 unsigned long eaddr = vcpu->arch.fault_dear; 286 unsigned long eaddr = vcpu->arch.fault_dear;
287 int gtlb_index;
287 gfn_t gfn; 288 gfn_t gfn;
288 289
289 /* Check the guest TLB. */ 290 /* Check the guest TLB. */
290 gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr); 291 gtlb_index = kvmppc_44x_dtlb_index(vcpu, eaddr);
291 if (!gtlbe) { 292 if (gtlb_index < 0) {
292 /* The guest didn't have a mapping for it. */ 293 /* The guest didn't have a mapping for it. */
293 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); 294 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS);
294 vcpu->arch.dear = vcpu->arch.fault_dear; 295 vcpu->arch.dear = vcpu->arch.fault_dear;
@@ -298,6 +299,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
298 break; 299 break;
299 } 300 }
300 301
302 gtlbe = &vcpu_44x->guest_tlb[gtlb_index];
301 vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr); 303 vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr);
302 gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT; 304 gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT;
303 305
@@ -309,7 +311,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
309 * Either way, we need to satisfy the fault without 311 * Either way, we need to satisfy the fault without
310 * invoking the guest. */ 312 * invoking the guest. */
311 kvmppc_mmu_map(vcpu, eaddr, vcpu->arch.paddr_accessed, gtlbe->tid, 313 kvmppc_mmu_map(vcpu, eaddr, vcpu->arch.paddr_accessed, gtlbe->tid,
312 gtlbe->word2, get_tlb_bytes(gtlbe)); 314 gtlbe->word2, get_tlb_bytes(gtlbe), gtlb_index);
313 vcpu->stat.dtlb_virt_miss_exits++; 315 vcpu->stat.dtlb_virt_miss_exits++;
314 r = RESUME_GUEST; 316 r = RESUME_GUEST;
315 } else { 317 } else {
@@ -322,17 +324,20 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
322 break; 324 break;
323 } 325 }
324 326
327 /* XXX move to a 440-specific file. */
325 case BOOKE_INTERRUPT_ITLB_MISS: { 328 case BOOKE_INTERRUPT_ITLB_MISS: {
329 struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
326 struct kvmppc_44x_tlbe *gtlbe; 330 struct kvmppc_44x_tlbe *gtlbe;
327 unsigned long eaddr = vcpu->arch.pc; 331 unsigned long eaddr = vcpu->arch.pc;
328 gpa_t gpaddr; 332 gpa_t gpaddr;
329 gfn_t gfn; 333 gfn_t gfn;
334 int gtlb_index;
330 335
331 r = RESUME_GUEST; 336 r = RESUME_GUEST;
332 337
333 /* Check the guest TLB. */ 338 /* Check the guest TLB. */
334 gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr); 339 gtlb_index = kvmppc_44x_itlb_index(vcpu, eaddr);
335 if (!gtlbe) { 340 if (gtlb_index < 0) {
336 /* The guest didn't have a mapping for it. */ 341 /* The guest didn't have a mapping for it. */
337 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS); 342 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS);
338 vcpu->stat.itlb_real_miss_exits++; 343 vcpu->stat.itlb_real_miss_exits++;
@@ -341,6 +346,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
341 346
342 vcpu->stat.itlb_virt_miss_exits++; 347 vcpu->stat.itlb_virt_miss_exits++;
343 348
349 gtlbe = &vcpu_44x->guest_tlb[gtlb_index];
344 gpaddr = tlb_xlate(gtlbe, eaddr); 350 gpaddr = tlb_xlate(gtlbe, eaddr);
345 gfn = gpaddr >> PAGE_SHIFT; 351 gfn = gpaddr >> PAGE_SHIFT;
346 352
@@ -352,7 +358,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
352 * Either way, we need to satisfy the fault without 358 * Either way, we need to satisfy the fault without
353 * invoking the guest. */ 359 * invoking the guest. */
354 kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlbe->tid, 360 kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlbe->tid,
355 gtlbe->word2, get_tlb_bytes(gtlbe)); 361 gtlbe->word2, get_tlb_bytes(gtlbe), gtlb_index);
356 } else { 362 } else {
357 /* Guest mapped and leaped at non-RAM! */ 363 /* Guest mapped and leaped at non-RAM! */
358 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK); 364 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK);