diff options
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/44x_emulate.c | 9 | ||||
-rw-r--r-- | arch/powerpc/kvm/44x_tlb.c | 31 |
2 files changed, 18 insertions, 22 deletions
diff --git a/arch/powerpc/kvm/44x_emulate.c b/arch/powerpc/kvm/44x_emulate.c index 9bc50cebf9ec..9ef79c78ede9 100644 --- a/arch/powerpc/kvm/44x_emulate.c +++ b/arch/powerpc/kvm/44x_emulate.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/dcr.h> | 21 | #include <asm/dcr.h> |
22 | #include <asm/dcr-regs.h> | 22 | #include <asm/dcr-regs.h> |
23 | #include <asm/disassemble.h> | 23 | #include <asm/disassemble.h> |
24 | #include <asm/kvm_44x.h> | ||
24 | 25 | ||
25 | #include "booke.h" | 26 | #include "booke.h" |
26 | #include "44x_tlb.h" | 27 | #include "44x_tlb.h" |
@@ -38,14 +39,6 @@ | |||
38 | #define XOP_ICCCI 966 | 39 | #define XOP_ICCCI 966 |
39 | #define XOP_TLBWE 978 | 40 | #define XOP_TLBWE 978 |
40 | 41 | ||
41 | static inline void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid) | ||
42 | { | ||
43 | if (vcpu->arch.pid != new_pid) { | ||
44 | vcpu->arch.pid = new_pid; | ||
45 | vcpu->arch.swap_pid = 1; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) | 42 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) |
50 | { | 43 | { |
51 | vcpu->arch.pc = vcpu->arch.srr0; | 44 | vcpu->arch.pc = vcpu->arch.srr0; |
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 6fadbd696021..ee2461860bcf 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -268,31 +268,34 @@ static void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
268 | } | 268 | } |
269 | } | 269 | } |
270 | 270 | ||
271 | /* Invalidate all mappings on the privilege switch after PID has been changed. | ||
272 | * The guest always runs with PID=1, so we must clear the entire TLB when | ||
273 | * switching address spaces. */ | ||
274 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | 271 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) |
275 | { | 272 | { |
273 | vcpu->arch.shadow_pid = !usermode; | ||
274 | } | ||
275 | |||
276 | void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid) | ||
277 | { | ||
276 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | 278 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); |
277 | int i; | 279 | int i; |
278 | 280 | ||
279 | if (vcpu->arch.swap_pid) { | 281 | if (unlikely(vcpu->arch.pid == new_pid)) |
280 | /* XXX Replace loop with fancy data structures. */ | 282 | return; |
281 | for (i = 0; i <= tlb_44x_hwater; i++) { | 283 | |
282 | struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i]; | 284 | vcpu->arch.pid = new_pid; |
285 | |||
286 | /* Guest userspace runs with TID=0 mappings and PID=0, to make sure it | ||
287 | * can't access guest kernel mappings (TID=1). When we switch to a new | ||
288 | * guest PID, which will also use host PID=0, we must discard the old guest | ||
289 | * userspace mappings. */ | ||
290 | for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_tlb); i++) { | ||
291 | struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i]; | ||
283 | 292 | ||
284 | /* Future optimization: clear only userspace mappings. */ | 293 | if (get_tlb_tid(stlbe) == 0) { |
285 | kvmppc_44x_shadow_release(vcpu, i); | 294 | kvmppc_44x_shadow_release(vcpu, i); |
286 | stlbe->word0 = 0; | 295 | stlbe->word0 = 0; |
287 | kvmppc_tlbe_set_modified(vcpu, i); | 296 | kvmppc_tlbe_set_modified(vcpu, i); |
288 | KVMTRACE_5D(STLB_INVAL, vcpu, i, | ||
289 | stlbe->tid, stlbe->word0, stlbe->word1, | ||
290 | stlbe->word2, handler); | ||
291 | } | 297 | } |
292 | vcpu->arch.swap_pid = 0; | ||
293 | } | 298 | } |
294 | |||
295 | vcpu->arch.shadow_pid = !usermode; | ||
296 | } | 299 | } |
297 | 300 | ||
298 | static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | 301 | static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, |