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
This commit is contained in:
Mark Johnston 2024-04-03 13:01:31 -04:00
parent 8b06bdc91d
commit 7e0fa79412
3 changed files with 59 additions and 46 deletions

View File

@ -9,12 +9,19 @@
#include <sys/types.h> #include <sys/types.h>
enum {
VM_MEMSEG_LOW,
VM_MEMSEG_HIGH,
VM_MEMSEG_COUNT,
};
struct vmctx { struct vmctx {
int fd; int fd;
uint32_t lowmem_limit; struct {
vm_paddr_t base;
vm_size_t size;
} memsegs[VM_MEMSEG_COUNT];
int memflags; int memflags;
size_t lowmem;
size_t highmem;
char *baseaddr; char *baseaddr;
char *name; char *name;
}; };

View File

@ -59,6 +59,9 @@
#define MB (1024 * 1024UL) #define MB (1024 * 1024UL)
#define GB (1024 * 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 * Size of the guard region before and after the virtual address space
* mapping the guest physical memory. This must be a multiple of the * 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->fd = -1;
vm->memflags = 0; vm->memflags = 0;
vm->lowmem_limit = 3 * GB;
vm->name = (char *)(vm + 1); vm->name = (char *)(vm + 1);
strcpy(vm->name, name); strcpy(vm->name, name);
memset(vm->memsegs, 0, sizeof(vm->memsegs));
if ((vm->fd = vm_device_open(vm->name)) < 0) if ((vm->fd = vm_device_open(vm->name)) < 0)
goto err; goto err;
@ -194,17 +197,10 @@ vm_parse_memsize(const char *opt, size_t *ret_memsize)
} }
uint32_t uint32_t
vm_get_lowmem_limit(struct vmctx *ctx) vm_get_lowmem_limit(struct vmctx *ctx __unused)
{ {
return (ctx->lowmem_limit); return (VM_LOWMEM_LIMIT);
}
void
vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit)
{
ctx->lowmem_limit = limit;
} }
void void
@ -266,8 +262,8 @@ vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr,
{ {
*guest_baseaddr = ctx->baseaddr; *guest_baseaddr = ctx->baseaddr;
*lowmem_size = ctx->lowmem; *lowmem_size = ctx->memsegs[VM_MEMSEG_LOW].size;
*highmem_size = ctx->highmem; *highmem_size = ctx->memsegs[VM_MEMSEG_HIGH].size;
return (0); 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); assert(vms == VM_MMAP_ALL);
/* /*
* If 'memsize' cannot fit entirely in the 'lowmem' segment then * If 'memsize' cannot fit entirely in the 'lowmem' segment then create
* create another 'highmem' segment above 4GB for the remainder. * another 'highmem' segment above VM_HIGHMEM_BASE for the remainder.
*/ */
if (memsize > ctx->lowmem_limit) { if (memsize > VM_LOWMEM_LIMIT) {
ctx->lowmem = ctx->lowmem_limit; ctx->memsegs[VM_MEMSEG_LOW].size = VM_LOWMEM_LIMIT;
ctx->highmem = memsize - ctx->lowmem_limit; ctx->memsegs[VM_MEMSEG_HIGH].size = memsize - VM_LOWMEM_LIMIT;
objsize = 4*GB + ctx->highmem; objsize = VM_HIGHMEM_BASE + ctx->memsegs[VM_MEMSEG_HIGH].size;
} else { } else {
ctx->lowmem = memsize; ctx->memsegs[VM_MEMSEG_LOW].size = memsize;
ctx->highmem = 0; ctx->memsegs[VM_MEMSEG_HIGH].size = 0;
objsize = ctx->lowmem; objsize = memsize;
} }
error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL); 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); return (-1);
baseaddr = ptr + VM_MMAP_GUARD_SIZE; baseaddr = ptr + VM_MMAP_GUARD_SIZE;
if (ctx->highmem > 0) { if (ctx->memsegs[VM_MEMSEG_HIGH].size > 0) {
gpa = 4*GB; gpa = VM_HIGHMEM_BASE;
len = ctx->highmem; len = ctx->memsegs[VM_MEMSEG_HIGH].size;
error = setup_memory_segment(ctx, gpa, len, baseaddr); error = setup_memory_segment(ctx, gpa, len, baseaddr);
if (error) if (error)
return (error); return (error);
} }
if (ctx->lowmem > 0) { if (ctx->memsegs[VM_MEMSEG_LOW].size > 0) {
gpa = 0; gpa = 0;
len = ctx->lowmem; len = ctx->memsegs[VM_MEMSEG_LOW].size;
error = setup_memory_segment(ctx, gpa, len, baseaddr); error = setup_memory_segment(ctx, gpa, len, baseaddr);
if (error) if (error)
return (error); return (error);
@ -476,20 +472,19 @@ vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
void * void *
vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len)
{ {
vm_size_t lowsize, highsize;
if (ctx->lowmem > 0) { lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
if (gaddr < ctx->lowmem && len <= ctx->lowmem && if (lowsize > 0) {
gaddr + len <= ctx->lowmem) if (gaddr < lowsize && len <= lowsize && gaddr + len <= lowsize)
return (ctx->baseaddr + gaddr); return (ctx->baseaddr + gaddr);
} }
if (ctx->highmem > 0) { highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
if (gaddr >= 4*GB) { if (highsize > 0 && gaddr >= VM_HIGHMEM_BASE) {
if (gaddr < 4*GB + ctx->highmem && if (gaddr < VM_HIGHMEM_BASE + highsize && len <= highsize &&
len <= ctx->highmem && gaddr + len <= VM_HIGHMEM_BASE + highsize)
gaddr + len <= 4*GB + ctx->highmem) return (ctx->baseaddr + gaddr);
return (ctx->baseaddr + gaddr);
}
} }
return (NULL); return (NULL);
@ -499,15 +494,19 @@ vm_paddr_t
vm_rev_map_gpa(struct vmctx *ctx, void *addr) vm_rev_map_gpa(struct vmctx *ctx, void *addr)
{ {
vm_paddr_t offaddr; vm_paddr_t offaddr;
vm_size_t lowsize, highsize;
offaddr = (char *)addr - ctx->baseaddr; offaddr = (char *)addr - ctx->baseaddr;
if (ctx->lowmem > 0) lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
if (offaddr <= ctx->lowmem) if (lowsize > 0)
if (offaddr <= lowsize)
return (offaddr); return (offaddr);
if (ctx->highmem > 0) highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
if (offaddr >= 4*GB && offaddr < 4*GB + ctx->highmem) if (highsize > 0)
if (offaddr >= VM_HIGHMEM_BASE &&
offaddr < VM_HIGHMEM_BASE + highsize)
return (offaddr); return (offaddr);
return ((vm_paddr_t)-1); return ((vm_paddr_t)-1);
@ -524,14 +523,21 @@ size_t
vm_get_lowmem_size(struct vmctx *ctx) 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 size_t
vm_get_highmem_size(struct vmctx *ctx) vm_get_highmem_size(struct vmctx *ctx)
{ {
return (ctx->highmem); return (ctx->memsegs[VM_MEMSEG_HIGH].size);
} }
void * void *

View File

@ -135,11 +135,11 @@ int vm_gla2gpa_nofault(struct vcpu *vcpu,
struct vm_guest_paging *paging, uint64_t gla, int prot, struct vm_guest_paging *paging, uint64_t gla, int prot,
uint64_t *gpa, int *fault); uint64_t *gpa, int *fault);
uint32_t vm_get_lowmem_limit(struct vmctx *ctx); 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); void vm_set_memflags(struct vmctx *ctx, int flags);
int vm_get_memflags(struct vmctx *ctx); int vm_get_memflags(struct vmctx *ctx);
const char *vm_get_name(struct vmctx *ctx); const char *vm_get_name(struct vmctx *ctx);
size_t vm_get_lowmem_size(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); size_t vm_get_highmem_size(struct vmctx *ctx);
#ifdef __amd64__ #ifdef __amd64__
int vm_set_desc(struct vcpu *vcpu, int reg, int vm_set_desc(struct vcpu *vcpu, int reg,