diff options
-rw-r--r-- | arch/powerpc/kvm/book3s_64_mmu.c | 150 |
1 files changed, 72 insertions, 78 deletions
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c index 739bfbadb85e..7e345e00661a 100644 --- a/arch/powerpc/kvm/book3s_64_mmu.c +++ b/arch/powerpc/kvm/book3s_64_mmu.c | |||
@@ -182,10 +182,13 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
182 | hva_t ptegp; | 182 | hva_t ptegp; |
183 | u64 pteg[16]; | 183 | u64 pteg[16]; |
184 | u64 avpn = 0; | 184 | u64 avpn = 0; |
185 | u64 v, r; | ||
186 | u64 v_val, v_mask; | ||
187 | u64 eaddr_mask; | ||
185 | int i; | 188 | int i; |
186 | u8 key = 0; | 189 | u8 pp, key = 0; |
187 | bool found = false; | 190 | bool found = false; |
188 | int second = 0; | 191 | bool second = false; |
189 | ulong mp_ea = vcpu->arch.magic_page_ea; | 192 | ulong mp_ea = vcpu->arch.magic_page_ea; |
190 | 193 | ||
191 | /* Magic page override */ | 194 | /* Magic page override */ |
@@ -208,8 +211,16 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | |||
208 | goto no_seg_found; | 211 | goto no_seg_found; |
209 | 212 | ||
210 | avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr); | 213 | avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr); |
214 | v_val = avpn & HPTE_V_AVPN; | ||
215 | |||
211 | if (slbe->tb) | 216 | if (slbe->tb) |
212 | avpn |= SLB_VSID_B_1T; | 217 | v_val |= SLB_VSID_B_1T; |
218 | if (slbe->large) | ||
219 | v_val |= HPTE_V_LARGE; | ||
220 | v_val |= HPTE_V_VALID; | ||
221 | |||
222 | v_mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_LARGE | HPTE_V_VALID | | ||
223 | HPTE_V_SECONDARY; | ||
213 | 224 | ||
214 | do_second: | 225 | do_second: |
215 | ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second); | 226 | ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second); |
@@ -227,91 +238,74 @@ do_second: | |||
227 | key = 4; | 238 | key = 4; |
228 | 239 | ||
229 | for (i=0; i<16; i+=2) { | 240 | for (i=0; i<16; i+=2) { |
230 | u64 v = pteg[i]; | 241 | /* Check all relevant fields of 1st dword */ |
231 | u64 r = pteg[i+1]; | 242 | if ((pteg[i] & v_mask) == v_val) { |
232 | |||
233 | /* Valid check */ | ||
234 | if (!(v & HPTE_V_VALID)) | ||
235 | continue; | ||
236 | /* Hash check */ | ||
237 | if ((v & HPTE_V_SECONDARY) != second) | ||
238 | continue; | ||
239 | |||
240 | /* AVPN compare */ | ||
241 | if (HPTE_V_COMPARE(avpn, v)) { | ||
242 | u8 pp = (r & HPTE_R_PP) | key; | ||
243 | int eaddr_mask = 0xFFF; | ||
244 | |||
245 | gpte->eaddr = eaddr; | ||
246 | gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, | ||
247 | eaddr, | ||
248 | data); | ||
249 | if (slbe->large) | ||
250 | eaddr_mask = 0xFFFFFF; | ||
251 | gpte->raddr = (r & HPTE_R_RPN) | (eaddr & eaddr_mask); | ||
252 | gpte->may_execute = ((r & HPTE_R_N) ? false : true); | ||
253 | gpte->may_read = false; | ||
254 | gpte->may_write = false; | ||
255 | |||
256 | switch (pp) { | ||
257 | case 0: | ||
258 | case 1: | ||
259 | case 2: | ||
260 | case 6: | ||
261 | gpte->may_write = true; | ||
262 | /* fall through */ | ||
263 | case 3: | ||
264 | case 5: | ||
265 | case 7: | ||
266 | gpte->may_read = true; | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx " | ||
271 | "-> 0x%lx\n", | ||
272 | eaddr, avpn, gpte->vpage, gpte->raddr); | ||
273 | found = true; | 243 | found = true; |
274 | break; | 244 | break; |
275 | } | 245 | } |
276 | } | 246 | } |
277 | 247 | ||
278 | /* Update PTE R and C bits, so the guest's swapper knows we used the | 248 | if (!found) { |
279 | * page */ | 249 | if (second) |
280 | if (found) { | 250 | goto no_page_found; |
281 | u32 oldr = pteg[i+1]; | 251 | v_val |= HPTE_V_SECONDARY; |
252 | second = true; | ||
253 | goto do_second; | ||
254 | } | ||
282 | 255 | ||
283 | if (gpte->may_read) { | 256 | v = pteg[i]; |
284 | /* Set the accessed flag */ | 257 | r = pteg[i+1]; |
285 | pteg[i+1] |= HPTE_R_R; | 258 | pp = (r & HPTE_R_PP) | key; |
286 | } | 259 | eaddr_mask = 0xFFF; |
287 | if (gpte->may_write) { | 260 | |
288 | /* Set the dirty flag */ | 261 | gpte->eaddr = eaddr; |
289 | pteg[i+1] |= HPTE_R_C; | 262 | gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data); |
290 | } else { | 263 | if (slbe->large) |
291 | dprintk("KVM: Mapping read-only page!\n"); | 264 | eaddr_mask = 0xFFFFFF; |
292 | } | 265 | gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask); |
266 | gpte->may_execute = ((r & HPTE_R_N) ? false : true); | ||
267 | gpte->may_read = false; | ||
268 | gpte->may_write = false; | ||
269 | |||
270 | switch (pp) { | ||
271 | case 0: | ||
272 | case 1: | ||
273 | case 2: | ||
274 | case 6: | ||
275 | gpte->may_write = true; | ||
276 | /* fall through */ | ||
277 | case 3: | ||
278 | case 5: | ||
279 | case 7: | ||
280 | gpte->may_read = true; | ||
281 | break; | ||
282 | } | ||
293 | 283 | ||
294 | /* Write back into the PTEG */ | 284 | dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx " |
295 | if (pteg[i+1] != oldr) | 285 | "-> 0x%lx\n", |
296 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); | 286 | eaddr, avpn, gpte->vpage, gpte->raddr); |
297 | 287 | ||
298 | if (!gpte->may_read) | 288 | /* Update PTE R and C bits, so the guest's swapper knows we used the |
299 | return -EPERM; | 289 | * page */ |
300 | return 0; | 290 | if (gpte->may_read) { |
301 | } else { | 291 | /* Set the accessed flag */ |
302 | dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx " | 292 | r |= HPTE_R_R; |
303 | "ptegp=0x%lx)\n", | 293 | } |
304 | eaddr, to_book3s(vcpu)->sdr1, ptegp); | 294 | if (data && gpte->may_write) { |
305 | for (i = 0; i < 16; i += 2) | 295 | /* Set the dirty flag -- XXX even if not writing */ |
306 | dprintk(" %02d: 0x%llx - 0x%llx (0x%llx)\n", | 296 | r |= HPTE_R_C; |
307 | i, pteg[i], pteg[i+1], avpn); | 297 | } |
308 | 298 | ||
309 | if (!second) { | 299 | /* Write back into the PTEG */ |
310 | second = HPTE_V_SECONDARY; | 300 | if (pteg[i+1] != r) { |
311 | goto do_second; | 301 | pteg[i+1] = r; |
312 | } | 302 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); |
313 | } | 303 | } |
314 | 304 | ||
305 | if (!gpte->may_read) | ||
306 | return -EPERM; | ||
307 | return 0; | ||
308 | |||
315 | no_page_found: | 309 | no_page_found: |
316 | return -ENOENT; | 310 | return -ENOENT; |
317 | 311 | ||