// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include #include static DEFINE_MUTEX(list_lock); static LIST_HEAD(page_list); static unsigned int list_count; static int fill_list(unsigned int nr_pages) { struct dev_pagemap *pgmap; struct resource *res; void *vaddr; unsigned int i, alloc_pages = round_up(nr_pages, PAGES_PER_SECTION); int ret = -ENOMEM; res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) return -ENOMEM; pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL); if (!pgmap) goto err_pgmap; pgmap->type = MEMORY_DEVICE_GENERIC; res->name = "Xen scratch"; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; ret = allocate_resource(&iomem_resource, res, alloc_pages * PAGE_SIZE, 0, -1, PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); if (ret < 0) { pr_err("Cannot allocate new IOMEM resource\n"); goto err_resource; } pgmap->range = (struct range) { .start = res->start, .end = res->end, }; pgmap->nr_range = 1; pgmap->owner = res; #ifdef CONFIG_XEN_HAVE_PVMMU /* * memremap will build page tables for the new memory so * the p2m must contain invalid entries so the correct * non-present PTEs will be written. * * If a failure occurs, the original (identity) p2m entries * are not restored since this region is now known not to * conflict with any devices. */ if (!xen_feature(XENFEAT_auto_translated_physmap)) { xen_pfn_t pfn = PFN_DOWN(res->start); for (i = 0; i < alloc_pages; i++) { if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) { pr_warn("set_phys_to_machine() failed, no memory added\n"); ret = -ENOMEM; goto err_memremap; } } } #endif vaddr = memremap_pages(pgmap, NUMA_NO_NODE); if (IS_ERR(vaddr)) { pr_err("Cannot remap memory range\n"); ret = PTR_ERR(vaddr); goto err_memremap; } for (i = 0; i < alloc_pages; i++) { struct page *pg = virt_to_page(vaddr + PAGE_SIZE * i); BUG_ON(!virt_addr_valid(vaddr + PAGE_SIZE * i)); list_add(&pg->lru, &page_list); list_count++; } return 0; err_memremap: release_resource(res); err_resource: kfree(pgmap); err_pgmap: kfree(res); return ret; } /** * xen_alloc_unpopulated_pages - alloc unpopulated pages * @nr_pages: Number of pages * @pages: pages returned * @return 0 on success, error otherwise */ int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages) { unsigned int i; int ret = 0; mutex_lock(&list_lock); if (list_count < nr_pages) { ret = fill_list(nr_pages - list_count); if (ret) goto out; } for (i = 0; i < nr_pages; i++) { struct page *pg = list_first_entry_or_null(&page_list, struct page, lru); BUG_ON(!pg); list_del(&pg->lru); list_count--; pages[i] = pg; #ifdef CONFIG_XEN_HAVE_PVMMU if (!xen_feature(XENFEAT_auto_translated_physmap)) { ret = xen_alloc_p2m_entry(page_to_pfn(pg)); if (ret < 0) { unsigned int j; for (j = 0; j <= i; j++) { list_add(&pages[j]->lru, &page_list); list_count++; } goto out; } } #endif } out: mutex_unlock(&list_lock); return ret; } EXPORT_SYMBOL(xen_alloc_unpopulated_pages); /** * xen_free_unpopulated_pages - return unpopulated pages * @nr_pages: Number of pages * @pages: pages to return */ void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages) { unsigned int i; mutex_lock(&list_lock); for (i = 0; i < nr_pages; i++) { list_add(&pages[i]->lru, &page_list); list_count++; } mutex_unlock(&list_lock); } EXPORT_SYMBOL(xen_free_unpopulated_pages); #ifdef CONFIG_XEN_PV static int __init init(void) { unsigned int i; if (!xen_domain()) return -ENODEV; if (!xen_pv_domain()) return 0; /* * Initialize with pages from the extra memory regions (see * arch/x86/xen/setup.c). */ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { unsigned int j; for (j = 0; j < xen_extra_mem[i].n_pfns; j++) { struct page *pg = pfn_to_page(xen_extra_mem[i].start_pfn + j); list_add(&pg->lru, &page_list); list_count++; } } return 0; } subsys_initcall(init); #endif