262 lines
7.7 KiB
Diff
262 lines
7.7 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jason Chen CJ <jason.cj.chen@intel.com>
|
|
Date: Fri, 31 Aug 2018 10:59:00 +0800
|
|
Subject: [PATCH] VHM: add hugetlb page ept mapping support
|
|
|
|
unlike cma, hugetlb allocates hugepage under user space, so VHM only
|
|
need take care of ept mapping for these allocated huge pages.
|
|
this patch add hugepage_map_guest function, it gets huge page struct
|
|
pointer according to user virtual address input from ioctl IC_SET_MEMSEG,
|
|
then build all required parameters for recording guest memseg and mapping
|
|
ept entry through this page struct.
|
|
|
|
Change-Id: I0b333613dc20fce41b9b091c72892bbac6b07735
|
|
Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com>
|
|
Reviewed-on:
|
|
---
|
|
drivers/char/vhm/vhm_dev.c | 1 +
|
|
drivers/vhm/Kconfig | 1 +
|
|
drivers/vhm/vhm_mm.c | 101 +++++++++++++++++++++++++----
|
|
include/linux/vhm/vhm_ioctl_defs.h | 27 +++++---
|
|
include/linux/vhm/vhm_vm_mngt.h | 1 +
|
|
5 files changed, 110 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/drivers/char/vhm/vhm_dev.c b/drivers/char/vhm/vhm_dev.c
|
|
index 8590d69..8d083a0 100644
|
|
--- a/drivers/char/vhm/vhm_dev.c
|
|
+++ b/drivers/char/vhm/vhm_dev.c
|
|
@@ -129,6 +129,7 @@ static int vhm_dev_open(struct inode *inodep, struct file *filep)
|
|
|
|
vm_mutex_lock(&vhm_vm_list_lock);
|
|
vm->refcnt = 1;
|
|
+ vm->hugetlb_enabled = 0;
|
|
vm_list_add(&vm->list);
|
|
vm_mutex_unlock(&vhm_vm_list_lock);
|
|
filep->private_data = vm;
|
|
diff --git a/drivers/vhm/Kconfig b/drivers/vhm/Kconfig
|
|
index e59b948..4ddb131 100644
|
|
--- a/drivers/vhm/Kconfig
|
|
+++ b/drivers/vhm/Kconfig
|
|
@@ -3,6 +3,7 @@ config ACRN_VHM
|
|
depends on ACRN
|
|
depends on DMA_CMA
|
|
depends on PCI_MSI
|
|
+ depends on HUGETLBFS
|
|
depends on !VMAP_STACK
|
|
default n
|
|
---help---
|
|
diff --git a/drivers/vhm/vhm_mm.c b/drivers/vhm/vhm_mm.c
|
|
index be6a47a..cc08fd9 100644
|
|
--- a/drivers/vhm/vhm_mm.c
|
|
+++ b/drivers/vhm/vhm_mm.c
|
|
@@ -110,31 +110,25 @@ static bool _free_memblk(struct device *dev, u64 vm0_gpa, size_t len)
|
|
return dma_release_from_contiguous(dev, page, count);
|
|
}
|
|
|
|
-int alloc_guest_memseg(struct vhm_vm *vm, struct vm_memseg *memseg)
|
|
+static int add_guest_memseg(struct vhm_vm *vm, unsigned long vm0_gpa,
|
|
+ unsigned long guest_gpa, unsigned long len)
|
|
{
|
|
struct guest_memseg *seg;
|
|
- u64 vm0_gpa;
|
|
int max_gfn;
|
|
|
|
seg = kzalloc(sizeof(struct guest_memseg), GFP_KERNEL);
|
|
if (seg == NULL)
|
|
return -ENOMEM;
|
|
|
|
- vm0_gpa = _alloc_memblk(vm->dev, memseg->len);
|
|
- if (vm0_gpa == 0ULL) {
|
|
- kfree(seg);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
seg->vm0_gpa = vm0_gpa;
|
|
- seg->len = memseg->len;
|
|
- seg->gpa = memseg->gpa;
|
|
+ seg->gpa = guest_gpa;
|
|
+ seg->len = len;
|
|
|
|
max_gfn = (seg->gpa + seg->len) >> PAGE_SHIFT;
|
|
if (vm->max_gfn < max_gfn)
|
|
vm->max_gfn = max_gfn;
|
|
|
|
- pr_info("VHM: alloc memseg with len=0x%lx, vm0_gpa=0x%llx,"
|
|
+ pr_info("VHM: add memseg with len=0x%lx, vm0_gpa=0x%llx,"
|
|
" and its guest gpa = 0x%llx, vm max_gfn 0x%x\n",
|
|
seg->len, seg->vm0_gpa, seg->gpa, vm->max_gfn);
|
|
|
|
@@ -146,6 +140,22 @@ int alloc_guest_memseg(struct vhm_vm *vm, struct vm_memseg *memseg)
|
|
return 0;
|
|
}
|
|
|
|
+int alloc_guest_memseg(struct vhm_vm *vm, struct vm_memseg *memseg)
|
|
+{
|
|
+ unsigned long vm0_gpa;
|
|
+ int ret;
|
|
+
|
|
+ vm0_gpa = _alloc_memblk(vm->dev, memseg->len);
|
|
+ if (vm0_gpa == 0ULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ ret = add_guest_memseg(vm, vm0_gpa, memseg->gpa, memseg->len);
|
|
+ if (ret < 0)
|
|
+ _free_memblk(vm->dev, vm0_gpa, memseg->len);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int _mem_set_memmap(unsigned long vmid, unsigned long guest_gpa,
|
|
unsigned long host_gpa, unsigned long len,
|
|
unsigned int mem_type, unsigned int mem_access_right,
|
|
@@ -197,6 +207,61 @@ int update_memmap_attr(unsigned long vmid, unsigned long guest_gpa,
|
|
mem_type, mem_access_right, MAP_MEM);
|
|
}
|
|
|
|
+static int hugepage_map_guest(struct vhm_vm *vm, struct vm_memmap *memmap)
|
|
+{
|
|
+ struct page *page;
|
|
+ unsigned long len, guest_gpa, vma;
|
|
+ unsigned int type;
|
|
+ unsigned int mem_type, mem_access_right;
|
|
+ int ret;
|
|
+
|
|
+ if (vm == NULL || memmap == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ len = memmap->len;
|
|
+ vma = memmap->vma_base;
|
|
+ guest_gpa = memmap->gpa;
|
|
+
|
|
+ while (len > 0) {
|
|
+ unsigned long vm0_gpa, pagesize;
|
|
+
|
|
+ ret = get_user_pages_fast(vma, 1, 1, &page);
|
|
+ if (unlikely(ret != 1) || (page == NULL)) {
|
|
+ pr_err("failed to pin huge page!\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ vm0_gpa = page_to_phys(page);
|
|
+ pagesize = PAGE_SIZE << compound_order(page);
|
|
+
|
|
+ ret = add_guest_memseg(vm, vm0_gpa, guest_gpa, pagesize);
|
|
+ if (ret < 0) {
|
|
+ pr_err("failed to add memseg for huge page!\n");
|
|
+ put_page(page);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* TODO: do batch hypercall for multi ept mapping */
|
|
+ mem_type = MEM_TYPE_WB;
|
|
+ mem_access_right = (memmap->prot & MEM_ACCESS_RIGHT_MASK);
|
|
+ type = MAP_MEM;
|
|
+ if (_mem_set_memmap(vm->vmid, guest_gpa, vm0_gpa, pagesize,
|
|
+ mem_type, mem_access_right, type) < 0) {
|
|
+ pr_err("vhm: failed to set memmap %ld!\n", vm->vmid);
|
|
+ put_page(page);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ len -= pagesize;
|
|
+ vma += pagesize;
|
|
+ guest_gpa += pagesize;
|
|
+ }
|
|
+
|
|
+ vm->hugetlb_enabled = 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int map_guest_memseg(struct vhm_vm *vm, struct vm_memmap *memmap)
|
|
{
|
|
struct guest_memseg *seg = NULL;
|
|
@@ -204,8 +269,13 @@ int map_guest_memseg(struct vhm_vm *vm, struct vm_memmap *memmap)
|
|
unsigned int mem_type, mem_access_right;
|
|
unsigned long guest_gpa, host_gpa;
|
|
|
|
+ /* hugetlb use vma to do the mapping */
|
|
+ if (memmap->type == VM_SYSMEM && memmap->using_vma)
|
|
+ return hugepage_map_guest(vm, memmap);
|
|
+
|
|
mutex_lock(&vm->seg_lock);
|
|
|
|
+ /* cma or mmio */
|
|
if (memmap->type == VM_SYSMEM) {
|
|
list_for_each_entry(seg, &vm->memseg_list, list) {
|
|
if (seg->gpa == memmap->gpa
|
|
@@ -249,8 +319,13 @@ void free_guest_mem(struct vhm_vm *vm)
|
|
while (!list_empty(&vm->memseg_list)) {
|
|
seg = list_first_entry(&vm->memseg_list,
|
|
struct guest_memseg, list);
|
|
- if (!_free_memblk(vm->dev, seg->vm0_gpa, seg->len))
|
|
- pr_warn("failed to free memblk\n");
|
|
+ if (vm->hugetlb_enabled) {
|
|
+ /* just put_page to unpin huge page */
|
|
+ put_page(pfn_to_page(seg->vm0_gpa >> PAGE_SHIFT));
|
|
+ } else {
|
|
+ if (!_free_memblk(vm->dev, seg->vm0_gpa, seg->len))
|
|
+ pr_warn("failed to free memblk\n");
|
|
+ }
|
|
list_del(&seg->list);
|
|
kfree(seg);
|
|
}
|
|
diff --git a/include/linux/vhm/vhm_ioctl_defs.h b/include/linux/vhm/vhm_ioctl_defs.h
|
|
index 5bc7c66..a0a830d 100644
|
|
--- a/include/linux/vhm/vhm_ioctl_defs.h
|
|
+++ b/include/linux/vhm/vhm_ioctl_defs.h
|
|
@@ -117,19 +117,30 @@ struct vm_memseg {
|
|
|
|
/**
|
|
* struct vm_memmap - EPT memory mapping info for guest
|
|
- *
|
|
- * @type: memory mapping type
|
|
- * @gpa: guest physical start address of memory mapping
|
|
- * @hpa: host physical start address of memory
|
|
- * @len: the length of memory range mapped
|
|
- * @prot: memory mapping attribute
|
|
*/
|
|
struct vm_memmap {
|
|
+ /** @type: memory mapping type */
|
|
uint32_t type;
|
|
- uint32_t reserved;
|
|
+ /** @using_vma: using vma_base to get vm0_gpa,
|
|
+ * only for type == VM_SYSTEM
|
|
+ */
|
|
+ uint32_t using_vma;
|
|
+ /** @gpa: user OS guest physical start address of memory mapping */
|
|
uint64_t gpa;
|
|
- uint64_t hpa; /* only for type == VM_MMIO */
|
|
+ /** union */
|
|
+ union {
|
|
+ /** @hpa: host physical start address of memory,
|
|
+ * only for type == VM_MMIO
|
|
+ */
|
|
+ uint64_t hpa;
|
|
+ /** @vma_base: service OS user virtual start address of
|
|
+ * memory, only for type == VM_SYSMEM && using_vma == true
|
|
+ */
|
|
+ uint64_t vma_base;
|
|
+ };
|
|
+ /** @len: the length of memory range mapped */
|
|
uint64_t len; /* mmap length */
|
|
+ /** @prot: memory mapping attribute */
|
|
uint32_t prot; /* RWX */
|
|
};
|
|
|
|
diff --git a/include/linux/vhm/vhm_vm_mngt.h b/include/linux/vhm/vhm_vm_mngt.h
|
|
index e7bc8b2..306bd54 100644
|
|
--- a/include/linux/vhm/vhm_vm_mngt.h
|
|
+++ b/include/linux/vhm/vhm_vm_mngt.h
|
|
@@ -96,6 +96,7 @@ struct vhm_vm {
|
|
struct list_head ioreq_client_list;
|
|
struct vhm_request_buffer *req_buf;
|
|
struct page *pg;
|
|
+ int hugetlb_enabled;
|
|
};
|
|
|
|
/**
|
|
--
|
|
https://clearlinux.org
|
|
|