ia64/xen-unstable

view xen/arch/powerpc/papr/xlate.c @ 14237:eceb9ccd84a8

[POWERPC][XEN] Introduce "platform" abstraction to describe the IO hole.
Signed-off-by: Ryan Harper <ryanh@us.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Hollis Blanchard <hollisb@us.ibm.com>
date Fri Mar 02 17:06:50 2007 -0600 (2007-03-02)
parents 4f0353778233
children
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>
32 #include <asm/platform.h>
34 #ifdef DEBUG
35 #define DBG(fmt...) printk(fmt)
36 #else
37 #define DBG(fmt...)
38 #endif
39 #ifdef DEBUG_LOW
40 #define DBG_LOW(fmt...) printk(fmt)
41 #else
42 #define DBG_LOW(fmt...)
43 #endif
45 #ifdef USE_PTE_INSERT
46 static inline void pte_insert(union pte volatile *pte,
47 ulong vsid, ulong rpn, ulong lrpn)
48 {
49 /*
50 * It's required that external locking be done to provide
51 * exclusion between the choices of insertion points. Any valid
52 * choice of pte requires that the pte be invalid upon entry to
53 * this function.
54 */
56 ASSERT( (pte->bits.v == 0) );
58 /* Set shadow word. */
59 (void)lrpn;
61 /* Set the second word first so the valid bit is the last thing set */
62 pte->words.rpn = rpn;
64 /* Guarantee the second word is visible before the valid bit */
65 __asm__ __volatile__("eieio" : : : "memory");
67 /* Now set the first word including the valid bit */
68 pte->words.vsid = vsid;
69 /* Architecturally this instruction will cause a heavier operation
70 * if this one is not supported. note: on come machines like Cell
71 * this coul dbe a nop */
72 __asm__ __volatile__("ptesync" : : : "memory");
73 }
74 #endif
76 /*
77 * POWER Arch 2.03 Sec 4.12.1 (Yes 970 is one)
78 *
79 * when a tlbsync instruction has been executed by a processor in a
80 * given partition, a ptesync instruction must be executed by that
81 * processor before a tlbie or tlbsync instruction is executed by
82 * another processor in that partition.
83 *
84 * So for now, here is a BFLock to deal with it, the lock should be per-domain.
85 *
86 * XXX Will need to audit all tlb usege soon enough.
87 */
89 static DEFINE_SPINLOCK(native_tlbie_lock);
90 static void pte_tlbie(union pte volatile *pte, ulong ptex)
91 {
92 ulong va;
93 ulong vsid;
94 ulong group;
95 ulong pi;
96 ulong pi_high;
98 vsid = pte->bits.avpn >> 5;
99 group = ptex >> 3;
100 if (pte->bits.h) {
101 group = ~group;
102 }
103 pi = (vsid ^ group) & 0x7ff;
104 pi_high = (pte->bits.avpn & 0x1f) << 11;
105 pi |= pi_high;
106 va = (pi << 12) | (vsid << 28);
107 va &= ~(0xffffULL << 48);
109 spin_lock(&native_tlbie_lock);
110 #ifndef FLUSH_THE_WHOLE_THING
111 if (pte->bits.l) {
112 va |= (pte->bits.rpn & 1);
113 asm volatile("ptesync ;tlbie %0,1" : : "r"(va) : "memory");
114 } else {
115 asm volatile("ptesync; tlbie %0,0" : : "r"(va) : "memory");
116 }
117 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
118 #else
119 {
120 unsigned i;
121 ulong rb;
123 for (i = 0; i < 256; i++) {
124 rb = i;
125 rb <<= 12;
126 asm volatile("ptesync; tlbie %0,0; eieio; tlbsync; ptesync; isync"
127 : "=r" (rb): : "memory");
128 asm volatile("ptesync; tlbie %0,1; eieio; tlbsync; ptesync; isync"
129 : "=r" (rb): : "memory");
130 }
131 }
132 #endif
133 spin_unlock(&native_tlbie_lock);
134 }
136 long pte_enter(ulong flags, ulong ptex, ulong vsid, ulong rpn)
137 {
138 union pte pte;
139 union pte volatile *ppte;
140 struct domain_htab *htab;
141 int lp_bits = 0;
142 int pgshift = PAGE_SHIFT;
143 ulong idx;
144 int limit = 0; /* how many PTEs to examine in the PTEG */
145 ulong pfn;
146 ulong mfn;
147 struct vcpu *v = get_current();
148 struct domain *d = v->domain;
149 int mtype;
150 struct page_info *pg = NULL;
151 struct domain *f = NULL;
154 htab = &d->arch.htab;
155 if (ptex > (1UL << htab->log_num_ptes)) {
156 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
157 return H_Parameter;
158 }
160 /* use local HPTE to avoid manual shifting & masking */
161 pte.words.vsid = vsid;
162 pte.words.rpn = rpn;
164 if ( pte.bits.l ) { /* large page? */
165 /* figure out the page size for the selected large page */
166 ulong lp_rpn = pte.bits.rpn;
167 uint lp_size = 0;
169 while ( lp_rpn & 0x1 ) {
170 lp_rpn >>= 1;
171 lp_bits = ((lp_bits << 1) | 0x1);
172 lp_size++;
173 }
175 if ( lp_size >= d->arch.large_page_sizes ) {
176 DBG("%s: attempt to use unsupported lp_size %d\n",
177 __func__, lp_size);
178 return H_Parameter;
179 }
181 /* get correct pgshift value */
182 pgshift = d->arch.large_page_order[lp_size] + PAGE_SHIFT;
183 }
185 /* get the correct logical RPN in terms of 4K pages need to mask
186 * off lp bits and unused arpn bits if this is a large page */
188 pfn = ~0ULL << (pgshift - PAGE_SHIFT);
189 pfn = pte.bits.rpn & pfn;
191 mfn = pfn2mfn(d, pfn, &mtype);
192 if (mfn == INVALID_MFN) {
193 DBG("%s: Bad PFN: 0x%lx\n", __func__, pfn);
194 return H_Parameter;
195 }
197 if (mtype == PFN_TYPE_IO && !d->is_privileged) {
198 /* only a privilaged dom can access outside IO space */
199 DBG("%s: unprivileged access to physical page: 0x%lx\n",
200 __func__, pfn);
201 return H_Privilege;
202 }
203 if (mtype == PFN_TYPE_IO) {
204 if ( !((pte.bits.w == 0)
205 && (pte.bits.i == 1)
206 && (pte.bits.g == 1)) ) {
207 DBG("%s: expecting an IO WIMG "
208 "w=%x i=%d m=%d, g=%d\n word 0x%lx\n", __func__,
209 pte.bits.w, pte.bits.i, pte.bits.m, pte.bits.g,
210 pte.words.rpn);
211 return H_Parameter;
212 }
213 }
214 if (mtype == PFN_TYPE_GNTTAB) {
215 DBG("%s: Dom[%d] mapping grant table: 0x%lx\n",
216 __func__, d->domain_id, pfn << PAGE_SHIFT);
217 pte.bits.i = 0;
218 pte.bits.g = 0;
219 }
220 /* fixup the RPN field of our local PTE copy */
221 pte.bits.rpn = mfn | lp_bits;
223 /* clear reserved bits in high word */
224 pte.bits.lock = 0x0;
225 pte.bits.res = 0x0;
227 /* clear reserved bits in low word */
228 pte.bits.pp0 = 0x0;
229 pte.bits.ts = 0x0;
230 pte.bits.res2 = 0x0;
232 if (mtype == PFN_TYPE_FOREIGN) {
233 pg = mfn_to_page(mfn);
234 f = page_get_owner(pg);
236 BUG_ON(f == d);
238 if (unlikely(!get_domain(f))) {
239 DBG("%s: Rescinded, no domain: 0x%lx\n", __func__, pfn);
240 return H_Rescinded;
241 }
242 if (unlikely(!get_page(pg, f))) {
243 put_domain(f);
244 DBG("%s: Rescinded, no page: 0x%lx\n", __func__, pfn);
245 return H_Rescinded;
246 }
247 }
249 if ( !(flags & H_EXACT) ) {
250 /* PTEG (not specific PTE); clear 3 lowest bits */
251 ptex &= ~0x7UL;
252 limit = 7;
253 }
255 /* data manipulations should be done prior to the pte insertion. */
256 if ( flags & H_ZERO_PAGE ) {
257 ulong pg = mfn << PAGE_SHIFT;
258 ulong pgs = 1UL << pgshift;
260 while (pgs > 0) {
261 clear_page((void *)pg);
262 pg += PAGE_SIZE;
263 --pgs;
264 }
265 }
267 if ( flags & H_ICACHE_INVALIDATE ) {
268 ulong k;
269 ulong addr = mfn << PAGE_SHIFT;
271 for (k = 0; k < (1UL << pgshift); k += L1_CACHE_BYTES) {
272 dcbst(addr + k);
273 sync();
274 icbi(addr + k);
275 sync();
276 isync();
277 }
278 }
280 if ( flags & H_ICACHE_SYNCHRONIZE ) {
281 ulong k;
282 ulong addr = mfn << PAGE_SHIFT;
283 for (k = 0; k < (1UL << pgshift); k += L1_CACHE_BYTES) {
284 icbi(addr + k);
285 sync();
286 isync();
287 }
288 }
290 for (idx = ptex; idx <= ptex + limit; idx++) {
291 ppte = &htab->map[idx];
293 if ( ppte->bits.v == 0 && ppte->bits.lock == 0) {
294 /* got it */
296 asm volatile(
297 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
298 :
299 : "b" (ppte), "r" (pte.words.rpn), "r" (pte.words.vsid)
300 : "memory");
302 return idx;
303 }
304 }
306 /* If the PTEG is full then no additional values are returned. */
307 DBG("%s: PTEG FULL\n", __func__);
309 if (pg != NULL)
310 put_page(pg);
312 if (f != NULL)
313 put_domain(f);
315 return H_PTEG_Full;
316 }
318 static void h_enter(struct cpu_user_regs *regs)
319 {
320 ulong flags = regs->gprs[4];
321 ulong ptex = regs->gprs[5];
322 ulong vsid = regs->gprs[6];
323 ulong rpn = regs->gprs[7];
324 long ret;
326 ret = pte_enter(flags, ptex, vsid, rpn);
328 if (ret >= 0) {
329 regs->gprs[3] = H_Success;
330 regs->gprs[4] = ret;
331 } else
332 regs->gprs[3] = ret;
333 }
335 static void h_protect(struct cpu_user_regs *regs)
336 {
337 ulong flags = regs->gprs[4];
338 ulong ptex = regs->gprs[5];
339 ulong avpn = regs->gprs[6];
340 struct vcpu *v = get_current();
341 struct domain *d = v->domain;
342 struct domain_htab *htab = &d->arch.htab;
343 union pte volatile *ppte;
344 union pte lpte;
346 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx avpn: 0x%lx\n", __func__,
347 flags, ptex, avpn);
348 if ( ptex > (1UL << htab->log_num_ptes) ) {
349 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
350 regs->gprs[3] = H_Parameter;
351 return;
352 }
353 ppte = &htab->map[ptex];
355 lpte.words.vsid = ppte->words.vsid;
356 lpte.words.rpn = ppte->words.rpn;
358 /* the AVPN param occupies the bit-space of the word */
359 if ( (flags & H_AVPN) && lpte.bits.avpn != avpn >> 7 ) {
360 DBG_LOW("%s: %p: AVPN check failed: 0x%lx, 0x%lx\n", __func__,
361 ppte, lpte.words.vsid, lpte.words.rpn);
362 regs->gprs[3] = H_Not_Found;
363 return;
364 }
366 if (lpte.bits.v == 0) {
367 /* the PAPR does not specify what to do here, this is because
368 * we invalidate entires where the PAPR says to 0 the whole hi
369 * dword, so the AVPN should catch this first */
371 DBG("%s: pte invalid\n", __func__);
372 regs->gprs[3] = H_Not_Found;
373 return;
374 }
376 lpte.bits.v = 0;
378 /* ppte->words.vsid = lpte.words.vsid; */
379 asm volatile(
380 "eieio; std %1, 0(%0); ptesync"
381 :
382 : "b" (ppte), "r" (0)
383 : "memory");
385 pte_tlbie(&lpte, ptex);
387 /* We never touch pp0, and PP bits in flags are in the right
388 * order */
389 lpte.bits.pp1 = flags & (H_PP1 | H_PP2);
390 lpte.bits.n = (flags & H_N) ? 1 : 0;
392 lpte.bits.v = 1;
393 lpte.bits.r = 0;
395 asm volatile(
396 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
397 :
398 : "b" (ppte), "r" (lpte.words.rpn), "r" (lpte.words.vsid)
399 : "memory");
401 regs->gprs[3] = H_Success;
402 }
404 static void h_clear_ref(struct cpu_user_regs *regs)
405 {
406 ulong ptex = regs->gprs[5];
407 struct vcpu *v = get_current();
408 struct domain *d = v->domain;
409 struct domain_htab *htab = &d->arch.htab;
410 union pte volatile *pte;
411 union pte lpte;
413 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx\n", __func__,
414 regs->gprs[4], ptex);
416 #ifdef DEBUG
417 if (regs->gprs[4] != 0) {
418 DBG("WARNING: %s: "
419 "flags are undefined and should be 0: 0x%lx\n",
420 __func__, regs->gprs[4]);
421 }
422 #endif
424 if (ptex > (1UL << htab->log_num_ptes)) {
425 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
426 regs->gprs[3] = H_Parameter;
427 return;
428 }
429 pte = &htab->map[ptex];
430 lpte.words.rpn = pte->words.rpn;
432 regs->gprs[4] = lpte.words.rpn;
434 if (lpte.bits.r != 0) {
435 lpte.bits.r = 0;
437 asm volatile("std %1, 8(%0); eieio; ptesync"
438 :
439 : "b" (pte), "r" (lpte.words.rpn) : "memory");
441 pte_tlbie(&lpte, ptex);
442 }
443 regs->gprs[3] = H_Success;
444 }
446 static void h_clear_mod(struct cpu_user_regs *regs)
447 {
448 ulong ptex = regs->gprs[5];
449 struct vcpu *v = get_current();
450 struct domain *d = v->domain;
451 struct domain_htab *htab = &d->arch.htab;
452 union pte volatile *pte;
453 union pte lpte;
455 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx\n", __func__,
456 regs->gprs[4], ptex);
458 #ifdef DEBUG
459 if (regs->gprs[4] != 0) {
460 DBG("WARNING: %s: "
461 "flags are undefined and should be 0: 0x%lx\n",
462 __func__, regs->gprs[4]);
463 }
464 #endif
466 if (ptex > (1UL << htab->log_num_ptes)) {
467 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
468 regs->gprs[3] = H_Parameter;
469 return;
470 }
471 pte = &htab->map[ptex];
472 lpte.words.vsid = pte->words.vsid;
473 lpte.words.rpn = pte->words.rpn;
475 regs->gprs[3] = H_Success;
476 regs->gprs[4] = lpte.words.rpn;
478 if (lpte.bits.c != 0) {
479 /* invalidate */
480 asm volatile(
481 "eieio; std %1, 0(%0); ptesync"
482 :
483 : "b" (pte), "r" (0)
484 : "memory");
486 pte_tlbie(&lpte, ptex);
488 lpte.bits.c = 0;
489 asm volatile(
490 "std %1, 8(%0); eieio; std %2, 0(%0); ptesync"
491 :
492 : "b" (pte), "r" (lpte.words.rpn), "r" (lpte.words.vsid)
493 : "memory");
494 }
495 }
497 long pte_remove(ulong flags, ulong ptex, ulong avpn, ulong *hi, ulong *lo)
498 {
499 struct vcpu *v = get_current();
500 struct domain *d = v->domain;
501 struct domain_htab *htab = &d->arch.htab;
502 union pte volatile *pte;
503 union pte lpte;
505 DBG_LOW("%s: flags: 0x%lx ptex: 0x%lx avpn: 0x%lx\n", __func__,
506 flags, ptex, avpn);
508 if ( ptex > (1UL << htab->log_num_ptes) ) {
509 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
510 return H_Parameter;
511 }
512 pte = &htab->map[ptex];
513 lpte.words.vsid = pte->words.vsid;
514 lpte.words.rpn = pte->words.rpn;
516 if ((flags & H_AVPN) && lpte.bits.avpn != (avpn >> 7)) {
517 DBG_LOW("%s: AVPN does not match\n", __func__);
518 return H_Not_Found;
519 }
521 if ((flags & H_ANDCOND) && ((avpn & pte->words.vsid) != 0)) {
522 DBG("%s: andcond does not match\n", __func__);
523 return H_Not_Found;
524 }
526 /* return old PTE in regs 4 and 5 */
527 *hi = lpte.words.vsid;
528 *lo = lpte.words.rpn;
530 #ifdef DEBUG_LOW
531 /* XXX - I'm very skeptical of doing ANYTHING if not bits.v */
532 /* XXX - I think the spec should be questioned in this case (MFM) */
533 if (lpte.bits.v == 0) {
534 DBG_LOW("%s: removing invalid entry\n", __func__);
535 }
536 #endif
538 if (lpte.bits.v) {
539 ulong mfn = lpte.bits.rpn;
540 if (!platform_io_mfn(mfn)) {
541 struct page_info *pg = mfn_to_page(mfn);
542 struct domain *f = page_get_owner(pg);
544 if (f != d) {
545 put_domain(f);
546 put_page(pg);
547 }
548 }
549 }
551 asm volatile("eieio; std %1, 0(%0); ptesync"
552 :
553 : "b" (pte), "r" (0)
554 : "memory");
556 pte_tlbie(&lpte, ptex);
558 return H_Success;
559 }
561 static void h_remove(struct cpu_user_regs *regs)
562 {
563 ulong flags = regs->gprs[4];
564 ulong ptex = regs->gprs[5];
565 ulong avpn = regs->gprs[6];
566 ulong hi, lo;
567 long ret;
569 ret = pte_remove(flags, ptex, avpn, &hi, &lo);
571 regs->gprs[3] = ret;
573 if (ret == H_Success) {
574 regs->gprs[4] = hi;
575 regs->gprs[5] = lo;
576 }
577 return;
578 }
580 static void h_read(struct cpu_user_regs *regs)
581 {
582 ulong flags = regs->gprs[4];
583 ulong ptex = regs->gprs[5];
584 struct vcpu *v = get_current();
585 struct domain *d = v->domain;
586 struct domain_htab *htab = &d->arch.htab;
587 union pte volatile *pte;
589 if (flags & H_READ_4)
590 ptex &= ~0x3UL;
592 if (ptex > (1UL << htab->log_num_ptes)) {
593 DBG("%s: bad ptex: 0x%lx\n", __func__, ptex);
594 regs->gprs[3] = H_Parameter;
595 return;
596 }
597 pte = &htab->map[ptex];
598 regs->gprs[4] = pte[0].words.vsid;
599 regs->gprs[5] = pte[0].words.rpn;
601 if (!(flags & H_READ_4)) {
602 /* dump another 3 PTEs */
603 regs->gprs[6] = pte[1].words.vsid;
604 regs->gprs[7] = pte[1].words.rpn;
605 regs->gprs[8] = pte[2].words.vsid;
606 regs->gprs[9] = pte[2].words.rpn;
607 regs->gprs[10] = pte[3].words.vsid;
608 regs->gprs[11] = pte[3].words.rpn;
609 }
611 regs->gprs[3] = H_Success;
612 }
614 __init_papr_hcall(H_ENTER, h_enter);
615 __init_papr_hcall(H_READ, h_read);
616 __init_papr_hcall(H_REMOVE, h_remove);
617 __init_papr_hcall(H_CLEAR_MOD, h_clear_mod);
618 __init_papr_hcall(H_CLEAR_REF, h_clear_ref);
619 __init_papr_hcall(H_PROTECT, h_protect);