/* * This function takes a contiguous pfn range that needs to be identity mapped * and: * * 1) Finds a new range of pfns to use to remap based on E820 and remap_pfn. * 2) Calls the do_ function to actually do the mapping/remapping work. * * The goal is to not allocate additional memory but to remap the existing * pages. In the case of an error the underlying memory is simply released back * to Xen and not remapped. */ static unsigned long __init xen_set_identity_and_remap_chunk( unsigned long start_pfn, unsigned long end_pfn, unsigned long nr_pages, unsigned long remap_pfn) { unsigned long pfn; unsigned long i = 0; unsigned long n = end_pfn - start_pfn; if (remap_pfn == 0) remap_pfn = nr_pages; while (i < n) { unsigned long cur_pfn = start_pfn + i; unsigned long left = n - i; unsigned long size = left; unsigned long remap_range_size; /* Do not remap pages beyond the current allocation */ if (cur_pfn >= nr_pages) { /* Identity map remaining pages */ set_phys_range_identity(cur_pfn, cur_pfn + size); break; } if (cur_pfn + size > nr_pages) size = nr_pages - cur_pfn; remap_range_size = xen_find_pfn_range(&remap_pfn); if (!remap_range_size) { pr_warning("Unable to find available pfn range, not remapping identity pages\n"); xen_set_identity_and_release_chunk(cur_pfn, cur_pfn + left, nr_pages); break; } /* Adjust size to fit in current e820 RAM region */ if (size > remap_range_size) size = remap_range_size; xen_do_set_identity_and_remap_chunk(cur_pfn, size, remap_pfn); /* Update variables to reflect new mappings. */ i += size; remap_pfn += size; } /* * If the PFNs are currently mapped, the VA mapping also needs * to be updated to be 1:1. */ for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++) (void)HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), mfn_pte(pfn, PAGE_KERNEL_IO), 0); return remap_pfn; }
static unsigned long __init xen_set_identity_and_release( const struct e820entry *list, size_t map_size, unsigned long nr_pages) { phys_addr_t start = 0; unsigned long released = 0; unsigned long identity = 0; const struct e820entry *entry; int i; int xlated_phys = xen_feature(XENFEAT_auto_translated_physmap); /* * Combine non-RAM regions and gaps until a RAM region (or the * end of the map) is reached, then set the 1:1 map and * release the pages (if available) in those non-RAM regions. * * The combined non-RAM regions are rounded to a whole number * of pages so any partial pages are accessible via the 1:1 * mapping. This is needed for some BIOSes that put (for * example) the DMI tables in a reserved region that begins on * a non-page boundary. */ for (i = 0, entry = list; i < map_size; i++, entry++) { phys_addr_t end = entry->addr + entry->size; if (entry->type == E820_RAM || i == map_size - 1) { unsigned long start_pfn = PFN_DOWN(start); unsigned long end_pfn = PFN_UP(end); if (entry->type == E820_RAM) end_pfn = PFN_UP(entry->addr); if (start_pfn < end_pfn) { if (xlated_phys) { xen_pvh_adjust_stats(start_pfn, end_pfn, &released, &identity, nr_pages); } else { xen_set_identity_and_release_chunk( start_pfn, end_pfn, nr_pages, &released, &identity); } } start = end; } } if (released) printk(KERN_INFO "Released %lu pages of unused memory\n", released); if (identity) printk(KERN_INFO "Set %ld page(s) to 1-1 mapping\n", identity); return released; }