|
@@ -36,99 +36,133 @@
|
|
|
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/mm.h>
|
|
|
+#include <linux/slab.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
|
|
#include <xen/interface/xen.h>
|
|
|
#include <xen/page.h>
|
|
|
#include <xen/grant_table.h>
|
|
|
+#include <xen/xen.h>
|
|
|
|
|
|
#include <asm/pgtable.h>
|
|
|
|
|
|
-static int map_pte_fn(pte_t *pte, struct page *pmd_page,
|
|
|
- unsigned long addr, void *data)
|
|
|
+static struct gnttab_vm_area {
|
|
|
+ struct vm_struct *area;
|
|
|
+ pte_t **ptes;
|
|
|
+} gnttab_shared_vm_area, gnttab_status_vm_area;
|
|
|
+
|
|
|
+int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
|
|
|
+ unsigned long max_nr_gframes,
|
|
|
+ void **__shared)
|
|
|
{
|
|
|
- unsigned long **frames = (unsigned long **)data;
|
|
|
+ void *shared = *__shared;
|
|
|
+ unsigned long addr;
|
|
|
+ unsigned long i;
|
|
|
|
|
|
- set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
|
|
|
- (*frames)++;
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ if (shared == NULL)
|
|
|
+ *__shared = shared = gnttab_shared_vm_area.area->addr;
|
|
|
|
|
|
-/*
|
|
|
- * This function is used to map shared frames to store grant status. It is
|
|
|
- * different from map_pte_fn above, the frames type here is uint64_t.
|
|
|
- */
|
|
|
-static int map_pte_fn_status(pte_t *pte, struct page *pmd_page,
|
|
|
- unsigned long addr, void *data)
|
|
|
-{
|
|
|
- uint64_t **frames = (uint64_t **)data;
|
|
|
+ addr = (unsigned long)shared;
|
|
|
+
|
|
|
+ for (i = 0; i < nr_gframes; i++) {
|
|
|
+ set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
|
|
|
+ mfn_pte(frames[i], PAGE_KERNEL));
|
|
|
+ addr += PAGE_SIZE;
|
|
|
+ }
|
|
|
|
|
|
- set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
|
|
|
- (*frames)++;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
|
|
|
- unsigned long addr, void *data)
|
|
|
+int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
|
|
|
+ unsigned long max_nr_gframes,
|
|
|
+ grant_status_t **__shared)
|
|
|
{
|
|
|
+ grant_status_t *shared = *__shared;
|
|
|
+ unsigned long addr;
|
|
|
+ unsigned long i;
|
|
|
+
|
|
|
+ if (shared == NULL)
|
|
|
+ *__shared = shared = gnttab_status_vm_area.area->addr;
|
|
|
+
|
|
|
+ addr = (unsigned long)shared;
|
|
|
+
|
|
|
+ for (i = 0; i < nr_gframes; i++) {
|
|
|
+ set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i],
|
|
|
+ mfn_pte(frames[i], PAGE_KERNEL));
|
|
|
+ addr += PAGE_SIZE;
|
|
|
+ }
|
|
|
|
|
|
- set_pte_at(&init_mm, addr, pte, __pte(0));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
|
|
|
- unsigned long max_nr_gframes,
|
|
|
- void **__shared)
|
|
|
+void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
|
|
|
{
|
|
|
- int rc;
|
|
|
- void *shared = *__shared;
|
|
|
+ pte_t **ptes;
|
|
|
+ unsigned long addr;
|
|
|
+ unsigned long i;
|
|
|
|
|
|
- if (shared == NULL) {
|
|
|
- struct vm_struct *area =
|
|
|
- alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
|
|
|
- BUG_ON(area == NULL);
|
|
|
- shared = area->addr;
|
|
|
- *__shared = shared;
|
|
|
- }
|
|
|
+ if (shared == gnttab_status_vm_area.area->addr)
|
|
|
+ ptes = gnttab_status_vm_area.ptes;
|
|
|
+ else
|
|
|
+ ptes = gnttab_shared_vm_area.ptes;
|
|
|
|
|
|
- rc = apply_to_page_range(&init_mm, (unsigned long)shared,
|
|
|
- PAGE_SIZE * nr_gframes,
|
|
|
- map_pte_fn, &frames);
|
|
|
- return rc;
|
|
|
+ addr = (unsigned long)shared;
|
|
|
+
|
|
|
+ for (i = 0; i < nr_gframes; i++) {
|
|
|
+ set_pte_at(&init_mm, addr, ptes[i], __pte(0));
|
|
|
+ addr += PAGE_SIZE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
|
|
|
- unsigned long max_nr_gframes,
|
|
|
- grant_status_t **__shared)
|
|
|
+static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames)
|
|
|
{
|
|
|
- int rc;
|
|
|
- grant_status_t *shared = *__shared;
|
|
|
+ area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL);
|
|
|
+ if (area->ptes == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- if (shared == NULL) {
|
|
|
- /* No need to pass in PTE as we are going to do it
|
|
|
- * in apply_to_page_range anyhow. */
|
|
|
- struct vm_struct *area =
|
|
|
- alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
|
|
|
- BUG_ON(area == NULL);
|
|
|
- shared = area->addr;
|
|
|
- *__shared = shared;
|
|
|
+ area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes);
|
|
|
+ if (area->area == NULL) {
|
|
|
+ kfree(area->ptes);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- rc = apply_to_page_range(&init_mm, (unsigned long)shared,
|
|
|
- PAGE_SIZE * nr_gframes,
|
|
|
- map_pte_fn_status, &frames);
|
|
|
- return rc;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
|
|
|
+static void arch_gnttab_vfree(struct gnttab_vm_area *area)
|
|
|
+{
|
|
|
+ free_vm_area(area->area);
|
|
|
+ kfree(area->ptes);
|
|
|
+}
|
|
|
+
|
|
|
+int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status)
|
|
|
{
|
|
|
- apply_to_page_range(&init_mm, (unsigned long)shared,
|
|
|
- PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!xen_pv_domain())
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Always allocate the space for the status frames in case
|
|
|
+ * we're migrated to a host with V2 support.
|
|
|
+ */
|
|
|
+ ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status);
|
|
|
+ if (ret < 0)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ err:
|
|
|
+ arch_gnttab_vfree(&gnttab_shared_vm_area);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
+
|
|
|
#ifdef CONFIG_XEN_PVH
|
|
|
#include <xen/balloon.h>
|
|
|
#include <xen/events.h>
|
|
|
-#include <xen/xen.h>
|
|
|
#include <linux/slab.h>
|
|
|
static int __init xlated_setup_gnttab_pages(void)
|
|
|
{
|