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 {

Reply via email to