clear-pkgs-linux-iot-lts2018/0519-VHM-add-hugetlb-page-e...

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