direct-io.hg

view xen/arch/powerpc/papr/xlate.c @ 12957:4d47f058fffd

[XEN][POWERPC] Turn off the Guard bit for access to the grant table
Soon, we will not have domains map this page like IO, but for the near
term lets undo all the IO-type PTE bits.
Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Sat Nov 11 10:30:07 2006 -0500 (2006-11-11)
parents 79bb96e0ba73
children 6deca1ea217f
line source
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2005
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 */
21 #undef DEBUG
22 #undef DEBUG_LOW
24 #include <xen/config.h>
25 #include <xen/types.h>
26 #include <xen/sched.h>
27 #include <xen/init.h>
28 #include <public/xen.h>
29 #include <asm/current.h>
30 #include <asm/papr.h>
31 #include <asm/hcalls.h>
33 #ifdef DEBUG
34 #define DBG(fmt...) printk(fmt)
35 #else
36 #define DBG(fmt...)
37 #endif
38 #ifdef DEBUG_LOW
39 #define DBG_LOW(fmt...) printk(fmt)
40 #else
41 #define DBG_LOW(fmt...)
42 #endif
44 #ifdef USE_PTE_INSERT
45 static inline void pte_insert(union pte volatile *pte,
46 ulong vsid, ulong rpn, ulong lrpn)
47 {
48 /*
49 * It's required that external locking be done to provide
50 * exclusion between the choices of insertion points. Any valid
51 * choice of pte requires that the pte be invalid upon entry to
52 * this function.
53 */
55 ASSERT( (pte->bits.v == 0) );
57 /* Set shadow word. */
58 (void)lrpn;
60 /* Set the second word first so the valid bit is the last thing set */
61 pte->words.rpn = rpn;
63 /* Guarantee the second word is visible before the valid bit */
64 __asm__ __volatile__("eieio" : : : "memory");
66 /* Now set the first word including the valid bit */
67 pte->words.vsid = vsid;
68 /* Architecturally this instruction will cause a heavier operation
69 * if this one is not supported. note: on come machines like Cell
70 * this coul dbe a nop */
71 __asm__ __volatile__("ptesync" : : : "memory");
72 }
73 #endif
75 static void pte_tlbie(union pte volatile *pte, ulong ptex)
76 {
77 ulong va;
78 ulong vsid;
79 ulong group;
80 ulong pi;
81 ulong pi_high;
83 vsid = pte->bits.avpn >> 5;
84 group = ptex >> 3;
85 if (pte->bits.h) {
86 group = ~group;
87 }
88 pi = (vsid ^ group) & 0x7ff;
89 pi_high = (pte->bits.avpn & 0x1f) << 11;
90 pi |= pi_high;
91 va = (pi << 12) | (vsid << 28);
92 va &= ~(0xffffULL << 48);
94 #ifndef FLUSH_THE_WHOLE_THING
95 if (pte->bits.l) {
96 va |= (pte->bits.rpn & 1);
97 asm volatile("ptesync ;tlbie %0,1" : : "r"(va) : "memory");
98 } else {
99 asm volatile("ptesync; tlbie %0,0" : : "r"(va) : "memory");
100 }
101 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
102 #else
103 {
104 unsigned i;
105 ulong rb;
107 for (i = 0; i < 256; i++) {
108 rb = i;
109 rb <<= 12;
110 asm volatile("ptesync; tlbie %0,0; eieio; tlbsync; ptesync; isync"
111 : "=r" (rb): : "memory");
112 asm volatile("ptesync; tlbie %0,1; eieio; tlbsync; ptesync; isync"
113 : "=r" (rb): : "memory");
114 }
115 }
116 #endif
118 }
120 long pte_enter(ulong flags, ulong ptex, ulong vsid, ulong rpn)
121 {
122 union pte pte;
123 union pte volatile *ppte;
124 struct domain_htab *htab;
125 int lp_bits = 0;
126 int pgshift = PAGE_SHIFT;
127 ulong idx;
128 int limit = 0; /* how many PTEs to examine in the PTEG */
129 ulong pfn;
130 ulong mfn;
131 struct vcpu *v = get_current();
132 struct domain *d = v->domain;
133 int mtype;
134 struct page_info *pg = NULL;
135 struct domain *f = NULL;
138 htab = &d->arch.htab;
139 if (ptex > (1UL << htab->log_num_ptes)) {
140 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
141 return H_Parameter;
142 }
144 /* use local HPTE to avoid manual shifting & masking */
145 pte.words.vsid = vsid;
146 pte.words.rpn = rpn;
148 if ( pte.bits.l ) { /* large page? */
149 /* figure out the page size for the selected large page */
150 ulong lp_rpn = pte.bits.rpn;
151 uint lp_size = 0;
153 while ( lp_rpn & 0x1 ) {
154 lp_rpn >>= 1;
155 lp_bits = ((lp_bits << 1) | 0x1);
156 lp_size++;
157 }
159 if ( lp_size >= d->arch.large_page_sizes ) {
160 DBG("%s: attempt to use unsupported lp_size %d\n",
161 __func__, lp_size);
162 return H_Parameter;
163 }
165 /* get correct pgshift value */
166 pgshift = d->arch.large_page_order[lp_size] + PAGE_SHIFT;
167 }
169 /* get the correct logical RPN in terms of 4K pages need to mask
170 * off lp bits and unused arpn bits if this is a large page */
172 pfn = ~0ULL << (pgshift - PAGE_SHIFT);
173 pfn = pte.bits.rpn & pfn;
175 mfn = pfn2mfn(d, pfn, &mtype);
176 if (mfn == INVALID_MFN) {
177 DBG("%s: Bad PFN: 0x%lx\n", __func__, pfn);
178 return H_Parameter;
179 }
181 if (mtype == PFN_TYPE_IO &&!test_bit(_DOMF_privileged, &d->domain_flags)) {
182 /* only a privilaged dom can access outside IO space */
183 DBG("%s: unprivileged access to physical page: 0x%lx\n",
184 __func__, pfn);
185 return H_Privilege;
186 }
187 if (mtype == PFN_TYPE_IO) {
188 if ( !((pte.bits.w == 0)
189 && (pte.bits.i == 1)
190 && (pte.bits.g == 1)) ) {
191 DBG("%s: expecting an IO WIMG "
192 "w=%x i=%d m=%d, g=%d\n word 0x%lx\n", __func__,
193 pte.bits.w, pte.bits.i, pte.bits.m, pte.bits.g,
194 pte.words.rpn);
195 return H_Parameter;
196 }
197 }
198 if (mtype == PFN_TYPE_GNTTAB) {
199 DBG("%s: Dom[%d] mapping grant table: 0x%lx\n",
200 __func__, d->domain_id, pfn << PAGE_SHIFT);
201 pte.bits.i = 0;
202 pte.bits.g = 0;
203 }
204 /* fixup the RPN field of our local PTE copy */
205 pte.bits.rpn = mfn | lp_bits;
207 /* clear reserved bits in high word */
208 pte.bits.lock = 0x0;
209 pte.bits.res = 0x0;
211 /* clear reserved bits in low word */
212 pte.bits.pp0 = 0x0;
213 pte.bits.ts = 0x0;
214 pte.bits.res2 = 0x0;
216 if (mtype == PFN_TYPE_FOREIGN) {
217 pg = mfn_to_page(mfn);
218 f = page_get_owner(pg);
220 BUG_ON(f == d);
222 if (unlikely(!get_domain(f))) {
223 DBG("%s: Rescinded, no domain: 0x%lx\n", __func__, pfn);
224 return H_Rescinded;
225 }
226 if (unlikely(!get_page(pg, f))) {
227 put_domain(f);
228 DBG("%s: Rescinded, no page: 0x%lx\n", __func__, pfn);
229 return H_Rescinded;
230 }
231 }
233 if ( !(flags & H_EXACT) ) {
234 /* PTEG (not specific PTE); clear 3 lowest bits */
235 ptex &= ~0x7UL;
236 limit = 7;
237 }
239 /* data manipulations should be done prior to the pte insertion. */
240 if ( flags & H_ZERO_PAGE ) {
241 ulong pg = mfn << PAGE_SHIFT;
242 ulong pgs = 1UL << pgshift;
244 while (pgs > 0) {
245 clear_page((void *)pg);
246 pg += PAGE_SIZE;
247 --pgs;
248 }
249 }
251 if ( flags & H_ICACHE_INVALIDATE ) {
252 ulong k;
253 ulong addr = mfn << PAGE_SHIFT;
255 for (k = 0; k < (1UL << pgshift); k += L1_CACHE_BYTES) {
256 dcbst(addr + k);
257 sync();
258 icbi(addr + k);
259 sync();
260 isync();
261 }
262 }
264 if ( flags & H_ICACHE_SYNCHRONIZE ) {
265 ulong k;
266 ulong addr = mfn << PAGE_SHIFT;
267 for (k = 0; k < (1UL << pgshift); k += L1_CACHE_BYTES) {
268 icbi(addr + k);
269 sync();
270 isync();
271 }
272 }
274 for (idx = ptex; idx <= ptex + limit; idx++) {
275 ppte = &htab->map[idx];
277 if ( ppte->bits.v == 0 && ppte->bits.lock == 0) {
278 /* got it */
280 asm volatile(
281 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
282 :
283 : "b" (ppte), "r" (pte.words.rpn), "r" (pte.words.vsid)
284 : "memory");
286 return idx;
287 }
288 }
290 /* If the PTEG is full then no additional values are returned. */
291 DBG("%s: PTEG FULL\n", __func__);
293 if (pg != NULL)
294 put_page(pg);
296 if (f != NULL)
297 put_domain(f);
299 return H_PTEG_Full;
300 }
302 static void h_enter(struct cpu_user_regs *regs)
303 {
304 ulong flags = regs->gprs[4];
305 ulong ptex = regs->gprs[5];
306 ulong vsid = regs->gprs[6];
307 ulong rpn = regs->gprs[7];
308 long ret;
310 ret = pte_enter(flags, ptex, vsid, rpn);
312 if (ret >= 0) {
313 regs->gprs[3] = H_Success;
314 regs->gprs[4] = ret;
315 } else
316 regs->gprs[3] = ret;
317 }
319 static void h_protect(struct cpu_user_regs *regs)
320 {
321 ulong flags = regs->gprs[4];
322 ulong ptex = regs->gprs[5];
323 ulong avpn = regs->gprs[6];
324 struct vcpu *v = get_current();
325 struct domain *d = v->domain;
326 struct domain_htab *htab = &d->arch.htab;
327 union pte volatile *ppte;
328 union pte lpte;
330 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx avpn: 0x%lx\n", __func__,
331 flags, ptex, avpn);
332 if ( ptex > (1UL << htab->log_num_ptes) ) {
333 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
334 regs->gprs[3] = H_Parameter;
335 return;
336 }
337 ppte = &htab->map[ptex];
339 lpte.words.vsid = ppte->words.vsid;
340 lpte.words.rpn = ppte->words.rpn;
342 /* the AVPN param occupies the bit-space of the word */
343 if ( (flags & H_AVPN) && lpte.bits.avpn != avpn >> 7 ) {
344 DBG_LOW("%s: %p: AVPN check failed: 0x%lx, 0x%lx\n", __func__,
345 ppte, lpte.words.vsid, lpte.words.rpn);
346 regs->gprs[3] = H_Not_Found;
347 return;
348 }
350 if (lpte.bits.v == 0) {
351 /* the PAPR does not specify what to do here, this is because
352 * we invalidate entires where the PAPR says to 0 the whole hi
353 * dword, so the AVPN should catch this first */
355 DBG("%s: pte invalid\n", __func__);
356 regs->gprs[3] = H_Not_Found;
357 return;
358 }
360 lpte.bits.v = 0;
362 /* ppte->words.vsid = lpte.words.vsid; */
363 asm volatile(
364 "eieio; std %1, 0(%0); ptesync"
365 :
366 : "b" (ppte), "r" (0)
367 : "memory");
369 pte_tlbie(&lpte, ptex);
371 /* We never touch pp0, and PP bits in flags are in the right
372 * order */
373 lpte.bits.pp1 = flags & (H_PP1 | H_PP2);
374 lpte.bits.n = (flags & H_N) ? 1 : 0;
376 lpte.bits.v = 1;
377 lpte.bits.r = 0;
379 asm volatile(
380 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
381 :
382 : "b" (ppte), "r" (lpte.words.rpn), "r" (lpte.words.vsid)
383 : "memory");
385 regs->gprs[3] = H_Success;
386 }
388 static void h_clear_ref(struct cpu_user_regs *regs)
389 {
390 ulong ptex = regs->gprs[5];
391 struct vcpu *v = get_current();
392 struct domain *d = v->domain;
393 struct domain_htab *htab = &d->arch.htab;
394 union pte volatile *pte;
395 union pte lpte;
397 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx\n", __func__,
398 regs->gprs[4], ptex);
400 #ifdef DEBUG
401 if (regs->gprs[4] != 0) {
402 DBG("WARNING: %s: "
403 "flags are undefined and should be 0: 0x%lx\n",
404 __func__, regs->gprs[4]);
405 }
406 #endif
408 if (ptex > (1UL << htab->log_num_ptes)) {
409 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
410 regs->gprs[3] = H_Parameter;
411 return;
412 }
413 pte = &htab->map[ptex];
414 lpte.words.rpn = pte->words.rpn;
416 regs->gprs[4] = lpte.words.rpn;
418 if (lpte.bits.r != 0) {
419 lpte.bits.r = 0;
421 asm volatile("std %1, 8(%0); eieio; ptesync"
422 :
423 : "b" (pte), "r" (lpte.words.rpn) : "memory");
425 pte_tlbie(&lpte, ptex);
426 }
427 regs->gprs[3] = H_Success;
428 }
430 static void h_clear_mod(struct cpu_user_regs *regs)
431 {
432 ulong ptex = regs->gprs[5];
433 struct vcpu *v = get_current();
434 struct domain *d = v->domain;
435 struct domain_htab *htab = &d->arch.htab;
436 union pte volatile *pte;
437 union pte lpte;
439 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx\n", __func__,
440 regs->gprs[4], ptex);
442 #ifdef DEBUG
443 if (regs->gprs[4] != 0) {
444 DBG("WARNING: %s: "
445 "flags are undefined and should be 0: 0x%lx\n",
446 __func__, regs->gprs[4]);
447 }
448 #endif
450 if (ptex > (1UL << htab->log_num_ptes)) {
451 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
452 regs->gprs[3] = H_Parameter;
453 return;
454 }
455 pte = &htab->map[ptex];
456 lpte.words.vsid = pte->words.vsid;
457 lpte.words.rpn = pte->words.rpn;
459 regs->gprs[3] = H_Success;
460 regs->gprs[4] = lpte.words.rpn;
462 if (lpte.bits.c != 0) {
463 /* invalidate */
464 asm volatile(
465 "eieio; std %1, 0(%0); ptesync"
466 :
467 : "b" (pte), "r" (0)
468 : "memory");
470 pte_tlbie(&lpte, ptex);
472 lpte.bits.c = 0;
473 asm volatile(
474 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
475 :
476 : "b" (pte), "r" (lpte.words.rpn), "r" (lpte.words.vsid)
477 : "memory");
478 }
479 }
481 long pte_remove(ulong flags, ulong ptex, ulong avpn, ulong *hi, ulong *lo)
482 {
483 struct vcpu *v = get_current();
484 struct domain *d = v->domain;
485 struct domain_htab *htab = &d->arch.htab;
486 union pte volatile *pte;
487 union pte lpte;
489 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx avpn: 0x%lx\n", __func__,
490 flags, ptex, avpn);
492 if ( ptex > (1UL << htab->log_num_ptes) ) {
493 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
494 return H_Parameter;
495 }
496 pte = &htab->map[ptex];
497 lpte.words.vsid = pte->words.vsid;
498 lpte.words.rpn = pte->words.rpn;
500 if ((flags & H_AVPN) && lpte.bits.avpn != (avpn >> 7)) {
501 DBG_LOW("%s: AVPN does not match\n", __func__);
502 return H_Not_Found;
503 }
505 if ((flags & H_ANDCOND) && ((avpn & pte->words.vsid) != 0)) {
506 DBG("%s: andcond does not match\n", __func__);
507 return H_Not_Found;
508 }
510 /* return old PTE in regs 4 and 5 */
511 *hi = lpte.words.vsid;
512 *lo = lpte.words.rpn;
514 #ifdef DEBUG_LOW
515 /* XXX - I'm very skeptical of doing ANYTHING if not bits.v */
516 /* XXX - I think the spec should be questioned in this case (MFM) */
517 if (lpte.bits.v == 0) {
518 DBG_LOW("%s: removing invalid entry\n", __func__);
519 }
520 #endif
522 if (lpte.bits.v) {
523 ulong mfn = lpte.bits.rpn;
524 if (!cpu_io_mfn(mfn)) {
525 struct page_info *pg = mfn_to_page(mfn);
526 struct domain *f = page_get_owner(pg);
528 if (f != d) {
529 put_domain(f);
530 put_page(pg);
531 }
532 }
533 }
535 asm volatile("eieio; std %1, 0(%0); ptesync"
536 :
537 : "b" (pte), "r" (0)
538 : "memory");
540 pte_tlbie(&lpte, ptex);
542 return H_Success;
543 }
545 static void h_remove(struct cpu_user_regs *regs)
546 {
547 ulong flags = regs->gprs[4];
548 ulong ptex = regs->gprs[5];
549 ulong avpn = regs->gprs[6];
550 ulong hi, lo;
551 long ret;
553 ret = pte_remove(flags, ptex, avpn, &hi, &lo);
555 regs->gprs[3] = ret;
557 if (ret == H_Success) {
558 regs->gprs[4] = hi;
559 regs->gprs[5] = lo;
560 }
561 return;
562 }
564 static void h_read(struct cpu_user_regs *regs)
565 {
566 ulong flags = regs->gprs[4];
567 ulong ptex = regs->gprs[5];
568 struct vcpu *v = get_current();
569 struct domain *d = v->domain;
570 struct domain_htab *htab = &d->arch.htab;
571 union pte volatile *pte;
573 if (flags & H_READ_4)
574 ptex &= ~0x3UL;
576 if (ptex > (1UL << htab->log_num_ptes)) {
577 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
578 regs->gprs[3] = H_Parameter;
579 return;
580 }
581 pte = &htab->map[ptex];
582 regs->gprs[4] = pte[0].words.vsid;
583 regs->gprs[5] = pte[0].words.rpn;
585 if (!(flags & H_READ_4)) {
586 /* dump another 3 PTEs */
587 regs->gprs[6] = pte[1].words.vsid;
588 regs->gprs[7] = pte[1].words.rpn;
589 regs->gprs[8] = pte[2].words.vsid;
590 regs->gprs[9] = pte[2].words.rpn;
591 regs->gprs[10] = pte[3].words.vsid;
592 regs->gprs[11] = pte[3].words.rpn;
593 }
595 regs->gprs[3] = H_Success;
596 }
598 __init_papr_hcall(H_ENTER, h_enter);
599 __init_papr_hcall(H_READ, h_read);
600 __init_papr_hcall(H_REMOVE, h_remove);
601 __init_papr_hcall(H_CLEAR_MOD, h_clear_mod);
602 __init_papr_hcall(H_CLEAR_REF, h_clear_ref);
603 __init_papr_hcall(H_PROTECT, h_protect);