diff options
author | Liu Yu <yu.liu@freescale.com> | 2011-06-14 19:34:59 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-07-12 06:16:38 -0400 |
commit | 08b7fa92b9250eab0f493f7721977e781a887b3d (patch) | |
tree | c798369236627a144d541809b9c298332509455e /arch/powerpc/kvm | |
parent | a4cd8b23ac5786943202c0174c717956947db43c (diff) |
KVM: PPC: e500: Stop keeping shadow TLB
Instead of a fully separate set of TLB entries, keep just the
pfn and dirty status.
Signed-off-by: Liu Yu <yu.liu@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.c | 317 |
1 files changed, 140 insertions, 177 deletions
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index c09e642ee537..9d1e28d443c4 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c | |||
@@ -41,25 +41,14 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | |||
41 | 41 | ||
42 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | 42 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { |
43 | printk("Guest TLB%d:\n", tlbsel); | 43 | printk("Guest TLB%d:\n", tlbsel); |
44 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { | 44 | for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) { |
45 | tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; | 45 | tlbe = &vcpu_e500->gtlb_arch[tlbsel][i]; |
46 | if (tlbe->mas1 & MAS1_VALID) | 46 | if (tlbe->mas1 & MAS1_VALID) |
47 | printk(" G[%d][%3d] | %08X | %08X | %08X | %08X |\n", | 47 | printk(" G[%d][%3d] | %08X | %08X | %08X | %08X |\n", |
48 | tlbsel, i, tlbe->mas1, tlbe->mas2, | 48 | tlbsel, i, tlbe->mas1, tlbe->mas2, |
49 | tlbe->mas3, tlbe->mas7); | 49 | tlbe->mas3, tlbe->mas7); |
50 | } | 50 | } |
51 | } | 51 | } |
52 | |||
53 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | ||
54 | printk("Shadow TLB%d:\n", tlbsel); | ||
55 | for (i = 0; i < vcpu_e500->shadow_tlb_size[tlbsel]; i++) { | ||
56 | tlbe = &vcpu_e500->shadow_tlb[tlbsel][i]; | ||
57 | if (tlbe->mas1 & MAS1_VALID) | ||
58 | printk(" S[%d][%3d] | %08X | %08X | %08X | %08X |\n", | ||
59 | tlbsel, i, tlbe->mas1, tlbe->mas2, | ||
60 | tlbe->mas3, tlbe->mas7); | ||
61 | } | ||
62 | } | ||
63 | } | 52 | } |
64 | 53 | ||
65 | static inline unsigned int tlb0_get_next_victim( | 54 | static inline unsigned int tlb0_get_next_victim( |
@@ -67,9 +56,9 @@ static inline unsigned int tlb0_get_next_victim( | |||
67 | { | 56 | { |
68 | unsigned int victim; | 57 | unsigned int victim; |
69 | 58 | ||
70 | victim = vcpu_e500->guest_tlb_nv[0]++; | 59 | victim = vcpu_e500->gtlb_nv[0]++; |
71 | if (unlikely(vcpu_e500->guest_tlb_nv[0] >= KVM_E500_TLB0_WAY_NUM)) | 60 | if (unlikely(vcpu_e500->gtlb_nv[0] >= KVM_E500_TLB0_WAY_NUM)) |
72 | vcpu_e500->guest_tlb_nv[0] = 0; | 61 | vcpu_e500->gtlb_nv[0] = 0; |
73 | 62 | ||
74 | return victim; | 63 | return victim; |
75 | } | 64 | } |
@@ -128,10 +117,8 @@ static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0) | |||
128 | } | 117 | } |
129 | 118 | ||
130 | static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | 119 | static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, |
131 | int tlbsel, int esel) | 120 | int tlbsel, int esel, struct tlbe *stlbe) |
132 | { | 121 | { |
133 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
134 | |||
135 | if (tlbsel == 0) { | 122 | if (tlbsel == 0) { |
136 | __write_host_tlbe(stlbe, | 123 | __write_host_tlbe(stlbe, |
137 | MAS0_TLBSEL(0) | | 124 | MAS0_TLBSEL(0) | |
@@ -141,6 +128,8 @@ static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
141 | MAS0_TLBSEL(1) | | 128 | MAS0_TLBSEL(1) | |
142 | MAS0_ESEL(to_htlb1_esel(esel))); | 129 | MAS0_ESEL(to_htlb1_esel(esel))); |
143 | } | 130 | } |
131 | trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, | ||
132 | stlbe->mas3, stlbe->mas7); | ||
144 | } | 133 | } |
145 | 134 | ||
146 | void kvmppc_map_magic(struct kvm_vcpu *vcpu) | 135 | void kvmppc_map_magic(struct kvm_vcpu *vcpu) |
@@ -178,8 +167,8 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
178 | int i; | 167 | int i; |
179 | 168 | ||
180 | /* XXX Replace loop with fancy data structures. */ | 169 | /* XXX Replace loop with fancy data structures. */ |
181 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { | 170 | for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) { |
182 | struct tlbe *tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; | 171 | struct tlbe *tlbe = &vcpu_e500->gtlb_arch[tlbsel][i]; |
183 | unsigned int tid; | 172 | unsigned int tid; |
184 | 173 | ||
185 | if (eaddr < get_tlb_eaddr(tlbe)) | 174 | if (eaddr < get_tlb_eaddr(tlbe)) |
@@ -204,60 +193,33 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
204 | return -1; | 193 | return -1; |
205 | } | 194 | } |
206 | 195 | ||
207 | static void kvmppc_e500_shadow_release(struct kvmppc_vcpu_e500 *vcpu_e500, | 196 | static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv, |
208 | int tlbsel, int esel) | 197 | struct tlbe *gtlbe, |
198 | pfn_t pfn) | ||
209 | { | 199 | { |
210 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | 200 | priv->pfn = pfn; |
211 | unsigned long pfn; | 201 | priv->flags = E500_TLB_VALID; |
212 | |||
213 | pfn = stlbe->mas3 >> PAGE_SHIFT; | ||
214 | pfn |= stlbe->mas7 << (32 - PAGE_SHIFT); | ||
215 | 202 | ||
216 | if (get_tlb_v(stlbe)) { | 203 | if (tlbe_is_writable(gtlbe)) |
217 | if (tlbe_is_writable(stlbe)) | 204 | priv->flags |= E500_TLB_DIRTY; |
218 | kvm_release_pfn_dirty(pfn); | ||
219 | else | ||
220 | kvm_release_pfn_clean(pfn); | ||
221 | } | ||
222 | } | 205 | } |
223 | 206 | ||
224 | static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | 207 | static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv) |
225 | int tlbsel, int esel) | ||
226 | { | 208 | { |
227 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | 209 | if (priv->flags & E500_TLB_VALID) { |
210 | if (priv->flags & E500_TLB_DIRTY) | ||
211 | kvm_release_pfn_dirty(priv->pfn); | ||
212 | else | ||
213 | kvm_release_pfn_clean(priv->pfn); | ||
228 | 214 | ||
229 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); | 215 | priv->flags = 0; |
230 | stlbe->mas1 = 0; | 216 | } |
231 | trace_kvm_stlb_inval(index_of(tlbsel, esel)); | ||
232 | } | 217 | } |
233 | 218 | ||
234 | static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | 219 | static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, |
235 | gva_t eaddr, gva_t eend, u32 tid) | 220 | int esel) |
236 | { | 221 | { |
237 | unsigned int pid = tid & 0xff; | 222 | mtspr(SPRN_MMUCSR0, MMUCSR0_TLB1FI); |
238 | unsigned int i; | ||
239 | |||
240 | /* XXX Replace loop with fancy data structures. */ | ||
241 | for (i = 0; i < vcpu_e500->guest_tlb_size[1]; i++) { | ||
242 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[1][i]; | ||
243 | unsigned int tid; | ||
244 | |||
245 | if (!get_tlb_v(stlbe)) | ||
246 | continue; | ||
247 | |||
248 | if (eend < get_tlb_eaddr(stlbe)) | ||
249 | continue; | ||
250 | |||
251 | if (eaddr > get_tlb_end(stlbe)) | ||
252 | continue; | ||
253 | |||
254 | tid = get_tlb_tid(stlbe); | ||
255 | if (tid && (tid != pid)) | ||
256 | continue; | ||
257 | |||
258 | kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); | ||
259 | write_host_tlbe(vcpu_e500, 1, i); | ||
260 | } | ||
261 | } | 223 | } |
262 | 224 | ||
263 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | 225 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, |
@@ -274,7 +236,7 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | |||
274 | tsized = (vcpu_e500->mas4 >> 7) & 0x1f; | 236 | tsized = (vcpu_e500->mas4 >> 7) & 0x1f; |
275 | 237 | ||
276 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) | 238 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) |
277 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | 239 | | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); |
278 | vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0) | 240 | vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0) |
279 | | MAS1_TID(vcpu_e500->pid[pidsel]) | 241 | | MAS1_TID(vcpu_e500->pid[pidsel]) |
280 | | MAS1_TSIZE(tsized); | 242 | | MAS1_TSIZE(tsized); |
@@ -287,16 +249,35 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | |||
287 | vcpu_e500->mas7 = 0; | 249 | vcpu_e500->mas7 = 0; |
288 | } | 250 | } |
289 | 251 | ||
252 | static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
253 | struct tlbe *gtlbe, int tsize, | ||
254 | struct tlbe_priv *priv, | ||
255 | u64 gvaddr, struct tlbe *stlbe) | ||
256 | { | ||
257 | pfn_t pfn = priv->pfn; | ||
258 | |||
259 | /* Force TS=1 IPROT=0 for all guest mappings. */ | ||
260 | stlbe->mas1 = MAS1_TSIZE(tsize) | ||
261 | | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; | ||
262 | stlbe->mas2 = (gvaddr & MAS2_EPN) | ||
263 | | e500_shadow_mas2_attrib(gtlbe->mas2, | ||
264 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); | ||
265 | stlbe->mas3 = ((pfn << PAGE_SHIFT) & MAS3_RPN) | ||
266 | | e500_shadow_mas3_attrib(gtlbe->mas3, | ||
267 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); | ||
268 | stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN; | ||
269 | } | ||
270 | |||
271 | |||
290 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 272 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
291 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel) | 273 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel, |
274 | struct tlbe *stlbe) | ||
292 | { | 275 | { |
293 | struct kvm_memory_slot *slot; | 276 | struct kvm_memory_slot *slot; |
294 | struct tlbe *stlbe; | ||
295 | unsigned long pfn, hva; | 277 | unsigned long pfn, hva; |
296 | int pfnmap = 0; | 278 | int pfnmap = 0; |
297 | int tsize = BOOK3E_PAGESZ_4K; | 279 | int tsize = BOOK3E_PAGESZ_4K; |
298 | 280 | struct tlbe_priv *priv; | |
299 | stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
300 | 281 | ||
301 | /* | 282 | /* |
302 | * Translate guest physical to true physical, acquiring | 283 | * Translate guest physical to true physical, acquiring |
@@ -392,35 +373,25 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
392 | } | 373 | } |
393 | } | 374 | } |
394 | 375 | ||
395 | /* Drop reference to old page. */ | 376 | /* Drop old priv and setup new one. */ |
396 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); | 377 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; |
397 | 378 | kvmppc_e500_priv_release(priv); | |
398 | /* Force TS=1 IPROT=0 for all guest mappings. */ | 379 | kvmppc_e500_priv_setup(priv, gtlbe, pfn); |
399 | stlbe->mas1 = MAS1_TSIZE(tsize) | ||
400 | | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; | ||
401 | stlbe->mas2 = (gvaddr & MAS2_EPN) | ||
402 | | e500_shadow_mas2_attrib(gtlbe->mas2, | ||
403 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); | ||
404 | stlbe->mas3 = ((pfn << PAGE_SHIFT) & MAS3_RPN) | ||
405 | | e500_shadow_mas3_attrib(gtlbe->mas3, | ||
406 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); | ||
407 | stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN; | ||
408 | 380 | ||
409 | trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, | 381 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe); |
410 | stlbe->mas3, stlbe->mas7); | ||
411 | } | 382 | } |
412 | 383 | ||
413 | /* XXX only map the one-one case, for now use TLB0 */ | 384 | /* XXX only map the one-one case, for now use TLB0 */ |
414 | static int kvmppc_e500_stlbe_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 385 | static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
415 | int tlbsel, int esel) | 386 | int esel, struct tlbe *stlbe) |
416 | { | 387 | { |
417 | struct tlbe *gtlbe; | 388 | struct tlbe *gtlbe; |
418 | 389 | ||
419 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | 390 | gtlbe = &vcpu_e500->gtlb_arch[0][esel]; |
420 | 391 | ||
421 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), | 392 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), |
422 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, | 393 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, |
423 | gtlbe, tlbsel, esel); | 394 | gtlbe, 0, esel, stlbe); |
424 | 395 | ||
425 | return esel; | 396 | return esel; |
426 | } | 397 | } |
@@ -429,16 +400,16 @@ static int kvmppc_e500_stlbe_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
429 | * the shadow TLB. */ | 400 | * the shadow TLB. */ |
430 | /* XXX for both one-one and one-to-many , for now use TLB1 */ | 401 | /* XXX for both one-one and one-to-many , for now use TLB1 */ |
431 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 402 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
432 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe) | 403 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe) |
433 | { | 404 | { |
434 | unsigned int victim; | 405 | unsigned int victim; |
435 | 406 | ||
436 | victim = vcpu_e500->guest_tlb_nv[1]++; | 407 | victim = vcpu_e500->gtlb_nv[1]++; |
437 | 408 | ||
438 | if (unlikely(vcpu_e500->guest_tlb_nv[1] >= tlb1_max_shadow_size())) | 409 | if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size())) |
439 | vcpu_e500->guest_tlb_nv[1] = 0; | 410 | vcpu_e500->gtlb_nv[1] = 0; |
440 | 411 | ||
441 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim); | 412 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe); |
442 | 413 | ||
443 | return victim; | 414 | return victim; |
444 | } | 415 | } |
@@ -449,33 +420,19 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
449 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | 420 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) |
450 | { | 421 | { |
451 | if (usermode) { | 422 | if (usermode) { |
452 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
453 | int i; | ||
454 | |||
455 | /* XXX Replace loop with fancy data structures. */ | ||
456 | for (i = 0; i < tlb1_max_shadow_size(); i++) | ||
457 | kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); | ||
458 | |||
459 | _tlbil_all(); | 423 | _tlbil_all(); |
460 | } | 424 | } |
461 | } | 425 | } |
462 | 426 | ||
463 | static int kvmppc_e500_gtlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | 427 | static inline int kvmppc_e500_gtlbe_invalidate( |
464 | int tlbsel, int esel) | 428 | struct kvmppc_vcpu_e500 *vcpu_e500, |
429 | int tlbsel, int esel) | ||
465 | { | 430 | { |
466 | struct tlbe *gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | 431 | struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
467 | 432 | ||
468 | if (unlikely(get_tlb_iprot(gtlbe))) | 433 | if (unlikely(get_tlb_iprot(gtlbe))) |
469 | return -1; | 434 | return -1; |
470 | 435 | ||
471 | if (tlbsel == 1) { | ||
472 | kvmppc_e500_tlb1_invalidate(vcpu_e500, get_tlb_eaddr(gtlbe), | ||
473 | get_tlb_end(gtlbe), | ||
474 | get_tlb_tid(gtlbe)); | ||
475 | } else { | ||
476 | kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); | ||
477 | } | ||
478 | |||
479 | gtlbe->mas1 = 0; | 436 | gtlbe->mas1 = 0; |
480 | 437 | ||
481 | return 0; | 438 | return 0; |
@@ -486,10 +443,10 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value) | |||
486 | int esel; | 443 | int esel; |
487 | 444 | ||
488 | if (value & MMUCSR0_TLB0FI) | 445 | if (value & MMUCSR0_TLB0FI) |
489 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[0]; esel++) | 446 | for (esel = 0; esel < vcpu_e500->gtlb_size[0]; esel++) |
490 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel); | 447 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel); |
491 | if (value & MMUCSR0_TLB1FI) | 448 | if (value & MMUCSR0_TLB1FI) |
492 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[1]; esel++) | 449 | for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++) |
493 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); | 450 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); |
494 | 451 | ||
495 | _tlbil_all(); | 452 | _tlbil_all(); |
@@ -513,7 +470,7 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb) | |||
513 | 470 | ||
514 | if (ia) { | 471 | if (ia) { |
515 | /* invalidate all entries */ | 472 | /* invalidate all entries */ |
516 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[tlbsel]; esel++) | 473 | for (esel = 0; esel < vcpu_e500->gtlb_size[tlbsel]; esel++) |
517 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); | 474 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); |
518 | } else { | 475 | } else { |
519 | ea &= 0xfffff000; | 476 | ea &= 0xfffff000; |
@@ -537,9 +494,9 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu) | |||
537 | tlbsel = get_tlb_tlbsel(vcpu_e500); | 494 | tlbsel = get_tlb_tlbsel(vcpu_e500); |
538 | esel = get_tlb_esel(vcpu_e500, tlbsel); | 495 | esel = get_tlb_esel(vcpu_e500, tlbsel); |
539 | 496 | ||
540 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | 497 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
541 | vcpu_e500->mas0 &= ~MAS0_NV(~0); | 498 | vcpu_e500->mas0 &= ~MAS0_NV(~0); |
542 | vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | 499 | vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); |
543 | vcpu_e500->mas1 = gtlbe->mas1; | 500 | vcpu_e500->mas1 = gtlbe->mas1; |
544 | vcpu_e500->mas2 = gtlbe->mas2; | 501 | vcpu_e500->mas2 = gtlbe->mas2; |
545 | vcpu_e500->mas3 = gtlbe->mas3; | 502 | vcpu_e500->mas3 = gtlbe->mas3; |
@@ -562,14 +519,14 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) | |||
562 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | 519 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { |
563 | esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as); | 520 | esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as); |
564 | if (esel >= 0) { | 521 | if (esel >= 0) { |
565 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | 522 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
566 | break; | 523 | break; |
567 | } | 524 | } |
568 | } | 525 | } |
569 | 526 | ||
570 | if (gtlbe) { | 527 | if (gtlbe) { |
571 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel) | 528 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel) |
572 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | 529 | | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); |
573 | vcpu_e500->mas1 = gtlbe->mas1; | 530 | vcpu_e500->mas1 = gtlbe->mas1; |
574 | vcpu_e500->mas2 = gtlbe->mas2; | 531 | vcpu_e500->mas2 = gtlbe->mas2; |
575 | vcpu_e500->mas3 = gtlbe->mas3; | 532 | vcpu_e500->mas3 = gtlbe->mas3; |
@@ -582,7 +539,7 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) | |||
582 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; | 539 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; |
583 | 540 | ||
584 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) | 541 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) |
585 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | 542 | | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); |
586 | vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0) | 543 | vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0) |
587 | | (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0)) | 544 | | (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0)) |
588 | | (vcpu_e500->mas4 & MAS4_TSIZED(~0)); | 545 | | (vcpu_e500->mas4 & MAS4_TSIZED(~0)); |
@@ -599,23 +556,16 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) | |||
599 | int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | 556 | int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) |
600 | { | 557 | { |
601 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 558 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
602 | u64 eaddr; | ||
603 | u64 raddr; | ||
604 | u32 tid; | ||
605 | struct tlbe *gtlbe; | 559 | struct tlbe *gtlbe; |
606 | int tlbsel, esel, stlbsel, sesel; | 560 | int tlbsel, esel; |
607 | 561 | ||
608 | tlbsel = get_tlb_tlbsel(vcpu_e500); | 562 | tlbsel = get_tlb_tlbsel(vcpu_e500); |
609 | esel = get_tlb_esel(vcpu_e500, tlbsel); | 563 | esel = get_tlb_esel(vcpu_e500, tlbsel); |
610 | 564 | ||
611 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | 565 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
612 | 566 | ||
613 | if (get_tlb_v(gtlbe) && tlbsel == 1) { | 567 | if (get_tlb_v(gtlbe) && tlbsel == 1) |
614 | eaddr = get_tlb_eaddr(gtlbe); | 568 | kvmppc_e500_tlb1_invalidate(vcpu_e500, esel); |
615 | tid = get_tlb_tid(gtlbe); | ||
616 | kvmppc_e500_tlb1_invalidate(vcpu_e500, eaddr, | ||
617 | get_tlb_end(gtlbe), tid); | ||
618 | } | ||
619 | 569 | ||
620 | gtlbe->mas1 = vcpu_e500->mas1; | 570 | gtlbe->mas1 = vcpu_e500->mas1; |
621 | gtlbe->mas2 = vcpu_e500->mas2; | 571 | gtlbe->mas2 = vcpu_e500->mas2; |
@@ -627,6 +577,11 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
627 | 577 | ||
628 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ | 578 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ |
629 | if (tlbe_is_host_safe(vcpu, gtlbe)) { | 579 | if (tlbe_is_host_safe(vcpu, gtlbe)) { |
580 | struct tlbe stlbe; | ||
581 | int stlbsel, sesel; | ||
582 | u64 eaddr; | ||
583 | u64 raddr; | ||
584 | |||
630 | switch (tlbsel) { | 585 | switch (tlbsel) { |
631 | case 0: | 586 | case 0: |
632 | /* TLB0 */ | 587 | /* TLB0 */ |
@@ -634,7 +589,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
634 | gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K); | 589 | gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K); |
635 | 590 | ||
636 | stlbsel = 0; | 591 | stlbsel = 0; |
637 | sesel = kvmppc_e500_stlbe_map(vcpu_e500, 0, esel); | 592 | sesel = kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); |
638 | 593 | ||
639 | break; | 594 | break; |
640 | 595 | ||
@@ -649,13 +604,13 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
649 | * are mapped on the fly. */ | 604 | * are mapped on the fly. */ |
650 | stlbsel = 1; | 605 | stlbsel = 1; |
651 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, | 606 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, |
652 | raddr >> PAGE_SHIFT, gtlbe); | 607 | raddr >> PAGE_SHIFT, gtlbe, &stlbe); |
653 | break; | 608 | break; |
654 | 609 | ||
655 | default: | 610 | default: |
656 | BUG(); | 611 | BUG(); |
657 | } | 612 | } |
658 | write_host_tlbe(vcpu_e500, stlbsel, sesel); | 613 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); |
659 | } | 614 | } |
660 | 615 | ||
661 | kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS); | 616 | kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS); |
@@ -695,7 +650,7 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index, | |||
695 | { | 650 | { |
696 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 651 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
697 | struct tlbe *gtlbe = | 652 | struct tlbe *gtlbe = |
698 | &vcpu_e500->guest_tlb[tlbsel_of(index)][esel_of(index)]; | 653 | &vcpu_e500->gtlb_arch[tlbsel_of(index)][esel_of(index)]; |
699 | u64 pgmask = get_tlb_bytes(gtlbe) - 1; | 654 | u64 pgmask = get_tlb_bytes(gtlbe) - 1; |
700 | 655 | ||
701 | return get_tlb_raddr(gtlbe) | (eaddr & pgmask); | 656 | return get_tlb_raddr(gtlbe) | (eaddr & pgmask); |
@@ -703,38 +658,36 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index, | |||
703 | 658 | ||
704 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | 659 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) |
705 | { | 660 | { |
706 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
707 | int tlbsel, i; | ||
708 | |||
709 | for (tlbsel = 0; tlbsel < 2; tlbsel++) | ||
710 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) | ||
711 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, i); | ||
712 | |||
713 | /* discard all guest mapping */ | ||
714 | _tlbil_all(); | ||
715 | } | 661 | } |
716 | 662 | ||
717 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | 663 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, |
718 | unsigned int index) | 664 | unsigned int index) |
719 | { | 665 | { |
720 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 666 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
667 | struct tlbe_priv *priv; | ||
668 | struct tlbe *gtlbe, stlbe; | ||
721 | int tlbsel = tlbsel_of(index); | 669 | int tlbsel = tlbsel_of(index); |
722 | int esel = esel_of(index); | 670 | int esel = esel_of(index); |
723 | int stlbsel, sesel; | 671 | int stlbsel, sesel; |
724 | 672 | ||
673 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | ||
674 | |||
725 | switch (tlbsel) { | 675 | switch (tlbsel) { |
726 | case 0: | 676 | case 0: |
727 | stlbsel = 0; | 677 | stlbsel = 0; |
728 | sesel = esel; | 678 | sesel = esel; |
679 | priv = &vcpu_e500->gtlb_priv[stlbsel][sesel]; | ||
680 | |||
681 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K, | ||
682 | priv, eaddr, &stlbe); | ||
729 | break; | 683 | break; |
730 | 684 | ||
731 | case 1: { | 685 | case 1: { |
732 | gfn_t gfn = gpaddr >> PAGE_SHIFT; | 686 | gfn_t gfn = gpaddr >> PAGE_SHIFT; |
733 | struct tlbe *gtlbe | ||
734 | = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
735 | 687 | ||
736 | stlbsel = 1; | 688 | stlbsel = 1; |
737 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, gtlbe); | 689 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, |
690 | gtlbe, &stlbe); | ||
738 | break; | 691 | break; |
739 | } | 692 | } |
740 | 693 | ||
@@ -742,7 +695,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
742 | BUG(); | 695 | BUG(); |
743 | break; | 696 | break; |
744 | } | 697 | } |
745 | write_host_tlbe(vcpu_e500, stlbsel, sesel); | 698 | |
699 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); | ||
746 | } | 700 | } |
747 | 701 | ||
748 | int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, | 702 | int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, |
@@ -773,14 +727,14 @@ void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
773 | struct tlbe *tlbe; | 727 | struct tlbe *tlbe; |
774 | 728 | ||
775 | /* Insert large initial mapping for guest. */ | 729 | /* Insert large initial mapping for guest. */ |
776 | tlbe = &vcpu_e500->guest_tlb[1][0]; | 730 | tlbe = &vcpu_e500->gtlb_arch[1][0]; |
777 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M); | 731 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M); |
778 | tlbe->mas2 = 0; | 732 | tlbe->mas2 = 0; |
779 | tlbe->mas3 = E500_TLB_SUPER_PERM_MASK; | 733 | tlbe->mas3 = E500_TLB_SUPER_PERM_MASK; |
780 | tlbe->mas7 = 0; | 734 | tlbe->mas7 = 0; |
781 | 735 | ||
782 | /* 4K map for serial output. Used by kernel wrapper. */ | 736 | /* 4K map for serial output. Used by kernel wrapper. */ |
783 | tlbe = &vcpu_e500->guest_tlb[1][1]; | 737 | tlbe = &vcpu_e500->gtlb_arch[1][1]; |
784 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K); | 738 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K); |
785 | tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G; | 739 | tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G; |
786 | tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK; | 740 | tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK; |
@@ -791,52 +745,61 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
791 | { | 745 | { |
792 | tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF; | 746 | tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF; |
793 | 747 | ||
794 | vcpu_e500->guest_tlb_size[0] = KVM_E500_TLB0_SIZE; | 748 | vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE; |
795 | vcpu_e500->guest_tlb[0] = | 749 | vcpu_e500->gtlb_arch[0] = |
796 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | 750 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); |
797 | if (vcpu_e500->guest_tlb[0] == NULL) | 751 | if (vcpu_e500->gtlb_arch[0] == NULL) |
798 | goto err_out; | 752 | goto err_out; |
799 | 753 | ||
800 | vcpu_e500->shadow_tlb_size[0] = KVM_E500_TLB0_SIZE; | 754 | vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE; |
801 | vcpu_e500->shadow_tlb[0] = | 755 | vcpu_e500->gtlb_arch[1] = |
802 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | ||
803 | if (vcpu_e500->shadow_tlb[0] == NULL) | ||
804 | goto err_out_guest0; | ||
805 | |||
806 | vcpu_e500->guest_tlb_size[1] = KVM_E500_TLB1_SIZE; | ||
807 | vcpu_e500->guest_tlb[1] = | ||
808 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); | 756 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); |
809 | if (vcpu_e500->guest_tlb[1] == NULL) | 757 | if (vcpu_e500->gtlb_arch[1] == NULL) |
810 | goto err_out_shadow0; | 758 | goto err_out_guest0; |
811 | 759 | ||
812 | vcpu_e500->shadow_tlb_size[1] = tlb1_entry_num; | 760 | vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *) |
813 | vcpu_e500->shadow_tlb[1] = | 761 | kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL); |
814 | kzalloc(sizeof(struct tlbe) * tlb1_entry_num, GFP_KERNEL); | 762 | if (vcpu_e500->gtlb_priv[0] == NULL) |
815 | if (vcpu_e500->shadow_tlb[1] == NULL) | ||
816 | goto err_out_guest1; | 763 | goto err_out_guest1; |
764 | vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *) | ||
765 | kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL); | ||
766 | |||
767 | if (vcpu_e500->gtlb_priv[1] == NULL) | ||
768 | goto err_out_priv0; | ||
817 | 769 | ||
818 | /* Init TLB configuration register */ | 770 | /* Init TLB configuration register */ |
819 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; | 771 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; |
820 | vcpu_e500->tlb0cfg |= vcpu_e500->guest_tlb_size[0]; | 772 | vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0]; |
821 | vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) & ~0xfffUL; | 773 | vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) & ~0xfffUL; |
822 | vcpu_e500->tlb1cfg |= vcpu_e500->guest_tlb_size[1]; | 774 | vcpu_e500->tlb1cfg |= vcpu_e500->gtlb_size[1]; |
823 | 775 | ||
824 | return 0; | 776 | return 0; |
825 | 777 | ||
778 | err_out_priv0: | ||
779 | kfree(vcpu_e500->gtlb_priv[0]); | ||
826 | err_out_guest1: | 780 | err_out_guest1: |
827 | kfree(vcpu_e500->guest_tlb[1]); | 781 | kfree(vcpu_e500->gtlb_arch[1]); |
828 | err_out_shadow0: | ||
829 | kfree(vcpu_e500->shadow_tlb[0]); | ||
830 | err_out_guest0: | 782 | err_out_guest0: |
831 | kfree(vcpu_e500->guest_tlb[0]); | 783 | kfree(vcpu_e500->gtlb_arch[0]); |
832 | err_out: | 784 | err_out: |
833 | return -1; | 785 | return -1; |
834 | } | 786 | } |
835 | 787 | ||
836 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | 788 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) |
837 | { | 789 | { |
838 | kfree(vcpu_e500->shadow_tlb[1]); | 790 | int stlbsel, i; |
839 | kfree(vcpu_e500->guest_tlb[1]); | 791 | |
840 | kfree(vcpu_e500->shadow_tlb[0]); | 792 | /* release all privs */ |
841 | kfree(vcpu_e500->guest_tlb[0]); | 793 | for (stlbsel = 0; stlbsel < 2; stlbsel++) |
794 | for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) { | ||
795 | struct tlbe_priv *priv = | ||
796 | &vcpu_e500->gtlb_priv[stlbsel][i]; | ||
797 | kvmppc_e500_priv_release(priv); | ||
798 | } | ||
799 | |||
800 | /* discard all guest mapping */ | ||
801 | _tlbil_all(); | ||
802 | |||
803 | kfree(vcpu_e500->gtlb_arch[1]); | ||
804 | kfree(vcpu_e500->gtlb_arch[0]); | ||
842 | } | 805 | } |