ia64/xen-unstable

view xen/arch/powerpc/mm.c @ 16407:2e5d922b7ee3

xen: Allow granting of foreign access to iomem pages, and with
arbitrary cache attributes.
Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
Signed-off-by: Keir Fraser <keir.fraser@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Nov 20 17:26:48 2007 +0000 (2007-11-20)
parents a94bf8086002
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, 2006
17 *
18 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
19 * Jimi Xenidis <jimix@watson.ibm.com>
20 * Ryan Harper <ryanh@us.ibm.com>
21 */
23 #include <xen/config.h>
24 #include <xen/mm.h>
25 #include <xen/paging.h>
26 #include <xen/kernel.h>
27 #include <xen/sched.h>
28 #include <xen/perfc.h>
29 #include <asm/init.h>
30 #include <asm/page.h>
31 #include <asm/platform.h>
32 #include <asm/string.h>
33 #include <asm/platform.h>
34 #include <public/arch-powerpc.h>
36 #ifdef VERBOSE
37 #define MEM_LOG(_f, _a...) \
38 printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \
39 current->domain->domain_id , __LINE__ , ## _a )
40 #else
41 #define MEM_LOG(_f, _a...) ((void)0)
42 #endif
44 /* Frame table and its size in pages. */
45 struct page_info *frame_table;
46 unsigned long max_page;
47 unsigned long total_pages;
49 /* machine to phys mapping to used by all domains */
50 unsigned long *machine_phys_mapping;
52 void __init init_frametable(void)
53 {
54 unsigned long p;
55 unsigned long nr_pages;
56 int i;
58 nr_pages = PFN_UP(max_page * sizeof(struct page_info));
60 p = alloc_boot_pages(nr_pages, 1);
61 if (p == 0)
62 panic("Not enough memory for frame table\n");
64 frame_table = (struct page_info *)(p << PAGE_SHIFT);
65 for (i = 0; i < nr_pages; i += 1)
66 clear_page((void *)((p + i) << PAGE_SHIFT));
67 }
69 /* Array of PFNs, indexed by MFN. */
70 void __init init_machine_to_phys_table(void)
71 {
72 unsigned long p;
73 unsigned long nr_pages;
74 int i;
76 nr_pages = PFN_UP(max_page * sizeof(unsigned long));
78 p = alloc_boot_pages(nr_pages, 1);
79 if (p == 0)
80 panic("Not enough memory for machine phys mapping table\n");
82 machine_phys_mapping = (unsigned long *)(p << PAGE_SHIFT);
83 for (i = 0; i < nr_pages; i += 1)
84 clear_page((void *)((p + i) << PAGE_SHIFT));
85 }
87 void share_xen_page_with_guest(
88 struct page_info *page, struct domain *d, int readonly)
89 {
90 if ( page_get_owner(page) == d )
91 return;
93 /* this causes us to leak pages in the Domain and reuslts in
94 * Zombie domains, I think we are missing a piece, until we find
95 * it we disable the following code */
96 set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY);
98 spin_lock(&d->page_alloc_lock);
100 /* The incremented type count pins as writable or read-only. */
101 page->u.inuse.type_info = (readonly ? PGT_none : PGT_writable_page);
102 page->u.inuse.type_info |= PGT_validated | 1;
104 page_set_owner(page, d);
105 wmb(); /* install valid domain ptr before updating refcnt. */
106 ASSERT(page->count_info == 0);
108 /* Only add to the allocation list if the domain isn't dying. */
109 if ( !d->is_dying )
110 {
111 page->count_info |= PGC_allocated | 1;
112 if ( unlikely(d->xenheap_pages++ == 0) )
113 get_knownalive_domain(d);
114 list_add_tail(&page->list, &d->xenpage_list);
115 }
117 spin_unlock(&d->page_alloc_lock);
118 }
120 void share_xen_page_with_privileged_guests(
121 struct page_info *page, int readonly)
122 {
123 unimplemented();
124 }
126 static ulong foreign_to_mfn(struct domain *d, ulong pfn)
127 {
129 pfn -= 1UL << cpu_foreign_map_order();
131 BUG_ON(pfn >= d->arch.foreign_mfn_count);
133 return d->arch.foreign_mfns[pfn];
134 }
136 static int set_foreign(struct domain *d, ulong pfn, ulong mfn)
137 {
138 pfn -= 1UL << cpu_foreign_map_order();
140 BUG_ON(pfn >= d->arch.foreign_mfn_count);
141 d->arch.foreign_mfns[pfn] = mfn;
143 return 0;
144 }
146 static int create_grant_va_mapping(
147 unsigned long va, unsigned long frame, struct vcpu *v)
148 {
149 if (v->domain->domain_id != 0) {
150 printk("only Dom0 can map a grant entry\n");
151 BUG();
152 return GNTST_permission_denied;
153 }
154 set_foreign(v->domain, va >> PAGE_SHIFT, frame);
155 return GNTST_okay;
156 }
158 static int destroy_grant_va_mapping(
159 unsigned long addr, unsigned long frame, struct domain *d)
160 {
161 if (d->domain_id != 0) {
162 printk("only Dom0 can map a grant entry\n");
163 BUG();
164 return GNTST_permission_denied;
165 }
166 set_foreign(d, addr >> PAGE_SHIFT, ~0UL);
167 return GNTST_okay;
168 }
170 int create_grant_host_mapping(
171 unsigned long addr, unsigned long frame, unsigned int flags, unsigned int cache_flags)
172 {
173 if (flags & GNTMAP_application_map) {
174 printk("%s: GNTMAP_application_map not supported\n", __func__);
175 BUG();
176 return GNTST_general_error;
177 }
178 if (flags & GNTMAP_contains_pte) {
179 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
180 BUG();
181 return GNTST_general_error;
182 }
183 if (cache_flags) {
184 printk("%s: cache_flags not supported\n", __func__);
185 BUG();
186 return GNTST_general_error;
187 }
188 return create_grant_va_mapping(addr, frame, current);
189 }
191 int replace_grant_host_mapping(
192 unsigned long addr, unsigned long frame, unsigned long new_addr,
193 unsigned int flags)
194 {
195 if (new_addr) {
196 printk("%s: new_addr not supported\n", __func__);
197 BUG();
198 return GNTST_general_error;
199 }
201 if (flags & GNTMAP_contains_pte) {
202 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
203 BUG();
204 return GNTST_general_error;
205 }
207 /* may have force the remove here */
208 return destroy_grant_va_mapping(addr, frame, current->domain);
209 }
211 int steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
212 {
213 panic("%s called\n", __func__);
214 return 1;
215 }
217 void put_page_type(struct page_info *page)
218 {
219 unsigned long nx, x, y = page->u.inuse.type_info;
221 do {
222 x = y;
223 nx = x - 1;
225 ASSERT((x & PGT_count_mask) != 0);
227 /*
228 * The page should always be validated while a reference is held. The
229 * exception is during domain destruction, when we forcibly invalidate
230 * page-table pages if we detect a referential loop.
231 * See domain.c:relinquish_list().
232 */
233 ASSERT((x & PGT_validated) || page_get_owner(page)->is_dying);
235 if ( unlikely((nx & PGT_count_mask) == 0) )
236 {
237 /* Record TLB information for flush later. */
238 page->tlbflush_timestamp = tlbflush_current_time();
239 }
240 }
241 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
242 }
245 int get_page_type(struct page_info *page, unsigned long type)
246 {
247 unsigned long nx, x, y = page->u.inuse.type_info;
249 ASSERT(!(type & ~PGT_type_mask));
251 again:
252 do {
253 x = y;
254 nx = x + 1;
255 if ( unlikely((nx & PGT_count_mask) == 0) )
256 {
257 MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page));
258 return 0;
259 }
260 else if ( unlikely((x & PGT_count_mask) == 0) )
261 {
262 if ( (x & PGT_type_mask) != type )
263 {
264 /*
265 * On type change we check to flush stale TLB entries. This
266 * may be unnecessary (e.g., page was GDT/LDT) but those
267 * circumstances should be very rare.
268 */
269 cpumask_t mask =
270 page_get_owner(page)->domain_dirty_cpumask;
271 tlbflush_filter(mask, page->tlbflush_timestamp);
273 if ( unlikely(!cpus_empty(mask)) )
274 {
275 perfc_incr(need_flush_tlb_flush);
276 flush_tlb_mask(mask);
277 }
279 /* We lose existing type, back pointer, and validity. */
280 nx &= ~(PGT_type_mask | PGT_validated);
281 nx |= type;
283 /* No special validation needed for writable pages. */
284 /* Page tables and GDT/LDT need to be scanned for validity. */
285 if ( type == PGT_writable_page )
286 nx |= PGT_validated;
287 }
288 }
289 else if ( unlikely((x & PGT_type_mask) != type) )
290 {
291 return 0;
292 }
293 else if ( unlikely(!(x & PGT_validated)) )
294 {
295 /* Someone else is updating validation of this page. Wait... */
296 while ( (y = page->u.inuse.type_info) == x )
297 cpu_relax();
298 goto again;
299 }
300 }
301 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
303 if ( unlikely(!(nx & PGT_validated)) )
304 {
305 /* Noone else is updating simultaneously. */
306 __set_bit(_PGT_validated, &page->u.inuse.type_info);
307 }
309 return 1;
310 }
312 long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
313 {
314 printk("%s: no PPC specific memory ops\n", __func__);
315 return -ENOSYS;
316 }
318 extern void copy_page(void *dp, void *sp)
319 {
320 if (on_systemsim()) {
321 systemsim_memcpy(dp, sp, PAGE_SIZE);
322 } else {
323 memcpy(dp, sp, PAGE_SIZE);
324 }
325 }
327 /* Allocate (rma_nrpages - nrpages) more memory for domain in proper size. */
328 uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages)
329 {
330 struct page_info *pg;
331 ulong mfn;
332 ulong gpfn = rma_nrpages; /* starting PFN at end of RMA */
333 uint ext_order;
334 uint ext_nrpages;
335 uint total_nrpages;
336 int i;
338 ext_order = cpu_extent_order();
339 ext_nrpages = 1 << ext_order;
341 total_nrpages = rma_nrpages;
343 /* We only allocate in nr_extsz chunks so if you are not divisible
344 * you get more than you asked for. */
345 while (total_nrpages < nrpages) {
346 pg = alloc_domheap_pages(d, ext_order, 0);
347 if (pg == NULL)
348 return total_nrpages;
350 /* Build p2m mapping for newly allocated extent. */
351 mfn = page_to_mfn(pg);
352 for (i = 0; i < (1 << ext_order); i++)
353 guest_physmap_add_page(d, gpfn + i, mfn + i);
355 /* Bump starting PFN by extent size pages. */
356 gpfn += ext_nrpages;
358 total_nrpages += ext_nrpages;
359 }
361 return total_nrpages;
362 }
364 int allocate_rma(struct domain *d, unsigned int order)
365 {
366 struct vcpu *v;
367 ulong rma_base;
368 ulong rma_sz;
369 ulong mfn;
370 int i;
372 if (d->arch.rma_page)
373 return -EINVAL;
375 d->arch.rma_page = alloc_domheap_pages(d, order, 0);
376 if (d->arch.rma_page == NULL) {
377 gdprintk(XENLOG_INFO, "Could not allocate order=%d RMA for domain %u\n",
378 order, d->domain_id);
379 return -ENOMEM;
380 }
381 d->arch.rma_order = order;
383 rma_base = page_to_maddr(d->arch.rma_page);
384 rma_sz = rma_size(d->arch.rma_order);
386 BUG_ON(rma_base & (rma_sz - 1)); /* check alignment */
388 printk("allocated RMA for Dom[%d]: 0x%lx[0x%lx]\n",
389 d->domain_id, rma_base, rma_sz);
391 mfn = page_to_mfn(d->arch.rma_page);
393 for (i = 0; i < (1 << d->arch.rma_order); i++ ) {
394 d->arch.rma_page[i].count_info |= PGC_page_RMA;
395 clear_page((void *)page_to_maddr(&d->arch.rma_page[i]));
397 /* Set up p2m mapping for RMA. */
398 guest_physmap_add_page(d, i, mfn+i);
399 }
401 /* shared_info uses last page of RMA */
402 d->shared_info = (shared_info_t *) (rma_base + rma_sz - PAGE_SIZE);
404 /* if there are already running vcpus, adjust v->vcpu_info */
405 /* XXX untested */
406 for_each_vcpu(d, v) {
407 v->vcpu_info = &d->shared_info->vcpu_info[v->vcpu_id];
408 }
410 return 0;
411 }
413 void free_rma_check(struct page_info *page)
414 {
415 if (test_bit(_PGC_page_RMA, &page->count_info)) {
416 if (!page_get_owner(page)->is_dying) {
417 panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
418 } else {
419 clear_bit(_PGC_page_RMA, &page->count_info);
420 }
421 }
422 }
424 ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
425 {
426 ulong mfn = INVALID_MFN;
427 int t = PFN_TYPE_NONE;
428 ulong foreign_map_pfn = 1UL << cpu_foreign_map_order();
430 /* quick tests first */
431 if (pfn & foreign_map_pfn) {
432 t = PFN_TYPE_FOREIGN;
433 mfn = foreign_to_mfn(d, pfn);
434 } else if (pfn >= max_page && pfn <
435 (max_page + nr_grant_frames(d->grant_table))) {
436 /* XXX access d->grant_table->nr_grant_frames without lock.
437 * Currently on powerpc dynamic expanding grant table is
438 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
439 * so that this access is safe.
440 */
441 /* Its a grant table access */
442 t = PFN_TYPE_GNTTAB;
443 mfn = gnttab_shared_mfn(d, d->grant_table, (pfn - max_page));
444 } else if (d->is_privileged && platform_io_mfn(pfn)) {
445 t = PFN_TYPE_IO;
446 mfn = pfn;
447 } else {
448 if (pfn < d->arch.p2m_entries) {
449 t = PFN_TYPE_LOGICAL;
450 mfn = d->arch.p2m[pfn];
451 }
452 #ifdef DEBUG
453 if (t != PFN_TYPE_NONE && d->is_dying &&
454 page_get_owner(mfn_to_page(mfn)) != d) {
455 printk("%s: page type: %d owner Dom[%d]:%p expected Dom[%d]:%p\n",
456 __func__, t,
457 page_get_owner(mfn_to_page(mfn))->domain_id,
458 page_get_owner(mfn_to_page(mfn)),
459 d->domain_id, d);
460 BUG();
461 }
462 #endif
463 }
465 if (t == PFN_TYPE_NONE) {
466 /* This hack allows dom0 to map all memory, necessary to
467 * initialize domU state. */
468 if (d->is_privileged && mfn_valid(pfn)) {
469 struct page_info *pg;
471 /* page better be allocated to some domain but not the caller */
472 pg = mfn_to_page(pfn);
473 if (!(pg->count_info & PGC_allocated))
474 panic("Foreign page: 0x%lx is not owned by any domain\n",
475 mfn);
476 if (page_get_owner(pg) == d)
477 panic("Foreign page: 0x%lx is owned by this domain\n",
478 mfn);
480 t = PFN_TYPE_FOREIGN;
481 mfn = pfn;
482 }
483 }
485 if (mfn == INVALID_MFN) {
486 printk("%s: Dom[%d] pfn 0x%lx is not a valid page\n",
487 __func__, d->domain_id, pfn);
488 }
490 if (type)
491 *type = t;
493 return mfn;
494 }
496 unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn)
497 {
498 struct page_info *pg = mfn_to_page(mfn);
499 ulong gnttab_mfn;
501 /* is this our mfn? */
502 if (page_get_owner(pg) != d)
503 return INVALID_M2P_ENTRY;
505 /* XXX access d->grant_table->nr_grant_frames without lock.
506 * Currently on powerpc dynamic expanding grant table is
507 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
508 * so that this access is safe.
509 */
510 /* grant? */
511 gnttab_mfn = gnttab_shared_mfn(d, d->grant_table, 0);
512 if (mfn >= gnttab_mfn && mfn <
513 (gnttab_mfn + nr_grant_frames(d->grant_table)))
514 return max_page + (mfn - gnttab_mfn);
516 /* IO? */
517 if (d->is_privileged && platform_io_mfn(mfn))
518 return mfn;
520 /* check m2p table */
521 return get_gpfn_from_mfn(mfn);
522 }
524 /* NB: caller holds d->page_alloc lock, sets d->max_pages = new_max */
525 int guest_physmap_max_mem_pages(struct domain *d, unsigned long new_max_pages)
526 {
527 u32 *p2m_array = NULL;
528 u32 *p2m_old = NULL;
529 ulong i;
531 /* XXX We probably could, but right now we don't shrink the p2m array.
532 * NB: d->max_pages >= d->arch.p2m_entries */
533 if (new_max_pages < d->max_pages) {
534 printk("Can't shrink DOM%d max memory pages\n", d->domain_id);
535 return -EINVAL;
536 }
538 /* Allocate one u32 per page. */
539 p2m_array = xmalloc_array(u32, new_max_pages);
540 if (p2m_array == NULL)
541 return -ENOMEM;
543 /* Copy old mappings into new array. */
544 if (d->arch.p2m != NULL) {
545 /* XXX This could take a long time; we should use a continuation. */
546 memcpy(p2m_array, d->arch.p2m, d->arch.p2m_entries * sizeof(u32));
547 p2m_old = d->arch.p2m;
548 }
550 /* Mark new mfns as invalid. */
551 for (i = d->arch.p2m_entries; i < new_max_pages; i++)
552 p2m_array[i] = INVALID_MFN;
554 /* Set new p2m pointer and size. */
555 d->arch.p2m = p2m_array;
556 d->arch.p2m_entries = new_max_pages;
558 /* Free old p2m array if present. */
559 if (p2m_old)
560 xfree(p2m_old);
562 return 0;
563 }
565 void guest_physmap_add_page(
566 struct domain *d, unsigned long gpfn, unsigned long mfn)
567 {
568 if (page_get_owner(mfn_to_page(mfn)) != d) {
569 printk("Won't map foreign MFN 0x%lx for DOM%d\n", mfn, d->domain_id);
570 return;
571 }
573 /* Check that pfn is within guest table. */
574 if (gpfn >= d->arch.p2m_entries) {
575 printk("Won't map invalid PFN 0x%lx for DOM%d\n", gpfn, d->domain_id);
576 return;
577 }
579 /* Warn if there is an existing mapping. */
580 /* XXX: probably shouldn't let this happen, but
581 current interface doesn't throw errors. =( */
582 if (d->arch.p2m[gpfn] != INVALID_MFN)
583 printk("Ack! PFN aliased. PFN%lx, old MFN=%x, new MFN=%lx\n",
584 gpfn, d->arch.p2m[gpfn], mfn);
586 /* PFN and MFN ok, map in p2m table. */
587 d->arch.p2m[gpfn] = mfn;
589 /* Map in m2p table. */
590 set_gpfn_from_mfn(mfn, gpfn);
591 }
593 void guest_physmap_remove_page(
594 struct domain *d, unsigned long gpfn, unsigned long mfn)
595 {
596 if (page_get_owner(mfn_to_page(mfn)) != d) {
597 printk("Won't unmap foreign MFN 0x%lx for DOM%d\n", mfn, d->domain_id);
598 return;
599 }
601 /* check that pfn is within guest table */
602 if (gpfn >= d->arch.p2m_entries) {
603 printk("Won't unmap invalid PFN 0x%lx for DOM%d\n", gpfn, d->domain_id);
604 return;
605 }
607 /* PFN and MFN ok, unmap from p2m table. */
608 d->arch.p2m[gpfn] = INVALID_MFN;
610 /* Unmap from m2p table. */
611 set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
612 }
614 void shadow_drop_references(
615 struct domain *d, struct page_info *page)
616 {
617 }