/* Allocate 2^@order contiguous pages. Returns a VIRTUAL address. */ unsigned long alloc_pages(int order) { int i; chunk_head_t *alloc_ch, *spare_ch; chunk_tail_t *spare_ct; /* Find smallest order which can satisfy the request. */ for ( i = order; i < FREELIST_SIZE; i++ ) { if ( !FREELIST_EMPTY(free_head[i]) ) break; } if ( i == FREELIST_SIZE ) goto no_memory; /* Unlink a chunk. */ alloc_ch = free_head[i]; free_head[i] = alloc_ch->next; alloc_ch->next->pprev = alloc_ch->pprev; /* We may have to break the chunk a number of times. */ while ( i != order ) { /* Split into two equal parts. */ i--; spare_ch = (chunk_head_t *)((char *)alloc_ch + (1UL<<(i+PAGE_SHIFT))); spare_ct = (chunk_tail_t *)((char *)spare_ch + (1UL<<(i+PAGE_SHIFT)))-1; /* Create new header for spare chunk. */ spare_ch->level = i; spare_ch->next = free_head[i]; spare_ch->pprev = &free_head[i]; spare_ct->level = i; /* Link in the spare chunk. */ spare_ch->next->pprev = &spare_ch->next; free_head[i] = spare_ch; } map_alloc(PHYS_PFN(to_phys(alloc_ch)), 1UL<<order); return((unsigned long)alloc_ch); no_memory: printk("Cannot handle page request order %d!\n", order); return 0; }
int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) { unsigned long new_allocated = (up_to - dom->parms.virt_base) / PAGE_SIZE; unsigned long i; pages = realloc(pages, new_allocated * sizeof(*pages)); pages_mfns = realloc(pages_mfns, new_allocated * sizeof(*pages_mfns)); pages_moved2pfns = realloc(pages_moved2pfns, new_allocated * sizeof(*pages_moved2pfns)); for (i = allocated; i < new_allocated; i++) { /* Exchange old page of PFN i with a newly allocated page. */ xen_pfn_t old_mfn = dom->p2m_host[i]; xen_pfn_t new_pfn; xen_pfn_t new_mfn; pages[i] = alloc_page(); memset((void*) pages[i], 0, PAGE_SIZE); new_pfn = PHYS_PFN(to_phys(pages[i])); pages_mfns[i] = new_mfn = pfn_to_mfn(new_pfn); /* * If PFN of newly allocated page (new_pfn) is less then currently * requested PFN (i) then look for relevant PFN/MFN pair. In this * situation dom->p2m_host[new_pfn] no longer contains proper MFN * because original page with new_pfn was moved earlier * to different location. */ for (; new_pfn < i; new_pfn = pages_moved2pfns[new_pfn]); /* Store destination PFN of currently requested page. */ pages_moved2pfns[i] = new_pfn; /* Put old page at new PFN */ dom->p2m_host[new_pfn] = old_mfn; /* Put new page at PFN i */ dom->p2m_host[i] = new_mfn; } allocated = new_allocated; return 0; }