git: 7e0fa794123e - main - libvmmapi: Make memory segment handling a bit more abstract

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 10 Apr 2024 15:19:09 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=7e0fa794123eb8395fffa976c47e8ba4f44f2df0

commit 7e0fa794123eb8395fffa976c47e8ba4f44f2df0
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-04-03 17:01:31 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-04-10 15:17:56 +0000

    libvmmapi: Make memory segment handling a bit more abstract
    
    libvmmapi leaves a hole at [3GB, 4GB) in the guest physical address
    space.  This hole is not used in the arm64 port, which maps everything
    above 4GB.  This change makes the code a bit more general to accomodate
    arm64 more naturally.  In particular:
    
    - Remove vm_set_lowmem_limit(): it is unused and doesn't have
      well-defined constraints, e.g., nothing prevents a consumer from
      setting a lowmem limit above the highmem base.
    - Define a constant for the highmem base and use that everywhere that
      the base is currently hard-coded.
    - Make the lowmem limit a compile-time constant instead of a vmctx field.
    - Store segment info in an array.
    - Add vm_get_highmem_base(), for use in bhyve since the current value is
      hard-coded in some places.
    
    No functional change intended.
    
    Reviewed by:    corvink, jhb
    MFC after:      2 weeks
    Sponsored by:   Innovate UK
    Differential Revision:  https://reviews.freebsd.org/D41004
---
 lib/libvmmapi/internal.h | 13 +++++--
 lib/libvmmapi/vmmapi.c   | 90 ++++++++++++++++++++++++++----------------------
 lib/libvmmapi/vmmapi.h   |  2 +-
 3 files changed, 59 insertions(+), 46 deletions(-)

diff --git a/lib/libvmmapi/internal.h b/lib/libvmmapi/internal.h
index 98e50f9a1bf4..2b2f9eac3757 100644
--- a/lib/libvmmapi/internal.h
+++ b/lib/libvmmapi/internal.h
@@ -9,12 +9,19 @@
 
 #include <sys/types.h>
 
+enum {
+	VM_MEMSEG_LOW,
+	VM_MEMSEG_HIGH,
+	VM_MEMSEG_COUNT,
+};
+
 struct vmctx {
 	int	fd;
-	uint32_t lowmem_limit;
+	struct {
+		vm_paddr_t base;
+		vm_size_t size;
+	} memsegs[VM_MEMSEG_COUNT];
 	int	memflags;
-	size_t	lowmem;
-	size_t	highmem;
 	char	*baseaddr;
 	char	*name;
 };
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 63f0fe0f16fe..ab20df3f3fc9 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -59,6 +59,9 @@
 #define	MB	(1024 * 1024UL)
 #define	GB	(1024 * 1024 * 1024UL)
 
+#define	VM_LOWMEM_LIMIT	(3 * GB)
+#define	VM_HIGHMEM_BASE	(4 * GB)
+
 /*
  * Size of the guard region before and after the virtual address space
  * mapping the guest physical memory. This must be a multiple of the
@@ -110,9 +113,9 @@ vm_open(const char *name)
 
 	vm->fd = -1;
 	vm->memflags = 0;
-	vm->lowmem_limit = 3 * GB;
 	vm->name = (char *)(vm + 1);
 	strcpy(vm->name, name);
+	memset(vm->memsegs, 0, sizeof(vm->memsegs));
 
 	if ((vm->fd = vm_device_open(vm->name)) < 0)
 		goto err;
@@ -194,17 +197,10 @@ vm_parse_memsize(const char *opt, size_t *ret_memsize)
 }
 
 uint32_t
-vm_get_lowmem_limit(struct vmctx *ctx)
+vm_get_lowmem_limit(struct vmctx *ctx __unused)
 {
 
-	return (ctx->lowmem_limit);
-}
-
-void
-vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit)
-{
-
-	ctx->lowmem_limit = limit;
+	return (VM_LOWMEM_LIMIT);
 }
 
 void
@@ -266,8 +262,8 @@ vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr,
 {
 
 	*guest_baseaddr = ctx->baseaddr;
-	*lowmem_size = ctx->lowmem;
-	*highmem_size = ctx->highmem;
+	*lowmem_size = ctx->memsegs[VM_MEMSEG_LOW].size;
+	*highmem_size = ctx->memsegs[VM_MEMSEG_HIGH].size;
 	return (0);
 }
 
@@ -418,17 +414,17 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
 	assert(vms == VM_MMAP_ALL);
 
 	/*
-	 * If 'memsize' cannot fit entirely in the 'lowmem' segment then
-	 * create another 'highmem' segment above 4GB for the remainder.
+	 * If 'memsize' cannot fit entirely in the 'lowmem' segment then create
+	 * another 'highmem' segment above VM_HIGHMEM_BASE for the remainder.
 	 */
-	if (memsize > ctx->lowmem_limit) {
-		ctx->lowmem = ctx->lowmem_limit;
-		ctx->highmem = memsize - ctx->lowmem_limit;
-		objsize = 4*GB + ctx->highmem;
+	if (memsize > VM_LOWMEM_LIMIT) {
+		ctx->memsegs[VM_MEMSEG_LOW].size = VM_LOWMEM_LIMIT;
+		ctx->memsegs[VM_MEMSEG_HIGH].size = memsize - VM_LOWMEM_LIMIT;
+		objsize = VM_HIGHMEM_BASE + ctx->memsegs[VM_MEMSEG_HIGH].size;
 	} else {
-		ctx->lowmem = memsize;
-		ctx->highmem = 0;
-		objsize = ctx->lowmem;
+		ctx->memsegs[VM_MEMSEG_LOW].size = memsize;
+		ctx->memsegs[VM_MEMSEG_HIGH].size = 0;
+		objsize = memsize;
 	}
 
 	error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL);
@@ -445,17 +441,17 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
 		return (-1);
 
 	baseaddr = ptr + VM_MMAP_GUARD_SIZE;
-	if (ctx->highmem > 0) {
-		gpa = 4*GB;
-		len = ctx->highmem;
+	if (ctx->memsegs[VM_MEMSEG_HIGH].size > 0) {
+		gpa = VM_HIGHMEM_BASE;
+		len = ctx->memsegs[VM_MEMSEG_HIGH].size;
 		error = setup_memory_segment(ctx, gpa, len, baseaddr);
 		if (error)
 			return (error);
 	}
 
-	if (ctx->lowmem > 0) {
+	if (ctx->memsegs[VM_MEMSEG_LOW].size > 0) {
 		gpa = 0;
-		len = ctx->lowmem;
+		len = ctx->memsegs[VM_MEMSEG_LOW].size;
 		error = setup_memory_segment(ctx, gpa, len, baseaddr);
 		if (error)
 			return (error);
@@ -476,20 +472,19 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
 void *
 vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len)
 {
+	vm_size_t lowsize, highsize;
 
-	if (ctx->lowmem > 0) {
-		if (gaddr < ctx->lowmem && len <= ctx->lowmem &&
-		    gaddr + len <= ctx->lowmem)
+	lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
+	if (lowsize > 0) {
+		if (gaddr < lowsize && len <= lowsize && gaddr + len <= lowsize)
 			return (ctx->baseaddr + gaddr);
 	}
 
-	if (ctx->highmem > 0) {
-                if (gaddr >= 4*GB) {
-			if (gaddr < 4*GB + ctx->highmem &&
-			    len <= ctx->highmem &&
-			    gaddr + len <= 4*GB + ctx->highmem)
-				return (ctx->baseaddr + gaddr);
-		}
+	highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
+	if (highsize > 0 && gaddr >= VM_HIGHMEM_BASE) {
+		if (gaddr < VM_HIGHMEM_BASE + highsize && len <= highsize &&
+		    gaddr + len <= VM_HIGHMEM_BASE + highsize)
+			return (ctx->baseaddr + gaddr);
 	}
 
 	return (NULL);
@@ -499,15 +494,19 @@ vm_paddr_t
 vm_rev_map_gpa(struct vmctx *ctx, void *addr)
 {
 	vm_paddr_t offaddr;
+	vm_size_t lowsize, highsize;
 
 	offaddr = (char *)addr - ctx->baseaddr;
 
-	if (ctx->lowmem > 0)
-		if (offaddr <= ctx->lowmem)
+	lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
+	if (lowsize > 0)
+		if (offaddr <= lowsize)
 			return (offaddr);
 
-	if (ctx->highmem > 0)
-		if (offaddr >= 4*GB && offaddr < 4*GB + ctx->highmem)
+	highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
+	if (highsize > 0)
+		if (offaddr >= VM_HIGHMEM_BASE &&
+		    offaddr < VM_HIGHMEM_BASE + highsize)
 			return (offaddr);
 
 	return ((vm_paddr_t)-1);
@@ -524,14 +523,21 @@ size_t
 vm_get_lowmem_size(struct vmctx *ctx)
 {
 
-	return (ctx->lowmem);
+	return (ctx->memsegs[VM_MEMSEG_LOW].size);
+}
+
+vm_paddr_t
+vm_get_highmem_base(struct vmctx *ctx __unused)
+{
+
+	return (VM_HIGHMEM_BASE);
 }
 
 size_t
 vm_get_highmem_size(struct vmctx *ctx)
 {
 
-	return (ctx->highmem);
+	return (ctx->memsegs[VM_MEMSEG_HIGH].size);
 }
 
 void *
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index b69f02cde7e4..bd182b0914fc 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -135,11 +135,11 @@ int	vm_gla2gpa_nofault(struct vcpu *vcpu,
 		   struct vm_guest_paging *paging, uint64_t gla, int prot,
 		   uint64_t *gpa, int *fault);
 uint32_t vm_get_lowmem_limit(struct vmctx *ctx);
-void	vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit);
 void	vm_set_memflags(struct vmctx *ctx, int flags);
 int	vm_get_memflags(struct vmctx *ctx);
 const char *vm_get_name(struct vmctx *ctx);
 size_t	vm_get_lowmem_size(struct vmctx *ctx);
+vm_paddr_t vm_get_highmem_base(struct vmctx *ctx);
 size_t	vm_get_highmem_size(struct vmctx *ctx);
 #ifdef __amd64__
 int	vm_set_desc(struct vcpu *vcpu, int reg,