Skip to content

Commit

Permalink
Merge tag 'for-linus-5.17-rc1-tag' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:

 - a fix for the Xen gntdev driver

 - a fix for running as Xen dom0 booted via EFI and the EFI framebuffer
   being located above 4GB

 - a series for support of mapping other guest's memory by using zone
   device when running as Xen guest on Arm

* tag 'for-linus-5.17-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  dt-bindings: xen: Clarify "reg" purpose
  arm/xen: Read extended regions from DT and init Xen resource
  xen/unpopulated-alloc: Add mechanism to use Xen resource
  xen/balloon: Bring alloc(free)_xenballooned_pages helpers back
  arm/xen: Switch to use gnttab_setup_auto_xlat_frames() for DT
  xen/unpopulated-alloc: Drop check for virt_addr_valid() in fill_list()
  xen/x86: obtain upper 32 bits of video frame buffer address for Dom0
  xen/gntdev: fix unmap notification order
  • Loading branch information
Linus Torvalds committed Jan 13, 2022
2 parents 64ad946 + 54bb4a9 commit ce990f1
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 36 deletions.
14 changes: 8 additions & 6 deletions Documentation/devicetree/bindings/arm/xen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ the following properties:
compatible = "xen,xen-<version>", "xen,xen";
where <version> is the version of the Xen ABI of the platform.

- reg: specifies the base physical address and size of a region in
memory where the grant table should be mapped to, using an
HYPERVISOR_memory_op hypercall. The memory region is large enough to map
the whole grant table (it is larger or equal to gnttab_max_grant_frames()).
This property is unnecessary when booting Dom0 using ACPI.
- reg: specifies the base physical address and size of the regions in memory
where the special resources should be mapped to, using an HYPERVISOR_memory_op
hypercall.
Region 0 is reserved for mapping grant table, it must be always present.
The memory region is large enough to map the whole grant table (it is larger
or equal to gnttab_max_grant_frames()).
Regions 1...N are extended regions (unused address space) for mapping foreign
GFNs and grants, they might be absent if there is nothing to expose.

- interrupts: the interrupt used by Xen to inject event notifications.
A GIC node is also required.
This property is unnecessary when booting Dom0 using ACPI.

To support UEFI on Xen ARM virtual platforms, Xen populates the FDT "uefi" node
under /hypervisor with following parameters:
Expand Down
132 changes: 126 additions & 6 deletions arch/arm/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ unsigned long xen_released_pages;
struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;

static __read_mostly unsigned int xen_events_irq;
static __read_mostly phys_addr_t xen_grant_frames;

#define GRANT_TABLE_INDEX 0
#define EXT_REGION_INDEX 1

uint32_t xen_start_flags;
EXPORT_SYMBOL(xen_start_flags);
Expand Down Expand Up @@ -300,9 +304,115 @@ static void __init xen_acpi_guest_init(void)
#endif
}

#ifdef CONFIG_XEN_UNPOPULATED_ALLOC
/*
* A type-less specific Xen resource which contains extended regions
* (unused regions of guest physical address space provided by the hypervisor).
*/
static struct resource xen_resource = {
.name = "Xen unused space",
};

int __init arch_xen_unpopulated_init(struct resource **res)
{
struct device_node *np;
struct resource *regs, *tmp_res;
uint64_t min_gpaddr = -1, max_gpaddr = 0;
unsigned int i, nr_reg = 0;
int rc;

if (!xen_domain())
return -ENODEV;

if (!acpi_disabled)
return -ENODEV;

np = of_find_compatible_node(NULL, NULL, "xen,xen");
if (WARN_ON(!np))
return -ENODEV;

/* Skip region 0 which is reserved for grant table space */
while (of_get_address(np, nr_reg + EXT_REGION_INDEX, NULL, NULL))
nr_reg++;

if (!nr_reg) {
pr_err("No extended regions are found\n");
return -EINVAL;
}

regs = kcalloc(nr_reg, sizeof(*regs), GFP_KERNEL);
if (!regs)
return -ENOMEM;

/*
* Create resource from extended regions provided by the hypervisor to be
* used as unused address space for Xen scratch pages.
*/
for (i = 0; i < nr_reg; i++) {
rc = of_address_to_resource(np, i + EXT_REGION_INDEX, &regs[i]);
if (rc)
goto err;

if (max_gpaddr < regs[i].end)
max_gpaddr = regs[i].end;
if (min_gpaddr > regs[i].start)
min_gpaddr = regs[i].start;
}

xen_resource.start = min_gpaddr;
xen_resource.end = max_gpaddr;

/*
* Mark holes between extended regions as unavailable. The rest of that
* address space will be available for the allocation.
*/
for (i = 1; i < nr_reg; i++) {
resource_size_t start, end;

/* There is an overlap between regions */
if (regs[i - 1].end + 1 > regs[i].start) {
rc = -EINVAL;
goto err;
}

/* There is no hole between regions */
if (regs[i - 1].end + 1 == regs[i].start)
continue;

start = regs[i - 1].end + 1;
end = regs[i].start - 1;

tmp_res = kzalloc(sizeof(*tmp_res), GFP_KERNEL);
if (!tmp_res) {
rc = -ENOMEM;
goto err;
}

tmp_res->name = "Unavailable space";
tmp_res->start = start;
tmp_res->end = end;

rc = insert_resource(&xen_resource, tmp_res);
if (rc) {
pr_err("Cannot insert resource %pR (%d)\n", tmp_res, rc);
kfree(tmp_res);
goto err;
}
}

*res = &xen_resource;

err:
kfree(regs);

return rc;
}
#endif

static void __init xen_dt_guest_init(void)
{
struct device_node *xen_node;
struct resource res;

xen_node = of_find_compatible_node(NULL, NULL, "xen,xen");
if (!xen_node) {
Expand All @@ -311,13 +421,19 @@ static void __init xen_dt_guest_init(void)
}

xen_events_irq = irq_of_parse_and_map(xen_node, 0);

if (of_address_to_resource(xen_node, GRANT_TABLE_INDEX, &res)) {
pr_err("Xen grant table region is not found\n");
return;
}
xen_grant_frames = res.start;
}

static int __init xen_guest_init(void)
{
struct xen_add_to_physmap xatp;
struct shared_info *shared_info_page = NULL;
int cpu;
int rc, cpu;

if (!xen_domain())
return 0;
Expand Down Expand Up @@ -370,12 +486,16 @@ static int __init xen_guest_init(void)
for_each_possible_cpu(cpu)
per_cpu(xen_vcpu_id, cpu) = cpu;

xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames();
if (xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn,
&xen_auto_xlat_grant_frames.vaddr,
xen_auto_xlat_grant_frames.count)) {
if (!xen_grant_frames) {
xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames();
rc = xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn,
&xen_auto_xlat_grant_frames.vaddr,
xen_auto_xlat_grant_frames.count);
} else
rc = gnttab_setup_auto_xlat_frames(xen_grant_frames);
if (rc) {
free_percpu(xen_vcpu_info);
return -ENOMEM;
return rc;
}
gnttab_init();

Expand Down
12 changes: 8 additions & 4 deletions arch/x86/xen/vga.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,18 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
break;
}

if (size >= offsetof(struct dom0_vga_console_info,
u.vesa_lfb.gbl_caps)
+ sizeof(info->u.vesa_lfb.gbl_caps))
screen_info->capabilities = info->u.vesa_lfb.gbl_caps;
if (size >= offsetof(struct dom0_vga_console_info,
u.vesa_lfb.mode_attrs)
+ sizeof(info->u.vesa_lfb.mode_attrs))
screen_info->vesa_attributes = info->u.vesa_lfb.mode_attrs;

if (size >= offsetof(struct dom0_vga_console_info,
u.vesa_lfb.ext_lfb_base)
+ sizeof(info->u.vesa_lfb.ext_lfb_base)
&& info->u.vesa_lfb.ext_lfb_base) {
screen_info->ext_lfb_base = info->u.vesa_lfb.ext_lfb_base;
screen_info->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
}
break;
}
}
2 changes: 1 addition & 1 deletion drivers/xen/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ config XEN_FRONT_PGDIR_SHBUF

config XEN_UNPOPULATED_ALLOC
bool "Use unpopulated memory ranges for guest mappings"
depends on X86 && ZONE_DEVICE
depends on ZONE_DEVICE
default XEN_BACKEND || XEN_GNTDEV || XEN_DOM0
help
Use unpopulated memory ranges in order to create mappings for guest
Expand Down
20 changes: 9 additions & 11 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,6 @@ void balloon_set_new_target(unsigned long target)
}
EXPORT_SYMBOL_GPL(balloon_set_new_target);

#ifndef CONFIG_XEN_UNPOPULATED_ALLOC
static int add_ballooned_pages(unsigned int nr_pages)
{
enum bp_state st;
Expand Down Expand Up @@ -610,12 +609,12 @@ static int add_ballooned_pages(unsigned int nr_pages)
}

/**
* xen_alloc_unpopulated_pages - get pages that have been ballooned out
* xen_alloc_ballooned_pages - get pages that have been ballooned out
* @nr_pages: Number of pages to get
* @pages: pages returned
* @return 0 on success, error otherwise
*/
int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages)
int xen_alloc_ballooned_pages(unsigned int nr_pages, struct page **pages)
{
unsigned int pgno = 0;
struct page *page;
Expand Down Expand Up @@ -652,23 +651,23 @@ int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages)
return 0;
out_undo:
mutex_unlock(&balloon_mutex);
xen_free_unpopulated_pages(pgno, pages);
xen_free_ballooned_pages(pgno, pages);
/*
* NB: free_xenballooned_pages will only subtract pgno pages, but since
* NB: xen_free_ballooned_pages will only subtract pgno pages, but since
* target_unpopulated is incremented with nr_pages at the start we need
* to remove the remaining ones also, or accounting will be screwed.
*/
balloon_stats.target_unpopulated -= nr_pages - pgno;
return ret;
}
EXPORT_SYMBOL(xen_alloc_unpopulated_pages);
EXPORT_SYMBOL(xen_alloc_ballooned_pages);

/**
* xen_free_unpopulated_pages - return pages retrieved with get_ballooned_pages
* xen_free_ballooned_pages - return pages retrieved with get_ballooned_pages
* @nr_pages: Number of pages
* @pages: pages to return
*/
void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages)
void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages)
{
unsigned int i;

Expand All @@ -687,9 +686,9 @@ void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages)

mutex_unlock(&balloon_mutex);
}
EXPORT_SYMBOL(xen_free_unpopulated_pages);
EXPORT_SYMBOL(xen_free_ballooned_pages);

#if defined(CONFIG_XEN_PV)
#if defined(CONFIG_XEN_PV) && !defined(CONFIG_XEN_UNPOPULATED_ALLOC)
static void __init balloon_add_region(unsigned long start_pfn,
unsigned long pages)
{
Expand All @@ -712,7 +711,6 @@ static void __init balloon_add_region(unsigned long start_pfn,
balloon_stats.total_pages += extra_pfn_end - start_pfn;
}
#endif
#endif

static int __init balloon_init(void)
{
Expand Down
6 changes: 3 additions & 3 deletions drivers/xen/gntdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,13 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map)
if (!refcount_dec_and_test(&map->users))
return;

if (map->pages && !use_ptemod)
unmap_grant_pages(map, 0, map->count);

if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
notify_remote_via_evtchn(map->notify.event);
evtchn_put(map->notify.event);
}

if (map->pages && !use_ptemod)
unmap_grant_pages(map, 0, map->count);
gntdev_free_map(map);
}

Expand Down
Loading

0 comments on commit ce990f1

Please sign in to comment.