diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_32_mmu.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_32_mmu.c | 111 |
1 files changed, 67 insertions, 44 deletions
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c index 3292d76101d2..c8cefdd15fd8 100644 --- a/arch/powerpc/kvm/book3s_32_mmu.c +++ b/arch/powerpc/kvm/book3s_32_mmu.c | |||
@@ -58,14 +58,39 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu) | |||
58 | #endif | 58 | #endif |
59 | } | 59 | } |
60 | 60 | ||
61 | static inline u32 sr_vsid(u32 sr_raw) | ||
62 | { | ||
63 | return sr_raw & 0x0fffffff; | ||
64 | } | ||
65 | |||
66 | static inline bool sr_valid(u32 sr_raw) | ||
67 | { | ||
68 | return (sr_raw & 0x80000000) ? false : true; | ||
69 | } | ||
70 | |||
71 | static inline bool sr_ks(u32 sr_raw) | ||
72 | { | ||
73 | return (sr_raw & 0x40000000) ? true: false; | ||
74 | } | ||
75 | |||
76 | static inline bool sr_kp(u32 sr_raw) | ||
77 | { | ||
78 | return (sr_raw & 0x20000000) ? true: false; | ||
79 | } | ||
80 | |||
81 | static inline bool sr_nx(u32 sr_raw) | ||
82 | { | ||
83 | return (sr_raw & 0x10000000) ? true: false; | ||
84 | } | ||
85 | |||
61 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | 86 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, |
62 | struct kvmppc_pte *pte, bool data); | 87 | struct kvmppc_pte *pte, bool data); |
63 | static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | 88 | static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, |
64 | u64 *vsid); | 89 | u64 *vsid); |
65 | 90 | ||
66 | static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) | 91 | static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr) |
67 | { | 92 | { |
68 | return &vcpu_book3s->sr[(eaddr >> 28) & 0xf]; | 93 | return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf]; |
69 | } | 94 | } |
70 | 95 | ||
71 | static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | 96 | static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, |
@@ -87,7 +112,7 @@ static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) | |||
87 | } | 112 | } |
88 | 113 | ||
89 | static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, | 114 | static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, |
90 | struct kvmppc_sr *sre, gva_t eaddr, | 115 | u32 sre, gva_t eaddr, |
91 | bool primary) | 116 | bool primary) |
92 | { | 117 | { |
93 | u32 page, hash, pteg, htabmask; | 118 | u32 page, hash, pteg, htabmask; |
@@ -96,7 +121,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 | |||
96 | page = (eaddr & 0x0FFFFFFF) >> 12; | 121 | page = (eaddr & 0x0FFFFFFF) >> 12; |
97 | htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; | 122 | htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; |
98 | 123 | ||
99 | hash = ((sre->vsid ^ page) << 6); | 124 | hash = ((sr_vsid(sre) ^ page) << 6); |
100 | if (!primary) | 125 | if (!primary) |
101 | hash = ~hash; | 126 | hash = ~hash; |
102 | hash &= htabmask; | 127 | hash &= htabmask; |
@@ -104,8 +129,8 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 | |||
104 | pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; | 129 | pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; |
105 | 130 | ||
106 | dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", | 131 | dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", |
107 | vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg, | 132 | kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg, |
108 | sre->vsid); | 133 | sr_vsid(sre)); |
109 | 134 | ||
110 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); | 135 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); |
111 | if (kvm_is_error_hva(r)) | 136 | if (kvm_is_error_hva(r)) |
@@ -113,10 +138,9 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 | |||
113 | return r | (pteg & ~PAGE_MASK); | 138 | return r | (pteg & ~PAGE_MASK); |
114 | } | 139 | } |
115 | 140 | ||
116 | static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr, | 141 | static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary) |
117 | bool primary) | ||
118 | { | 142 | { |
119 | return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) | | 143 | return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) | |
120 | (primary ? 0 : 0x40) | 0x80000000; | 144 | (primary ? 0 : 0x40) | 0x80000000; |
121 | } | 145 | } |
122 | 146 | ||
@@ -133,7 +157,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
133 | else | 157 | else |
134 | bat = &vcpu_book3s->ibat[i]; | 158 | bat = &vcpu_book3s->ibat[i]; |
135 | 159 | ||
136 | if (vcpu->arch.msr & MSR_PR) { | 160 | if (vcpu->arch.shared->msr & MSR_PR) { |
137 | if (!bat->vp) | 161 | if (!bat->vp) |
138 | continue; | 162 | continue; |
139 | } else { | 163 | } else { |
@@ -180,17 +204,17 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
180 | bool primary) | 204 | bool primary) |
181 | { | 205 | { |
182 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | 206 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); |
183 | struct kvmppc_sr *sre; | 207 | u32 sre; |
184 | hva_t ptegp; | 208 | hva_t ptegp; |
185 | u32 pteg[16]; | 209 | u32 pteg[16]; |
186 | u32 ptem = 0; | 210 | u32 ptem = 0; |
187 | int i; | 211 | int i; |
188 | int found = 0; | 212 | int found = 0; |
189 | 213 | ||
190 | sre = find_sr(vcpu_book3s, eaddr); | 214 | sre = find_sr(vcpu, eaddr); |
191 | 215 | ||
192 | dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, | 216 | dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, |
193 | sre->vsid, sre->raw); | 217 | sr_vsid(sre), sre); |
194 | 218 | ||
195 | pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); | 219 | pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); |
196 | 220 | ||
@@ -214,8 +238,8 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
214 | pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); | 238 | pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); |
215 | pp = pteg[i+1] & 3; | 239 | pp = pteg[i+1] & 3; |
216 | 240 | ||
217 | if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) || | 241 | if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) || |
218 | (sre->Ks && !(vcpu->arch.msr & MSR_PR))) | 242 | (sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR))) |
219 | pp |= 4; | 243 | pp |= 4; |
220 | 244 | ||
221 | pte->may_write = false; | 245 | pte->may_write = false; |
@@ -269,7 +293,7 @@ no_page_found: | |||
269 | dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", | 293 | dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", |
270 | to_book3s(vcpu)->sdr1, ptegp); | 294 | to_book3s(vcpu)->sdr1, ptegp); |
271 | for (i=0; i<16; i+=2) { | 295 | for (i=0; i<16; i+=2) { |
272 | dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n", | 296 | dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n", |
273 | i, pteg[i], pteg[i+1], ptem); | 297 | i, pteg[i], pteg[i+1], ptem); |
274 | } | 298 | } |
275 | } | 299 | } |
@@ -281,8 +305,24 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
281 | struct kvmppc_pte *pte, bool data) | 305 | struct kvmppc_pte *pte, bool data) |
282 | { | 306 | { |
283 | int r; | 307 | int r; |
308 | ulong mp_ea = vcpu->arch.magic_page_ea; | ||
284 | 309 | ||
285 | pte->eaddr = eaddr; | 310 | pte->eaddr = eaddr; |
311 | |||
312 | /* Magic page override */ | ||
313 | if (unlikely(mp_ea) && | ||
314 | unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) && | ||
315 | !(vcpu->arch.shared->msr & MSR_PR)) { | ||
316 | pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); | ||
317 | pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff); | ||
318 | pte->raddr &= KVM_PAM; | ||
319 | pte->may_execute = true; | ||
320 | pte->may_read = true; | ||
321 | pte->may_write = true; | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
286 | r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); | 326 | r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); |
287 | if (r < 0) | 327 | if (r < 0) |
288 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); | 328 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); |
@@ -295,30 +335,13 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
295 | 335 | ||
296 | static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) | 336 | static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) |
297 | { | 337 | { |
298 | return to_book3s(vcpu)->sr[srnum].raw; | 338 | return vcpu->arch.shared->sr[srnum]; |
299 | } | 339 | } |
300 | 340 | ||
301 | static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | 341 | static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, |
302 | ulong value) | 342 | ulong value) |
303 | { | 343 | { |
304 | struct kvmppc_sr *sre; | 344 | vcpu->arch.shared->sr[srnum] = value; |
305 | |||
306 | sre = &to_book3s(vcpu)->sr[srnum]; | ||
307 | |||
308 | /* Flush any left-over shadows from the previous SR */ | ||
309 | |||
310 | /* XXX Not necessary? */ | ||
311 | /* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */ | ||
312 | |||
313 | /* And then put in the new SR */ | ||
314 | sre->raw = value; | ||
315 | sre->vsid = (value & 0x0fffffff); | ||
316 | sre->valid = (value & 0x80000000) ? false : true; | ||
317 | sre->Ks = (value & 0x40000000) ? true : false; | ||
318 | sre->Kp = (value & 0x20000000) ? true : false; | ||
319 | sre->nx = (value & 0x10000000) ? true : false; | ||
320 | |||
321 | /* Map the new segment */ | ||
322 | kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); | 345 | kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); |
323 | } | 346 | } |
324 | 347 | ||
@@ -331,19 +354,19 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | |||
331 | u64 *vsid) | 354 | u64 *vsid) |
332 | { | 355 | { |
333 | ulong ea = esid << SID_SHIFT; | 356 | ulong ea = esid << SID_SHIFT; |
334 | struct kvmppc_sr *sr; | 357 | u32 sr; |
335 | u64 gvsid = esid; | 358 | u64 gvsid = esid; |
336 | 359 | ||
337 | if (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | 360 | if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { |
338 | sr = find_sr(to_book3s(vcpu), ea); | 361 | sr = find_sr(vcpu, ea); |
339 | if (sr->valid) | 362 | if (sr_valid(sr)) |
340 | gvsid = sr->vsid; | 363 | gvsid = sr_vsid(sr); |
341 | } | 364 | } |
342 | 365 | ||
343 | /* In case we only have one of MSR_IR or MSR_DR set, let's put | 366 | /* In case we only have one of MSR_IR or MSR_DR set, let's put |
344 | that in the real-mode context (and hope RM doesn't access | 367 | that in the real-mode context (and hope RM doesn't access |
345 | high memory) */ | 368 | high memory) */ |
346 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | 369 | switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { |
347 | case 0: | 370 | case 0: |
348 | *vsid = VSID_REAL | esid; | 371 | *vsid = VSID_REAL | esid; |
349 | break; | 372 | break; |
@@ -354,8 +377,8 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | |||
354 | *vsid = VSID_REAL_DR | gvsid; | 377 | *vsid = VSID_REAL_DR | gvsid; |
355 | break; | 378 | break; |
356 | case MSR_DR|MSR_IR: | 379 | case MSR_DR|MSR_IR: |
357 | if (sr->valid) | 380 | if (sr_valid(sr)) |
358 | *vsid = sr->vsid; | 381 | *vsid = sr_vsid(sr); |
359 | else | 382 | else |
360 | *vsid = VSID_BAT | gvsid; | 383 | *vsid = VSID_BAT | gvsid; |
361 | break; | 384 | break; |
@@ -363,7 +386,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | |||
363 | BUG(); | 386 | BUG(); |
364 | } | 387 | } |
365 | 388 | ||
366 | if (vcpu->arch.msr & MSR_PR) | 389 | if (vcpu->arch.shared->msr & MSR_PR) |
367 | *vsid |= VSID_PR; | 390 | *vsid |= VSID_PR; |
368 | 391 | ||
369 | return 0; | 392 | return 0; |