git: 7e0fa794123e - main - libvmmapi: Make memory segment handling a bit more abstract
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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,