ia64/xen-unstable

view xen/arch/powerpc/mm.c @ 14196:9d36026b1b43

xen: Cleanups and bug fixes after the rcu_lock_domain patch.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Mar 01 11:38:55 2007 +0000 (2007-03-01)
parents 4ce0b332b572
children 7e9dc164b572
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 */
22 #include <xen/config.h>
23 #include <xen/mm.h>
24 #include <xen/shadow.h>
25 #include <xen/kernel.h>
26 #include <xen/sched.h>
27 #include <xen/perfc.h>
28 #include <asm/init.h>
29 #include <asm/page.h>
30 #include <asm/string.h>
31 #include <public/arch-powerpc.h>
33 #ifdef VERBOSE
34 #define MEM_LOG(_f, _a...) \
35 printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \
36 current->domain->domain_id , __LINE__ , ## _a )
37 #else
38 #define MEM_LOG(_f, _a...) ((void)0)
39 #endif
41 /* Frame table and its size in pages. */
42 struct page_info *frame_table;
43 unsigned long max_page;
44 unsigned long total_pages;
46 void __init init_frametable(void)
47 {
48 unsigned long p;
49 unsigned long nr_pages;
50 int i;
52 nr_pages = PFN_UP(max_page * sizeof(struct page_info));
54 p = alloc_boot_pages(nr_pages, 1);
55 if (p == 0)
56 panic("Not enough memory for frame table\n");
58 frame_table = (struct page_info *)(p << PAGE_SHIFT);
59 for (i = 0; i < nr_pages; i += 1)
60 clear_page((void *)((p + i) << PAGE_SHIFT));
61 }
63 void share_xen_page_with_guest(
64 struct page_info *page, struct domain *d, int readonly)
65 {
66 if ( page_get_owner(page) == d )
67 return;
69 /* this causes us to leak pages in the Domain and reuslts in
70 * Zombie domains, I think we are missing a piece, until we find
71 * it we disable the following code */
72 set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY);
74 spin_lock(&d->page_alloc_lock);
76 /* The incremented type count pins as writable or read-only. */
77 page->u.inuse.type_info = (readonly ? PGT_none : PGT_writable_page);
78 page->u.inuse.type_info |= PGT_validated | 1;
80 page_set_owner(page, d);
81 wmb(); /* install valid domain ptr before updating refcnt. */
82 ASSERT(page->count_info == 0);
84 /* Only add to the allocation list if the domain isn't dying. */
85 if ( !test_bit(_DOMF_dying, &d->domain_flags) )
86 {
87 page->count_info |= PGC_allocated | 1;
88 if ( unlikely(d->xenheap_pages++ == 0) )
89 get_knownalive_domain(d);
90 list_add_tail(&page->list, &d->xenpage_list);
91 }
93 spin_unlock(&d->page_alloc_lock);
94 }
96 void share_xen_page_with_privileged_guests(
97 struct page_info *page, int readonly)
98 {
99 unimplemented();
100 }
102 static ulong foreign_to_mfn(struct domain *d, ulong pfn)
103 {
105 pfn -= 1UL << cpu_foreign_map_order();
107 BUG_ON(pfn >= d->arch.foreign_mfn_count);
109 return d->arch.foreign_mfns[pfn];
110 }
112 static int set_foreign(struct domain *d, ulong pfn, ulong mfn)
113 {
114 pfn -= 1UL << cpu_foreign_map_order();
116 BUG_ON(pfn >= d->arch.foreign_mfn_count);
117 d->arch.foreign_mfns[pfn] = mfn;
119 return 0;
120 }
122 static int create_grant_va_mapping(
123 unsigned long va, unsigned long frame, struct vcpu *v)
124 {
125 if (v->domain->domain_id != 0) {
126 printk("only Dom0 can map a grant entry\n");
127 BUG();
128 return GNTST_permission_denied;
129 }
130 set_foreign(v->domain, va >> PAGE_SHIFT, frame);
131 return GNTST_okay;
132 }
134 static int destroy_grant_va_mapping(
135 unsigned long addr, unsigned long frame, struct domain *d)
136 {
137 if (d->domain_id != 0) {
138 printk("only Dom0 can map a grant entry\n");
139 BUG();
140 return GNTST_permission_denied;
141 }
142 set_foreign(d, addr >> PAGE_SHIFT, ~0UL);
143 return GNTST_okay;
144 }
146 int create_grant_host_mapping(
147 unsigned long addr, unsigned long frame, unsigned int flags)
148 {
149 if (flags & GNTMAP_application_map) {
150 printk("%s: GNTMAP_application_map not supported\n", __func__);
151 BUG();
152 return GNTST_general_error;
153 }
154 if (flags & GNTMAP_contains_pte) {
155 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
156 BUG();
157 return GNTST_general_error;
158 }
159 return create_grant_va_mapping(addr, frame, current);
160 }
162 int destroy_grant_host_mapping(
163 unsigned long addr, unsigned long frame, unsigned int flags)
164 {
165 if (flags & GNTMAP_contains_pte) {
166 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
167 BUG();
168 return GNTST_general_error;
169 }
171 /* may have force the remove here */
172 return destroy_grant_va_mapping(addr, frame, current->domain);
173 }
175 int steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
176 {
177 panic("%s called\n", __func__);
178 return 1;
179 }
181 void put_page_type(struct page_info *page)
182 {
183 unsigned long nx, x, y = page->u.inuse.type_info;
185 do {
186 x = y;
187 nx = x - 1;
189 ASSERT((x & PGT_count_mask) != 0);
191 /*
192 * The page should always be validated while a reference is held. The
193 * exception is during domain destruction, when we forcibly invalidate
194 * page-table pages if we detect a referential loop.
195 * See domain.c:relinquish_list().
196 */
197 ASSERT((x & PGT_validated) ||
198 test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
200 if ( unlikely((nx & PGT_count_mask) == 0) )
201 {
202 /* Record TLB information for flush later. */
203 page->tlbflush_timestamp = tlbflush_current_time();
204 }
205 }
206 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
207 }
210 int get_page_type(struct page_info *page, unsigned long type)
211 {
212 unsigned long nx, x, y = page->u.inuse.type_info;
214 ASSERT(!(type & ~PGT_type_mask));
216 again:
217 do {
218 x = y;
219 nx = x + 1;
220 if ( unlikely((nx & PGT_count_mask) == 0) )
221 {
222 MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page));
223 return 0;
224 }
225 else if ( unlikely((x & PGT_count_mask) == 0) )
226 {
227 if ( (x & PGT_type_mask) != type )
228 {
229 /*
230 * On type change we check to flush stale TLB entries. This
231 * may be unnecessary (e.g., page was GDT/LDT) but those
232 * circumstances should be very rare.
233 */
234 cpumask_t mask =
235 page_get_owner(page)->domain_dirty_cpumask;
236 tlbflush_filter(mask, page->tlbflush_timestamp);
238 if ( unlikely(!cpus_empty(mask)) )
239 {
240 perfc_incrc(need_flush_tlb_flush);
241 flush_tlb_mask(mask);
242 }
244 /* We lose existing type, back pointer, and validity. */
245 nx &= ~(PGT_type_mask | PGT_validated);
246 nx |= type;
248 /* No special validation needed for writable pages. */
249 /* Page tables and GDT/LDT need to be scanned for validity. */
250 if ( type == PGT_writable_page )
251 nx |= PGT_validated;
252 }
253 }
254 else if ( unlikely((x & PGT_type_mask) != type) )
255 {
256 return 0;
257 }
258 else if ( unlikely(!(x & PGT_validated)) )
259 {
260 /* Someone else is updating validation of this page. Wait... */
261 while ( (y = page->u.inuse.type_info) == x )
262 cpu_relax();
263 goto again;
264 }
265 }
266 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
268 if ( unlikely(!(nx & PGT_validated)) )
269 {
270 /* Noone else is updating simultaneously. */
271 __set_bit(_PGT_validated, &page->u.inuse.type_info);
272 }
274 return 1;
275 }
277 long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
278 {
279 printk("%s: no PPC specific memory ops\n", __func__);
280 return -ENOSYS;
281 }
283 extern void copy_page(void *dp, void *sp)
284 {
285 if (on_systemsim()) {
286 systemsim_memcpy(dp, sp, PAGE_SIZE);
287 } else {
288 memcpy(dp, sp, PAGE_SIZE);
289 }
290 }
292 /* XXX should probably replace with faster data structure */
293 static uint add_extent(struct domain *d, struct page_info *pg, uint order)
294 {
295 struct page_extents *pe;
297 pe = xmalloc(struct page_extents);
298 if (pe == NULL)
299 return -ENOMEM;
301 pe->pg = pg;
302 pe->order = order;
304 list_add_tail(&pe->pe_list, &d->arch.extent_list);
306 return 0;
307 }
309 void free_extents(struct domain *d)
310 {
311 /* we just need to free the memory behind list */
312 struct list_head *list;
313 struct list_head *ent;
314 struct list_head *next;
316 list = &d->arch.extent_list;
317 ent = list->next;
319 while (ent != list) {
320 next = ent->next;
321 xfree(ent);
322 ent = next;
323 }
324 }
326 uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages)
327 {
328 uint ext_order;
329 uint ext_nrpages;
330 uint total_nrpages;
331 struct page_info *pg;
333 ext_order = cpu_extent_order();
334 ext_nrpages = 1 << ext_order;
336 total_nrpages = rma_nrpages;
338 /* We only allocate in nr_extsz chunks so if you are not divisible
339 * you get more than you asked for */
340 while (total_nrpages < nrpages) {
341 pg = alloc_domheap_pages(d, ext_order, 0);
342 if (pg == NULL)
343 return total_nrpages;
345 if (add_extent(d, pg, ext_order) < 0) {
346 free_domheap_pages(pg, ext_order);
347 return total_nrpages;
348 }
349 total_nrpages += ext_nrpages;
350 }
352 return total_nrpages;
353 }
355 int allocate_rma(struct domain *d, unsigned int order)
356 {
357 struct vcpu *v;
358 ulong rma_base;
359 ulong rma_sz;
360 int i;
362 if (d->arch.rma_page)
363 return -EINVAL;
365 d->arch.rma_page = alloc_domheap_pages(d, order, 0);
366 if (d->arch.rma_page == NULL) {
367 gdprintk(XENLOG_INFO, "Could not allocate order=%d RMA for domain %u\n",
368 order, d->domain_id);
369 return -ENOMEM;
370 }
371 d->arch.rma_order = order;
373 rma_base = page_to_maddr(d->arch.rma_page);
374 rma_sz = rma_size(d->arch.rma_order);
376 BUG_ON(rma_base & (rma_sz - 1)); /* check alignment */
378 printk("allocated RMA for Dom[%d]: 0x%lx[0x%lx]\n",
379 d->domain_id, rma_base, rma_sz);
381 for (i = 0; i < (1 << d->arch.rma_order); i++ ) {
382 /* Add in any extra CPUs that need flushing because of this page. */
383 d->arch.rma_page[i].count_info |= PGC_page_RMA;
384 clear_page((void *)page_to_maddr(&d->arch.rma_page[i]));
385 }
387 d->shared_info = (shared_info_t *)
388 (rma_addr(&d->arch, RMA_SHARED_INFO) + rma_base);
390 /* if there are already running vcpus, adjust v->vcpu_info */
391 /* XXX untested */
392 for_each_vcpu(d, v) {
393 v->vcpu_info = &d->shared_info->vcpu_info[v->vcpu_id];
394 }
396 return 0;
397 }
399 void free_rma_check(struct page_info *page)
400 {
401 if (test_bit(_PGC_page_RMA, &page->count_info) &&
402 !test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags))
403 panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
404 }
406 ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
407 {
408 ulong rma_base_mfn = page_to_mfn(d->arch.rma_page);
409 ulong rma_size_mfn = 1UL << d->arch.rma_order;
410 struct page_extents *pe;
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 < (max_page + NR_GRANT_FRAMES)) {
420 /* Its a grant table access */
421 t = PFN_TYPE_GNTTAB;
422 mfn = gnttab_shared_mfn(d, d->grant_table, (pfn - max_page));
423 } else if (d->is_privileged && cpu_io_mfn(pfn)) {
424 t = PFN_TYPE_IO;
425 mfn = pfn;
426 } else {
427 if (pfn < rma_size_mfn) {
428 t = PFN_TYPE_RMA;
429 mfn = pfn + rma_base_mfn;
430 } else {
431 ulong cur_pfn = rma_size_mfn;
433 list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
434 uint pe_pages = 1UL << pe->order;
435 uint end_pfn = cur_pfn + pe_pages;
437 if (pfn >= cur_pfn && pfn < end_pfn) {
438 t = PFN_TYPE_LOGICAL;
439 mfn = page_to_mfn(pe->pg) + (pfn - cur_pfn);
440 break;
441 }
442 cur_pfn += pe_pages;
443 }
444 }
445 #ifdef DEBUG
446 if (t != PFN_TYPE_NONE &&
447 (d->domain_flags & DOMF_dying) &&
448 page_get_owner(mfn_to_page(mfn)) != d) {
449 printk("%s: page type: %d owner Dom[%d]:%p expected Dom[%d]:%p\n",
450 __func__, t,
451 page_get_owner(mfn_to_page(mfn))->domain_id,
452 page_get_owner(mfn_to_page(mfn)),
453 d->domain_id, d);
454 BUG();
455 }
456 #endif
457 }
459 if (t == PFN_TYPE_NONE) {
460 /* This hack allows dom0 to map all memory, necessary to
461 * initialize domU state. */
462 if (d->is_privileged && mfn_valid(pfn)) {
463 struct page_info *pg;
465 /* page better be allocated to some domain but not the caller */
466 pg = mfn_to_page(pfn);
467 if (!(pg->count_info & PGC_allocated))
468 panic("Foreign page: 0x%lx is not owned by any domain\n",
469 mfn);
470 if (page_get_owner(pg) == d)
471 panic("Foreign page: 0x%lx is owned by this domain\n",
472 mfn);
474 t = PFN_TYPE_FOREIGN;
475 mfn = pfn;
476 }
477 }
479 if (mfn == INVALID_MFN) {
480 printk("%s: Dom[%d] pfn 0x%lx is not a valid page\n",
481 __func__, d->domain_id, pfn);
482 }
484 if (type)
485 *type = t;
487 return mfn;
488 }
490 unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn)
491 {
492 struct page_extents *pe;
493 ulong cur_pfn;
494 ulong gnttab_mfn;
495 ulong rma_mfn;
497 /* grant? */
498 gnttab_mfn = gnttab_shared_mfn(d, d->grant_table, 0);
499 if (mfn >= gnttab_mfn && mfn < (gnttab_mfn + NR_GRANT_FRAMES))
500 return max_page + (mfn - gnttab_mfn);
502 /* IO? */
503 if (d->is_privileged && cpu_io_mfn(mfn))
504 return mfn;
506 rma_mfn = page_to_mfn(d->arch.rma_page);
507 if (mfn >= rma_mfn &&
508 mfn < (rma_mfn + (1 << d->arch.rma_order)))
509 return mfn - rma_mfn;
511 /* Extent? */
512 cur_pfn = 1UL << d->arch.rma_order;
513 list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
514 uint pe_pages = 1UL << pe->order;
515 uint b_mfn = page_to_mfn(pe->pg);
516 uint e_mfn = b_mfn + pe_pages;
518 if (mfn >= b_mfn && mfn < e_mfn) {
519 return cur_pfn + (mfn - b_mfn);
520 }
521 cur_pfn += pe_pages;
522 }
523 return INVALID_M2P_ENTRY;
524 }
526 void guest_physmap_add_page(
527 struct domain *d, unsigned long gpfn, unsigned long mfn)
528 {
529 printk("%s(%d, 0x%lx, 0x%lx)\n", __func__, d->domain_id, gpfn, mfn);
530 }
531 void guest_physmap_remove_page(
532 struct domain *d, unsigned long gpfn, unsigned long mfn)
533 {
534 panic("%s\n", __func__);
535 }
536 void shadow_drop_references(
537 struct domain *d, struct page_info *page)
538 {
539 }
541 int arch_domain_add_extent(struct domain *d, struct page_info *page, int order)
542 {
543 if (add_extent(d, page, order) < 0)
544 return -ENOMEM;
545 return 0;
546 }