ia64/xen-unstable

view xen/arch/powerpc/mm.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 6b42b8c08731
children f56981f78d73
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/platform.h>
31 #include <asm/string.h>
32 #include <public/arch-powerpc.h>
34 #ifdef VERBOSE
35 #define MEM_LOG(_f, _a...) \
36 printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \
37 current->domain->domain_id , __LINE__ , ## _a )
38 #else
39 #define MEM_LOG(_f, _a...) ((void)0)
40 #endif
42 /* Frame table and its size in pages. */
43 struct page_info *frame_table;
44 unsigned long max_page;
45 unsigned long total_pages;
47 void __init init_frametable(void)
48 {
49 unsigned long p;
50 unsigned long nr_pages;
51 int i;
53 nr_pages = PFN_UP(max_page * sizeof(struct page_info));
55 p = alloc_boot_pages(nr_pages, 1);
56 if (p == 0)
57 panic("Not enough memory for frame table\n");
59 frame_table = (struct page_info *)(p << PAGE_SHIFT);
60 for (i = 0; i < nr_pages; i += 1)
61 clear_page((void *)((p + i) << PAGE_SHIFT));
62 }
64 void share_xen_page_with_guest(
65 struct page_info *page, struct domain *d, int readonly)
66 {
67 if ( page_get_owner(page) == d )
68 return;
70 /* this causes us to leak pages in the Domain and reuslts in
71 * Zombie domains, I think we are missing a piece, until we find
72 * it we disable the following code */
73 set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY);
75 spin_lock(&d->page_alloc_lock);
77 /* The incremented type count pins as writable or read-only. */
78 page->u.inuse.type_info = (readonly ? PGT_none : PGT_writable_page);
79 page->u.inuse.type_info |= PGT_validated | 1;
81 page_set_owner(page, d);
82 wmb(); /* install valid domain ptr before updating refcnt. */
83 ASSERT(page->count_info == 0);
85 /* Only add to the allocation list if the domain isn't dying. */
86 if ( !test_bit(_DOMF_dying, &d->domain_flags) )
87 {
88 page->count_info |= PGC_allocated | 1;
89 if ( unlikely(d->xenheap_pages++ == 0) )
90 get_knownalive_domain(d);
91 list_add_tail(&page->list, &d->xenpage_list);
92 }
94 spin_unlock(&d->page_alloc_lock);
95 }
97 void share_xen_page_with_privileged_guests(
98 struct page_info *page, int readonly)
99 {
100 unimplemented();
101 }
103 static ulong foreign_to_mfn(struct domain *d, ulong pfn)
104 {
106 pfn -= 1UL << cpu_foreign_map_order();
108 BUG_ON(pfn >= d->arch.foreign_mfn_count);
110 return d->arch.foreign_mfns[pfn];
111 }
113 static int set_foreign(struct domain *d, ulong pfn, ulong mfn)
114 {
115 pfn -= 1UL << cpu_foreign_map_order();
117 BUG_ON(pfn >= d->arch.foreign_mfn_count);
118 d->arch.foreign_mfns[pfn] = mfn;
120 return 0;
121 }
123 static int create_grant_va_mapping(
124 unsigned long va, unsigned long frame, struct vcpu *v)
125 {
126 if (v->domain->domain_id != 0) {
127 printk("only Dom0 can map a grant entry\n");
128 BUG();
129 return GNTST_permission_denied;
130 }
131 set_foreign(v->domain, va >> PAGE_SHIFT, frame);
132 return GNTST_okay;
133 }
135 static int destroy_grant_va_mapping(
136 unsigned long addr, unsigned long frame, struct domain *d)
137 {
138 if (d->domain_id != 0) {
139 printk("only Dom0 can map a grant entry\n");
140 BUG();
141 return GNTST_permission_denied;
142 }
143 set_foreign(d, addr >> PAGE_SHIFT, ~0UL);
144 return GNTST_okay;
145 }
147 int create_grant_host_mapping(
148 unsigned long addr, unsigned long frame, unsigned int flags)
149 {
150 if (flags & GNTMAP_application_map) {
151 printk("%s: GNTMAP_application_map not supported\n", __func__);
152 BUG();
153 return GNTST_general_error;
154 }
155 if (flags & GNTMAP_contains_pte) {
156 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
157 BUG();
158 return GNTST_general_error;
159 }
160 return create_grant_va_mapping(addr, frame, current);
161 }
163 int destroy_grant_host_mapping(
164 unsigned long addr, unsigned long frame, unsigned int flags)
165 {
166 if (flags & GNTMAP_contains_pte) {
167 printk("%s: GNTMAP_contains_pte not supported\n", __func__);
168 BUG();
169 return GNTST_general_error;
170 }
172 /* may have force the remove here */
173 return destroy_grant_va_mapping(addr, frame, current->domain);
174 }
176 int steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
177 {
178 panic("%s called\n", __func__);
179 return 1;
180 }
182 void put_page_type(struct page_info *page)
183 {
184 unsigned long nx, x, y = page->u.inuse.type_info;
186 do {
187 x = y;
188 nx = x - 1;
190 ASSERT((x & PGT_count_mask) != 0);
192 /*
193 * The page should always be validated while a reference is held. The
194 * exception is during domain destruction, when we forcibly invalidate
195 * page-table pages if we detect a referential loop.
196 * See domain.c:relinquish_list().
197 */
198 ASSERT((x & PGT_validated) ||
199 test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
201 if ( unlikely((nx & PGT_count_mask) == 0) )
202 {
203 /* Record TLB information for flush later. */
204 page->tlbflush_timestamp = tlbflush_current_time();
205 }
206 }
207 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
208 }
211 int get_page_type(struct page_info *page, unsigned long type)
212 {
213 unsigned long nx, x, y = page->u.inuse.type_info;
215 ASSERT(!(type & ~PGT_type_mask));
217 again:
218 do {
219 x = y;
220 nx = x + 1;
221 if ( unlikely((nx & PGT_count_mask) == 0) )
222 {
223 MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page));
224 return 0;
225 }
226 else if ( unlikely((x & PGT_count_mask) == 0) )
227 {
228 if ( (x & PGT_type_mask) != type )
229 {
230 /*
231 * On type change we check to flush stale TLB entries. This
232 * may be unnecessary (e.g., page was GDT/LDT) but those
233 * circumstances should be very rare.
234 */
235 cpumask_t mask =
236 page_get_owner(page)->domain_dirty_cpumask;
237 tlbflush_filter(mask, page->tlbflush_timestamp);
239 if ( unlikely(!cpus_empty(mask)) )
240 {
241 perfc_incrc(need_flush_tlb_flush);
242 flush_tlb_mask(mask);
243 }
245 /* We lose existing type, back pointer, and validity. */
246 nx &= ~(PGT_type_mask | PGT_validated);
247 nx |= type;
249 /* No special validation needed for writable pages. */
250 /* Page tables and GDT/LDT need to be scanned for validity. */
251 if ( type == PGT_writable_page )
252 nx |= PGT_validated;
253 }
254 }
255 else if ( unlikely((x & PGT_type_mask) != type) )
256 {
257 return 0;
258 }
259 else if ( unlikely(!(x & PGT_validated)) )
260 {
261 /* Someone else is updating validation of this page. Wait... */
262 while ( (y = page->u.inuse.type_info) == x )
263 cpu_relax();
264 goto again;
265 }
266 }
267 while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
269 if ( unlikely(!(nx & PGT_validated)) )
270 {
271 /* Noone else is updating simultaneously. */
272 __set_bit(_PGT_validated, &page->u.inuse.type_info);
273 }
275 return 1;
276 }
278 long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
279 {
280 printk("%s: no PPC specific memory ops\n", __func__);
281 return -ENOSYS;
282 }
284 extern void copy_page(void *dp, void *sp)
285 {
286 if (on_systemsim()) {
287 systemsim_memcpy(dp, sp, PAGE_SIZE);
288 } else {
289 memcpy(dp, sp, PAGE_SIZE);
290 }
291 }
293 /* XXX should probably replace with faster data structure */
294 static uint add_extent(struct domain *d, struct page_info *pg, uint order)
295 {
296 struct page_extents *pe;
298 pe = xmalloc(struct page_extents);
299 if (pe == NULL)
300 return -ENOMEM;
302 pe->pg = pg;
303 pe->order = order;
305 list_add_tail(&pe->pe_list, &d->arch.extent_list);
307 return 0;
308 }
310 void free_extents(struct domain *d)
311 {
312 /* we just need to free the memory behind list */
313 struct list_head *list;
314 struct list_head *ent;
315 struct list_head *next;
317 list = &d->arch.extent_list;
318 ent = list->next;
320 while (ent != list) {
321 next = ent->next;
322 xfree(ent);
323 ent = next;
324 }
325 }
327 uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages)
328 {
329 uint ext_order;
330 uint ext_nrpages;
331 uint total_nrpages;
332 struct page_info *pg;
334 ext_order = cpu_extent_order();
335 ext_nrpages = 1 << ext_order;
337 total_nrpages = rma_nrpages;
339 /* We only allocate in nr_extsz chunks so if you are not divisible
340 * you get more than you asked for */
341 while (total_nrpages < nrpages) {
342 pg = alloc_domheap_pages(d, ext_order, 0);
343 if (pg == NULL)
344 return total_nrpages;
346 if (add_extent(d, pg, ext_order) < 0) {
347 free_domheap_pages(pg, ext_order);
348 return total_nrpages;
349 }
350 total_nrpages += ext_nrpages;
351 }
353 return total_nrpages;
354 }
356 int allocate_rma(struct domain *d, unsigned int order)
357 {
358 struct vcpu *v;
359 ulong rma_base;
360 ulong rma_sz;
361 int i;
363 if (d->arch.rma_page)
364 return -EINVAL;
366 d->arch.rma_page = alloc_domheap_pages(d, order, 0);
367 if (d->arch.rma_page == NULL) {
368 gdprintk(XENLOG_INFO, "Could not allocate order=%d RMA for domain %u\n",
369 order, d->domain_id);
370 return -ENOMEM;
371 }
372 d->arch.rma_order = order;
374 rma_base = page_to_maddr(d->arch.rma_page);
375 rma_sz = rma_size(d->arch.rma_order);
377 BUG_ON(rma_base & (rma_sz - 1)); /* check alignment */
379 printk("allocated RMA for Dom[%d]: 0x%lx[0x%lx]\n",
380 d->domain_id, rma_base, rma_sz);
382 for (i = 0; i < (1 << d->arch.rma_order); i++ ) {
383 /* Add in any extra CPUs that need flushing because of this page. */
384 d->arch.rma_page[i].count_info |= PGC_page_RMA;
385 clear_page((void *)page_to_maddr(&d->arch.rma_page[i]));
386 }
388 /* shared_info uses last page of RMA */
389 d->shared_info = (shared_info_t *) (rma_base + rma_sz - PAGE_SIZE);
391 /* if there are already running vcpus, adjust v->vcpu_info */
392 /* XXX untested */
393 for_each_vcpu(d, v) {
394 v->vcpu_info = &d->shared_info->vcpu_info[v->vcpu_id];
395 }
397 return 0;
398 }
400 void free_rma_check(struct page_info *page)
401 {
402 if (test_bit(_PGC_page_RMA, &page->count_info) &&
403 !test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags))
404 panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
405 }
407 ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
408 {
409 ulong rma_base_mfn = page_to_mfn(d->arch.rma_page);
410 ulong rma_size_mfn = 1UL << d->arch.rma_order;
411 struct page_extents *pe;
412 ulong mfn = INVALID_MFN;
413 int t = PFN_TYPE_NONE;
414 ulong foreign_map_pfn = 1UL << cpu_foreign_map_order();
416 /* quick tests first */
417 if (pfn & foreign_map_pfn) {
418 t = PFN_TYPE_FOREIGN;
419 mfn = foreign_to_mfn(d, pfn);
420 } else if (pfn >= max_page && pfn <
421 (max_page + nr_grant_frames(d->grant_table))) {
422 /* XXX access d->grant_table->nr_grant_frames without lock.
423 * Currently on powerpc dynamic expanding grant table is
424 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
425 * so that this access is safe.
426 */
427 /* Its a grant table access */
428 t = PFN_TYPE_GNTTAB;
429 mfn = gnttab_shared_mfn(d, d->grant_table, (pfn - max_page));
430 } else if (d->is_privileged && platform_io_mfn(pfn)) {
431 t = PFN_TYPE_IO;
432 mfn = pfn;
433 } else {
434 if (pfn < rma_size_mfn) {
435 t = PFN_TYPE_RMA;
436 mfn = pfn + rma_base_mfn;
437 } else {
438 ulong cur_pfn = rma_size_mfn;
440 list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
441 uint pe_pages = 1UL << pe->order;
442 uint end_pfn = cur_pfn + pe_pages;
444 if (pfn >= cur_pfn && pfn < end_pfn) {
445 t = PFN_TYPE_LOGICAL;
446 mfn = page_to_mfn(pe->pg) + (pfn - cur_pfn);
447 break;
448 }
449 cur_pfn += pe_pages;
450 }
451 }
452 #ifdef DEBUG
453 if (t != PFN_TYPE_NONE &&
454 (d->domain_flags & DOMF_dying) &&
455 page_get_owner(mfn_to_page(mfn)) != d) {
456 printk("%s: page type: %d owner Dom[%d]:%p expected Dom[%d]:%p\n",
457 __func__, t,
458 page_get_owner(mfn_to_page(mfn))->domain_id,
459 page_get_owner(mfn_to_page(mfn)),
460 d->domain_id, d);
461 BUG();
462 }
463 #endif
464 }
466 if (t == PFN_TYPE_NONE) {
467 /* This hack allows dom0 to map all memory, necessary to
468 * initialize domU state. */
469 if (d->is_privileged && mfn_valid(pfn)) {
470 struct page_info *pg;
472 /* page better be allocated to some domain but not the caller */
473 pg = mfn_to_page(pfn);
474 if (!(pg->count_info & PGC_allocated))
475 panic("Foreign page: 0x%lx is not owned by any domain\n",
476 mfn);
477 if (page_get_owner(pg) == d)
478 panic("Foreign page: 0x%lx is owned by this domain\n",
479 mfn);
481 t = PFN_TYPE_FOREIGN;
482 mfn = pfn;
483 }
484 }
486 if (mfn == INVALID_MFN) {
487 printk("%s: Dom[%d] pfn 0x%lx is not a valid page\n",
488 __func__, d->domain_id, pfn);
489 }
491 if (type)
492 *type = t;
494 return mfn;
495 }
497 unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn)
498 {
499 struct page_extents *pe;
500 ulong cur_pfn;
501 ulong gnttab_mfn;
502 ulong rma_mfn;
504 /* XXX access d->grant_table->nr_grant_frames without lock.
505 * Currently on powerpc dynamic expanding grant table is
506 * inhibited by setting max_nr_grant_frames = INITIAL_NR_GRANT_FRAMES
507 * so that this access is safe.
508 */
509 /* grant? */
510 gnttab_mfn = gnttab_shared_mfn(d, d->grant_table, 0);
511 if (mfn >= gnttab_mfn && mfn <
512 (gnttab_mfn + nr_grant_frames(d->grant_table)))
513 return max_page + (mfn - gnttab_mfn);
515 /* IO? */
516 if (d->is_privileged && platform_io_mfn(mfn))
517 return mfn;
519 rma_mfn = page_to_mfn(d->arch.rma_page);
520 if (mfn >= rma_mfn &&
521 mfn < (rma_mfn + (1 << d->arch.rma_order)))
522 return mfn - rma_mfn;
524 /* Extent? */
525 cur_pfn = 1UL << d->arch.rma_order;
526 list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
527 uint pe_pages = 1UL << pe->order;
528 uint b_mfn = page_to_mfn(pe->pg);
529 uint e_mfn = b_mfn + pe_pages;
531 if (mfn >= b_mfn && mfn < e_mfn) {
532 return cur_pfn + (mfn - b_mfn);
533 }
534 cur_pfn += pe_pages;
535 }
536 return INVALID_M2P_ENTRY;
537 }
539 void guest_physmap_add_page(
540 struct domain *d, unsigned long gpfn, unsigned long mfn)
541 {
542 printk("%s(%d, 0x%lx, 0x%lx)\n", __func__, d->domain_id, gpfn, mfn);
543 }
544 void guest_physmap_remove_page(
545 struct domain *d, unsigned long gpfn, unsigned long mfn)
546 {
547 panic("%s\n", __func__);
548 }
549 void shadow_drop_references(
550 struct domain *d, struct page_info *page)
551 {
552 }
554 int arch_domain_add_extent(struct domain *d, struct page_info *page, int order)
555 {
556 if (add_extent(d, page, order) < 0)
557 return -ENOMEM;
558 return 0;
559 }