diff options
author | Hollis Blanchard <hollisb@us.ibm.com> | 2008-11-05 10:36:11 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2008-12-31 09:51:50 -0500 |
commit | a0d7b9f246074fab1f42678d203ef4ba281505f2 (patch) | |
tree | 0e84016c1ddabdde19b0eda3954f53371a8e9b75 /arch/powerpc/kvm/44x_tlb.c | |
parent | 2843099fee32a6020e1caa95c6026f28b5d43bff (diff) |
KVM: ppc: Move 440-specific TLB code into 44x_tlb.c
This will make it easier to provide implementations for other cores.
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kvm/44x_tlb.c')
-rw-r--r-- | arch/powerpc/kvm/44x_tlb.c | 138 |
1 files changed, 136 insertions, 2 deletions
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index ad72c6f9811f..dd75ab84e04e 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -32,6 +32,34 @@ | |||
32 | 32 | ||
33 | static unsigned int kvmppc_tlb_44x_pos; | 33 | static unsigned int kvmppc_tlb_44x_pos; |
34 | 34 | ||
35 | #ifdef DEBUG | ||
36 | void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | ||
37 | { | ||
38 | struct kvmppc_44x_tlbe *tlbe; | ||
39 | int i; | ||
40 | |||
41 | printk("vcpu %d TLB dump:\n", vcpu->vcpu_id); | ||
42 | printk("| %2s | %3s | %8s | %8s | %8s |\n", | ||
43 | "nr", "tid", "word0", "word1", "word2"); | ||
44 | |||
45 | for (i = 0; i < PPC44x_TLB_SIZE; i++) { | ||
46 | tlbe = &vcpu->arch.guest_tlb[i]; | ||
47 | if (tlbe->word0 & PPC44x_TLB_VALID) | ||
48 | printk(" G%2d | %02X | %08X | %08X | %08X |\n", | ||
49 | i, tlbe->tid, tlbe->word0, tlbe->word1, | ||
50 | tlbe->word2); | ||
51 | } | ||
52 | |||
53 | for (i = 0; i < PPC44x_TLB_SIZE; i++) { | ||
54 | tlbe = &vcpu->arch.shadow_tlb[i]; | ||
55 | if (tlbe->word0 & PPC44x_TLB_VALID) | ||
56 | printk(" S%2d | %02X | %08X | %08X | %08X |\n", | ||
57 | i, tlbe->tid, tlbe->word0, tlbe->word1, | ||
58 | tlbe->word2); | ||
59 | } | ||
60 | } | ||
61 | #endif | ||
62 | |||
35 | static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode) | 63 | static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode) |
36 | { | 64 | { |
37 | /* Mask off reserved bits. */ | 65 | /* Mask off reserved bits. */ |
@@ -191,8 +219,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, | |||
191 | handler); | 219 | handler); |
192 | } | 220 | } |
193 | 221 | ||
194 | void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr, | 222 | static void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr, |
195 | gva_t eend, u32 asid) | 223 | gva_t eend, u32 asid) |
196 | { | 224 | { |
197 | unsigned int pid = !(asid & 0xff); | 225 | unsigned int pid = !(asid & 0xff); |
198 | int i; | 226 | int i; |
@@ -249,3 +277,109 @@ void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | |||
249 | 277 | ||
250 | vcpu->arch.shadow_pid = !usermode; | 278 | vcpu->arch.shadow_pid = !usermode; |
251 | } | 279 | } |
280 | |||
281 | static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | ||
282 | const struct tlbe *tlbe) | ||
283 | { | ||
284 | gpa_t gpa; | ||
285 | |||
286 | if (!get_tlb_v(tlbe)) | ||
287 | return 0; | ||
288 | |||
289 | /* Does it match current guest AS? */ | ||
290 | /* XXX what about IS != DS? */ | ||
291 | if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) | ||
292 | return 0; | ||
293 | |||
294 | gpa = get_tlb_raddr(tlbe); | ||
295 | if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT)) | ||
296 | /* Mapping is not for RAM. */ | ||
297 | return 0; | ||
298 | |||
299 | return 1; | ||
300 | } | ||
301 | |||
302 | int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws) | ||
303 | { | ||
304 | u64 eaddr; | ||
305 | u64 raddr; | ||
306 | u64 asid; | ||
307 | u32 flags; | ||
308 | struct tlbe *tlbe; | ||
309 | unsigned int index; | ||
310 | |||
311 | index = vcpu->arch.gpr[ra]; | ||
312 | if (index > PPC44x_TLB_SIZE) { | ||
313 | printk("%s: index %d\n", __func__, index); | ||
314 | kvmppc_dump_vcpu(vcpu); | ||
315 | return EMULATE_FAIL; | ||
316 | } | ||
317 | |||
318 | tlbe = &vcpu->arch.guest_tlb[index]; | ||
319 | |||
320 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ | ||
321 | if (tlbe->word0 & PPC44x_TLB_VALID) { | ||
322 | eaddr = get_tlb_eaddr(tlbe); | ||
323 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
324 | kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid); | ||
325 | } | ||
326 | |||
327 | switch (ws) { | ||
328 | case PPC44x_TLB_PAGEID: | ||
329 | tlbe->tid = vcpu->arch.mmucr & 0xff; | ||
330 | tlbe->word0 = vcpu->arch.gpr[rs]; | ||
331 | break; | ||
332 | |||
333 | case PPC44x_TLB_XLAT: | ||
334 | tlbe->word1 = vcpu->arch.gpr[rs]; | ||
335 | break; | ||
336 | |||
337 | case PPC44x_TLB_ATTRIB: | ||
338 | tlbe->word2 = vcpu->arch.gpr[rs]; | ||
339 | break; | ||
340 | |||
341 | default: | ||
342 | return EMULATE_FAIL; | ||
343 | } | ||
344 | |||
345 | if (tlbe_is_host_safe(vcpu, tlbe)) { | ||
346 | eaddr = get_tlb_eaddr(tlbe); | ||
347 | raddr = get_tlb_raddr(tlbe); | ||
348 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
349 | flags = tlbe->word2 & 0xffff; | ||
350 | |||
351 | /* Create a 4KB mapping on the host. If the guest wanted a | ||
352 | * large page, only the first 4KB is mapped here and the rest | ||
353 | * are mapped on the fly. */ | ||
354 | kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags); | ||
355 | } | ||
356 | |||
357 | KVMTRACE_5D(GTLB_WRITE, vcpu, index, | ||
358 | tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2, | ||
359 | handler); | ||
360 | |||
361 | return EMULATE_DONE; | ||
362 | } | ||
363 | |||
364 | int kvmppc_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, u8 rc) | ||
365 | { | ||
366 | u32 ea; | ||
367 | int index; | ||
368 | unsigned int as = get_mmucr_sts(vcpu); | ||
369 | unsigned int pid = get_mmucr_stid(vcpu); | ||
370 | |||
371 | ea = vcpu->arch.gpr[rb]; | ||
372 | if (ra) | ||
373 | ea += vcpu->arch.gpr[ra]; | ||
374 | |||
375 | index = kvmppc_44x_tlb_index(vcpu, ea, pid, as); | ||
376 | if (rc) { | ||
377 | if (index < 0) | ||
378 | vcpu->arch.cr &= ~0x20000000; | ||
379 | else | ||
380 | vcpu->arch.cr |= 0x20000000; | ||
381 | } | ||
382 | vcpu->arch.gpr[rt] = index; | ||
383 | |||
384 | return EMULATE_DONE; | ||
385 | } | ||