diff options
Diffstat (limited to 'stubdom/grub')
-rw-r--r-- | stubdom/grub/kexec.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c index 5281d0b194..06bef52ac2 100644 --- a/stubdom/grub/kexec.c +++ b/stubdom/grub/kexec.c @@ -48,6 +48,7 @@ extern void _boot(void); static unsigned long *pages; static unsigned long *pages_mfns; +static xen_pfn_t *pages_moved2pfns; static unsigned long allocated; int pin_table(xc_interface *xc_handle, unsigned int type, unsigned long mfn, @@ -80,6 +81,7 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) 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]; @@ -91,6 +93,18 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to) 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; |