Module Name: src Committed By: maxv Date: Thu Nov 29 19:55:21 UTC 2018
Modified Files: src/lib/libnvmm: libnvmm.c nvmm.h Log Message: Rewrite the gpa map/unmap functions. Dig holes in the mapped areas when there is an overlap. Close to what Qemu expects. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/lib/libnvmm/libnvmm.c cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/nvmm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.2 src/lib/libnvmm/libnvmm.c:1.3 --- src/lib/libnvmm/libnvmm.c:1.2 Mon Nov 19 21:45:37 2018 +++ src/lib/libnvmm/libnvmm.c Thu Nov 29 19:55:20 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.2 2018/11/19 21:45:37 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.3 2018/11/29 19:55:20 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -39,78 +39,145 @@ #include <errno.h> #include <sys/ioctl.h> #include <sys/mman.h> +#include <sys/queue.h> #include "nvmm.h" +typedef struct __area { + LIST_ENTRY(__area) list; + gpaddr_t gpa; + uintptr_t hva; + size_t size; +} area_t; + +typedef LIST_HEAD(, __area) area_list_t; + static int nvmm_fd = -1; static size_t nvmm_page_size = 0; /* -------------------------------------------------------------------------- */ static int -_nvmm_area_add(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva, +__area_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, + size_t size) +{ + struct nvmm_ioc_gpa_unmap args; + int ret; + + args.machid = mach->machid; + args.gpa = gpa; + args.size = size; + + ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args); + if (ret == -1) + return -1; + + ret = munmap((void *)hva, size); + + return ret; +} + +static int +__area_dig_hole(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) { - struct nvmm_area *area; - void *ptr; - size_t i; - - for (i = 0; i < mach->nareas; i++) { - if (gpa >= mach->areas[i].gpa && - gpa < mach->areas[i].gpa + mach->areas[i].size) { - goto error; + area_list_t *areas = mach->areas; + area_t *ent, *tmp, *nxt; + size_t diff; + + LIST_FOREACH_SAFE(ent, areas, list, nxt) { + /* Case 1. */ + if ((gpa < ent->gpa) && (gpa + size > ent->gpa)) { + diff = (gpa + size) - ent->gpa; + if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { + return -1; + } + ent->gpa += diff; + ent->hva += diff; + ent->size -= diff; } - if (gpa + size > mach->areas[i].gpa && - gpa + size <= mach->areas[i].gpa + mach->areas[i].size) { - goto error; + + /* Case 2. */ + if ((gpa >= ent->gpa) && (gpa + size <= ent->gpa + ent->size)) { + /* First half. */ + tmp = malloc(sizeof(*tmp)); + tmp->gpa = ent->gpa; + tmp->hva = ent->hva; + tmp->size = (gpa - ent->gpa); + LIST_INSERT_BEFORE(ent, tmp, list); + /* Second half. */ + ent->gpa += tmp->size; + ent->hva += tmp->size; + ent->size -= tmp->size; + diff = size; + if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { + return -1; + } + ent->gpa += diff; + ent->hva += diff; + ent->size -= diff; } - if (gpa < mach->areas[i].gpa && - gpa + size >= mach->areas[i].gpa + mach->areas[i].size) { - goto error; + + /* Case 3. */ + if ((gpa < ent->gpa + ent->size) && + (gpa + size > ent->gpa + ent->size)) { + diff = (ent->gpa + ent->size) - gpa; + if (__area_unmap(mach, hva, gpa, diff) == -1) { + return -1; + } + ent->size -= diff; + } + + /* Case 4. */ + if ((gpa < ent->gpa + ent->size) && + (gpa + size > ent->gpa + ent->size)) { + if (__area_unmap(mach, ent->hva, ent->gpa, ent->size) == -1) { + return -1; + } + LIST_REMOVE(ent, list); + free(ent); } } - ptr = realloc(mach->areas, (mach->nareas + 1) * - sizeof(struct nvmm_area)); - if (ptr == NULL) - return -1; - mach->areas = ptr; + return 0; +} + +static int +__area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) +{ + area_list_t *areas = mach->areas; + area_t *area; + int ret; - area = &mach->areas[mach->nareas++]; + area = malloc(sizeof(*area)); + if (area == NULL) + return -1; area->gpa = gpa; area->hva = hva; area->size = size; - return 0; + ret = __area_dig_hole(mach, hva, gpa, size); + if (ret == -1) { + free(area); + return -1; + } -error: - errno = EEXIST; - return -1; + LIST_INSERT_HEAD(areas, area, list); + return 0; } -static int -_nvmm_area_delete(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva, - size_t size) +static void +__area_remove_all(struct nvmm_machine *mach) { - size_t i; + area_list_t *areas = mach->areas; + area_t *ent; - for (i = 0; i < mach->nareas; i++) { - if (gpa == mach->areas[i].gpa && - hva == mach->areas[i].hva && - size == mach->areas[i].size) { - break; - } - } - if (i == mach->nareas) { - errno = ENOENT; - return -1; + while ((ent = LIST_FIRST(areas)) != NULL) { + LIST_REMOVE(ent, list); + free(ent); } - memmove(&mach->areas[i], &mach->areas[i+1], - (mach->nareas - i - 1) * sizeof(struct nvmm_area)); - mach->nareas--; - - return 0; + free(areas); } /* -------------------------------------------------------------------------- */ @@ -150,17 +217,26 @@ int nvmm_machine_create(struct nvmm_machine *mach) { struct nvmm_ioc_machine_create args; + area_list_t *areas; int ret; if (nvmm_init() == -1) { return -1; } + areas = calloc(1, sizeof(*areas)); + if (areas == NULL) + return -1; + ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args); - if (ret == -1) + if (ret == -1) { + free(areas); return -1; + } memset(mach, 0, sizeof(*mach)); + LIST_INIT(areas); + mach->areas = areas; mach->machid = args.machid; return 0; @@ -182,7 +258,7 @@ nvmm_machine_destroy(struct nvmm_machine if (ret == -1) return -1; - free(mach->areas); + __area_remove_all(mach); return 0; } @@ -351,6 +427,10 @@ nvmm_gpa_map(struct nvmm_machine *mach, return -1; } + ret = __area_add(mach, hva, gpa, size); + if (ret == -1) + return -1; + args.machid = mach->machid; args.hva = hva; args.gpa = gpa; @@ -358,13 +438,9 @@ nvmm_gpa_map(struct nvmm_machine *mach, args.flags = flags; ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args); - if (ret == -1) - return -1; - - ret = _nvmm_area_add(mach, gpa, hva, size); if (ret == -1) { - nvmm_gpa_unmap(mach, hva, gpa, size); - return -1; + /* Can't recover. */ + abort(); } return 0; @@ -374,28 +450,11 @@ int nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) { - struct nvmm_ioc_gpa_unmap args; - int ret; - if (nvmm_init() == -1) { return -1; } - ret = _nvmm_area_delete(mach, gpa, hva, size); - if (ret == -1) - return -1; - - args.machid = mach->machid; - args.gpa = gpa; - args.size = size; - - ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args); - if (ret == -1) - return -1; - - ret = munmap((void *)hva, size); - - return ret; + return __area_dig_hole(mach, hva, gpa, size); } /* @@ -405,22 +464,23 @@ nvmm_gpa_unmap(struct nvmm_machine *mach int nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva) { - size_t i; + area_list_t *areas = mach->areas; + area_t *ent; if (gpa % nvmm_page_size != 0) { errno = EINVAL; return -1; } - for (i = 0; i < mach->nareas; i++) { - if (gpa < mach->areas[i].gpa) { + LIST_FOREACH(ent, areas, list) { + if (gpa < ent->gpa) { continue; } - if (gpa >= mach->areas[i].gpa + mach->areas[i].size) { + if (gpa >= ent->gpa + ent->size) { continue; } - *hva = mach->areas[i].hva + (gpa - mach->areas[i].gpa); + *hva = ent->hva + (gpa - ent->gpa); return 0; } Index: src/lib/libnvmm/nvmm.h diff -u src/lib/libnvmm/nvmm.h:1.1 src/lib/libnvmm/nvmm.h:1.2 --- src/lib/libnvmm/nvmm.h:1.1 Sat Nov 10 09:28:56 2018 +++ src/lib/libnvmm/nvmm.h Thu Nov 29 19:55:20 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.h,v 1.1 2018/11/10 09:28:56 maxv Exp $ */ +/* $NetBSD: nvmm.h,v 1.2 2018/11/29 19:55:20 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -41,16 +41,9 @@ #include <dev/nvmm/x86/nvmm_x86.h> #endif -struct nvmm_area { - gpaddr_t gpa; - uintptr_t hva; - size_t size; -}; - struct nvmm_machine { nvmm_machid_t machid; - struct nvmm_area *areas; - size_t nareas; + void *areas; /* opaque */ }; struct nvmm_io {