ia64/xen-unstable

view xen/arch/powerpc/mm.c @ 14239:b75609e1fa81

[POWERPC][XEN] Implement guest_physmap_{add,remove}_page().
- Use p2m array in pfn2mfn() and DOMCTL_getmemlist.
- Remove domain extent list.
- Create and use an m2p array for mfn_to_gmfn().
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:07:59 2007 -0600 (2007-03-02)
parents f56981f78d73
children 59305500d95d
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/shadow.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 ( !test_bit(_DOMF_dying, &d->domain_flags) )
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)
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 return create_grant_va_mapping(addr, frame, current);
184 }
186 int destroy_grant_host_mapping(
187 unsigned long addr, unsigned long frame, unsigned int flags)
188 {
189 if (flags & GNTMAP_contains_pte) {
190 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
191 BUG();
192 return GNTST_general_error;
193 }
195 /* may have force the remove here */
196 return destroy_grant_va_mapping(addr, frame, current->domain);
197 }
199 int steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
200 {
201 panic("%s called\n", __func__);
202 return 1;
203 }
205 void put_page_type(struct page_info *page)
206 {
207 unsigned long nx, x, y = page->u.inuse.type_info;
209 do {
210 x = y;
211 nx = x - 1;
213 ASSERT((x & PGT_count_mask) != 0);
215 /*
216 * The page should always be validated while a reference is held. The
217 * exception is during domain destruction, when we forcibly invalidate
218 * page-table pages if we detect a referential loop.
219 * See domain.c:relinquish_list().
220 */
221 ASSERT((x & PGT_validated) ||
222 test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
224 if ( unlikely((nx & PGT_count_mask) == 0) )
225 {
226 /* Record TLB information for flush later. */
227 page->tlbflush_timestamp = tlbflush_current_time();
228 }
229 }
230 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
231 }
234 int get_page_type(struct page_info *page, unsigned long type)
235 {
236 unsigned long nx, x, y = page->u.inuse.type_info;
238 ASSERT(!(type & ~PGT_type_mask));
240 again:
241 do {
242 x = y;
243 nx = x + 1;
244 if ( unlikely((nx & PGT_count_mask) == 0) )
245 {
246 MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page));
247 return 0;
248 }
249 else if ( unlikely((x & PGT_count_mask) == 0) )
250 {
251 if ( (x & PGT_type_mask) != type )
252 {
253 /*
254 * On type change we check to flush stale TLB entries. This
255 * may be unnecessary (e.g., page was GDT/LDT) but those
256 * circumstances should be very rare.
257 */
258 cpumask_t mask =
259 page_get_owner(page)->domain_dirty_cpumask;
260 tlbflush_filter(mask, page->tlbflush_timestamp);
262 if ( unlikely(!cpus_empty(mask)) )
263 {
264 perfc_incrc(need_flush_tlb_flush);
265 flush_tlb_mask(mask);
266 }
268 /* We lose existing type, back pointer, and validity. */
269 nx &= ~(PGT_type_mask | PGT_validated);
270 nx |= type;
272 /* No special validation needed for writable pages. */
273 /* Page tables and GDT/LDT need to be scanned for validity. */
274 if ( type == PGT_writable_page )
275 nx |= PGT_validated;
276 }
277 }
278 else if ( unlikely((x & PGT_type_mask) != type) )
279 {
280 return 0;
281 }
282 else if ( unlikely(!(x & PGT_validated)) )
283 {
284 /* Someone else is updating validation of this page. Wait... */
285 while ( (y = page->u.inuse.type_info) == x )
286 cpu_relax();
287 goto again;
288 }
289 }
290 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
292 if ( unlikely(!(nx & PGT_validated)) )
293 {
294 /* Noone else is updating simultaneously. */
295 __set_bit(_PGT_validated, &page->u.inuse.type_info);
296 }
298 return 1;
299 }
301 long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
302 {
303 printk("%s: no PPC specific memory ops\n", __func__);
304 return -ENOSYS;
305 }
307 extern void copy_page(void *dp, void *sp)
308 {
309 if (on_systemsim()) {
310 systemsim_memcpy(dp, sp, PAGE_SIZE);
311 } else {
312 memcpy(dp, sp, PAGE_SIZE);
313 }
314 }
316 /* Allocate (rma_nrpages - nrpages) more memory for domain in proper size. */
317 uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages)
318 {
319 struct page_info *pg;
320 ulong mfn;
321 ulong gpfn = rma_nrpages; /* starting PFN at end of RMA */
322 uint ext_order;
323 uint ext_nrpages;
324 uint total_nrpages;
325 int i;
327 ext_order = cpu_extent_order();
328 ext_nrpages = 1 << ext_order;
330 total_nrpages = rma_nrpages;
332 /* We only allocate in nr_extsz chunks so if you are not divisible
333 * you get more than you asked for. */
334 while (total_nrpages < nrpages) {
335 pg = alloc_domheap_pages(d, ext_order, 0);
336 if (pg == NULL)
337 return total_nrpages;
339 /* Build p2m mapping for newly allocated extent. */
340 mfn = page_to_mfn(pg);
341 for (i = 0; i < (1 << ext_order); i++)
342 guest_physmap_add_page(d, gpfn + i, mfn + i);
344 /* Bump starting PFN by extent size pages. */
345 gpfn += ext_nrpages;
347 total_nrpages += ext_nrpages;
348 }
350 return total_nrpages;
351 }
353 int allocate_rma(struct domain *d, unsigned int order)
354 {
355 struct vcpu *v;
356 ulong rma_base;
357 ulong rma_sz;
358 ulong mfn;
359 int i;
361 if (d->arch.rma_page)
362 return -EINVAL;
364 d->arch.rma_page = alloc_domheap_pages(d, order, 0);
365 if (d->arch.rma_page == NULL) {
366 gdprintk(XENLOG_INFO, "Could not allocate order=%d RMA for domain %u\n",
367 order, d->domain_id);
368 return -ENOMEM;
369 }
370 d->arch.rma_order = order;
372 rma_base = page_to_maddr(d->arch.rma_page);
373 rma_sz = rma_size(d->arch.rma_order);
375 BUG_ON(rma_base & (rma_sz - 1)); /* check alignment */
377 printk("allocated RMA for Dom[%d]: 0x%lx[0x%lx]\n",
378 d->domain_id, rma_base, rma_sz);
380 mfn = page_to_mfn(d->arch.rma_page);
382 for (i = 0; i < (1 << d->arch.rma_order); i++ ) {
383 d->arch.rma_page[i].count_info |= PGC_page_RMA;
384 clear_page((void *)page_to_maddr(&d->arch.rma_page[i]));
386 /* Set up p2m mapping for RMA. */
387 guest_physmap_add_page(d, i, mfn+i);
388 }
390 /* shared_info uses last page of RMA */
391 d->shared_info = (shared_info_t *) (rma_base + rma_sz - PAGE_SIZE);
393 /* if there are already running vcpus, adjust v->vcpu_info */
394 /* XXX untested */
395 for_each_vcpu(d, v) {
396 v->vcpu_info = &d->shared_info->vcpu_info[v->vcpu_id];
397 }
399 return 0;
400 }
402 void free_rma_check(struct page_info *page)
403 {
404 if (test_bit(_PGC_page_RMA, &page->count_info) &&
405 !test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags))
406 panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
407 }
409 ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
410 {
411 ulong mfn = INVALID_MFN;
412 int t = PFN_TYPE_NONE;
413 ulong foreign_map_pfn = 1UL << cpu_foreign_map_order();
415 /* quick tests first */
416 if (pfn & foreign_map_pfn) {
417 t = PFN_TYPE_FOREIGN;
418 mfn = foreign_to_mfn(d, pfn);
419 } else if (pfn >= max_page && pfn <
420 (max_page + nr_grant_frames(d->grant_table))) {
421 /* XXX access d->grant_table->nr_grant_frames without lock.
422 * Currently on powerpc dynamic expanding grant table is
423 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
424 * so that this access is safe.
425 */
426 /* Its a grant table access */
427 t = PFN_TYPE_GNTTAB;
428 mfn = gnttab_shared_mfn(d, d->grant_table, (pfn - max_page));
429 } else if (d->is_privileged && platform_io_mfn(pfn)) {
430 t = PFN_TYPE_IO;
431 mfn = pfn;
432 } else {
433 if (pfn < d->arch.p2m_entries) {
434 t = PFN_TYPE_LOGICAL;
435 mfn = d->arch.p2m[pfn];
436 }
437 #ifdef DEBUG
438 if (t != PFN_TYPE_NONE &&
439 (d->domain_flags & DOMF_dying) &&
440 page_get_owner(mfn_to_page(mfn)) != d) {
441 printk("%s: page type: %d owner Dom[%d]:%p expected Dom[%d]:%p\n",
442 __func__, t,
443 page_get_owner(mfn_to_page(mfn))->domain_id,
444 page_get_owner(mfn_to_page(mfn)),
445 d->domain_id, d);
446 BUG();
447 }
448 #endif
449 }
451 if (t == PFN_TYPE_NONE) {
452 /* This hack allows dom0 to map all memory, necessary to
453 * initialize domU state. */
454 if (d->is_privileged && mfn_valid(pfn)) {
455 struct page_info *pg;
457 /* page better be allocated to some domain but not the caller */
458 pg = mfn_to_page(pfn);
459 if (!(pg->count_info & PGC_allocated))
460 panic("Foreign page: 0x%lx is not owned by any domain\n",
461 mfn);
462 if (page_get_owner(pg) == d)
463 panic("Foreign page: 0x%lx is owned by this domain\n",
464 mfn);
466 t = PFN_TYPE_FOREIGN;
467 mfn = pfn;
468 }
469 }
471 if (mfn == INVALID_MFN) {
472 printk("%s: Dom[%d] pfn 0x%lx is not a valid page\n",
473 __func__, d->domain_id, pfn);
474 }
476 if (type)
477 *type = t;
479 return mfn;
480 }
482 unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn)
483 {
484 struct page_info *pg = mfn_to_page(mfn);
485 ulong gnttab_mfn;
487 /* is this our mfn? */
488 if (page_get_owner(pg) != d)
489 return INVALID_M2P_ENTRY;
491 /* XXX access d->grant_table->nr_grant_frames without lock.
492 * Currently on powerpc dynamic expanding grant table is
493 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
494 * so that this access is safe.
495 */
496 /* grant? */
497 gnttab_mfn = gnttab_shared_mfn(d, d->grant_table, 0);
498 if (mfn >= gnttab_mfn && mfn <
499 (gnttab_mfn + nr_grant_frames(d->grant_table)))
500 return max_page + (mfn - gnttab_mfn);
502 /* IO? */
503 if (d->is_privileged && platform_io_mfn(mfn))
504 return mfn;
506 /* check m2p table */
507 return get_gpfn_from_mfn(mfn);
508 }
510 /* NB: caller holds d->page_alloc lock, sets d->max_pages = new_max */
511 int guest_physmap_max_mem_pages(struct domain *d, unsigned long new_max_pages)
512 {
513 u32 *p2m_array = NULL;
514 u32 *p2m_old = NULL;
515 ulong i;
517 /* XXX We probably could, but right now we don't shrink the p2m array.
518 * NB: d->max_pages >= d->arch.p2m_entries */
519 if (new_max_pages < d->max_pages) {
520 printk("Can't shrink DOM%d max memory pages\n", d->domain_id);
521 return -EINVAL;
522 }
524 /* Allocate one u32 per page. */
525 p2m_array = xmalloc_array(u32, new_max_pages);
526 if (p2m_array == NULL)
527 return -ENOMEM;
529 /* Copy old mappings into new array. */
530 if (d->arch.p2m != NULL) {
531 /* XXX This could take a long time; we should use a continuation. */
532 memcpy(p2m_array, d->arch.p2m, d->arch.p2m_entries * sizeof(u32));
533 p2m_old = d->arch.p2m;
534 }
536 /* Mark new mfns as invalid. */
537 for (i = d->arch.p2m_entries; i < new_max_pages; i++)
538 p2m_array[i] = INVALID_MFN;
540 /* Set new p2m pointer and size. */
541 d->arch.p2m = p2m_array;
542 d->arch.p2m_entries = new_max_pages;
544 /* Free old p2m array if present. */
545 if (p2m_old)
546 xfree(p2m_old);
548 return 0;
549 }
551 void guest_physmap_add_page(
552 struct domain *d, unsigned long gpfn, unsigned long mfn)
553 {
554 if (page_get_owner(mfn_to_page(mfn)) != d) {
555 printk("Won't map foreign MFN 0x%lx for DOM%d\n", mfn, d->domain_id);
556 return;
557 }
559 /* Check that pfn is within guest table. */
560 if (gpfn >= d->arch.p2m_entries) {
561 printk("Won't map invalid PFN 0x%lx for DOM%d\n", gpfn, d->domain_id);
562 return;
563 }
565 /* Warn if there is an existing mapping. */
566 /* XXX: probably shouldn't let this happen, but
567 current interface doesn't throw errors. =( */
568 if (d->arch.p2m[gpfn] != INVALID_MFN)
569 printk("Ack! PFN aliased. PFN%lx, old MFN=%x, new MFN=%lx\n",
570 gpfn, d->arch.p2m[gpfn], mfn);
572 /* PFN and MFN ok, map in p2m table. */
573 d->arch.p2m[gpfn] = mfn;
575 /* Map in m2p table. */
576 set_gpfn_from_mfn(mfn, gpfn);
577 }
579 void guest_physmap_remove_page(
580 struct domain *d, unsigned long gpfn, unsigned long mfn)
581 {
582 if (page_get_owner(mfn_to_page(mfn)) != d) {
583 printk("Won't unmap foreign MFN 0x%lx for DOM%d\n", mfn, d->domain_id);
584 return;
585 }
587 /* check that pfn is within guest table */
588 if (gpfn >= d->arch.p2m_entries) {
589 printk("Won't unmap invalid PFN 0x%lx for DOM%d\n", gpfn, d->domain_id);
590 return;
591 }
593 /* PFN and MFN ok, unmap from p2m table. */
594 d->arch.p2m[gpfn] = INVALID_MFN;
596 /* Unmap from m2p table. */
597 set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
598 }
600 void shadow_drop_references(
601 struct domain *d, struct page_info *page)
602 {
603 }