Changeset View
Changeset View
Standalone View
Standalone View
lib/libvmmapi/vmmapi.c
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <machine/vmm_dev.h> | #include <machine/vmm_dev.h> | ||||
#include <machine/vmm_snapshot.h> | #include <machine/vmm_snapshot.h> | ||||
#include "vmmapi.h" | #include "vmmapi.h" | ||||
#define KB (1024UL) | |||||
#define MB (1024 * 1024UL) | #define MB (1024 * 1024UL) | ||||
#define GB (1024 * 1024 * 1024UL) | #define GB (1024 * 1024 * 1024UL) | ||||
#define VGAMEM_START (640*KB) | |||||
#define VGAMEM_END (VGAMEM_START + 128*KB) | |||||
/* | /* | ||||
* 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 | ||||
* superpage size for performance reasons. | * superpage size for performance reasons. | ||||
*/ | */ | ||||
#define VM_MMAP_GUARD_SIZE (4 * MB) | #define VM_MMAP_GUARD_SIZE (4 * MB) | ||||
#define PROT_RW (PROT_READ | PROT_WRITE) | #define PROT_RW (PROT_READ | PROT_WRITE) | ||||
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) | #define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) | ||||
struct vmctx { | struct vmctx { | ||||
int fd; | int fd; | ||||
uint32_t lowmem_limit; | uint32_t lowmem_limit; | ||||
int memflags; | int memflags; | ||||
size_t lowmem; | size_t lowmem; | ||||
size_t highmem; | size_t highmem; | ||||
char *baseaddr; | char *baseaddr; | ||||
char *name; | char *name; | ||||
}; | }; | ||||
#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) | #define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) | ||||
#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) | #define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) | ||||
#ifndef min | |||||
#define min(a,b) (((a) < (b)) ? (a) : (b)) | |||||
#endif | |||||
static int | static int | ||||
vm_device_open(const char *name) | vm_device_open(const char *name) | ||||
{ | { | ||||
int fd, len; | int fd, len; | ||||
char *vmfile; | char *vmfile; | ||||
len = strlen("/dev/vmm/") + strlen(name) + 1; | len = strlen("/dev/vmm/") + strlen(name) + 1; | ||||
vmfile = malloc(len); | vmfile = malloc(len); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | if (ctx->memflags & VM_MEM_F_WIRED) | ||||
memmap.flags |= VM_MEMMAP_F_WIRED; | memmap.flags |= VM_MEMMAP_F_WIRED; | ||||
/* | /* | ||||
* If this mapping already exists then don't create it again. This | * If this mapping already exists then don't create it again. This | ||||
* is the common case for SYSMEM mappings created by bhyveload(8). | * is the common case for SYSMEM mappings created by bhyveload(8). | ||||
*/ | */ | ||||
error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags); | error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags); | ||||
if (error == 0 && gpa == memmap.gpa) { | if (error == 0 && gpa == memmap.gpa) { | ||||
if (segid != memmap.segid || off != memmap.segoff || | /* Allow other segments to align with SYSMEM borders */ | ||||
prot != memmap.prot || flags != memmap.flags) { | if ((segid != VM_SYSMEM || memmap.segid == VM_SYSMEM) && | ||||
(segid != memmap.segid || off != memmap.segoff || | |||||
prot != memmap.prot || flags != memmap.flags)) { | |||||
errno = EEXIST; | errno = EEXIST; | ||||
return (-1); | return (-1); | ||||
} else { | } else { | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); | error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr, | vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr, | ||||
size_t *lowmem_size, size_t *highmem_size) | size_t *lowmem_size, size_t *highmem_size) | ||||
{ | { | ||||
*guest_baseaddr = ctx->baseaddr; | *guest_baseaddr = ctx->baseaddr; | ||||
*lowmem_size = ctx->lowmem; | *lowmem_size = ctx->lowmem; | ||||
*highmem_size = ctx->highmem; | *highmem_size = ctx->highmem; | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, | |||||
int segid, vm_ooffset_t segoff) | |||||
{ | |||||
struct vm_memmap memmap; | |||||
int error; | |||||
memmap.gpa = gpa; | |||||
memmap.segid = segid; | |||||
memmap.segoff = segoff; | |||||
memmap.len = 0; | |||||
memmap.prot = 0; | |||||
memmap.flags = 0; | |||||
error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); | |||||
return (error); | |||||
} | |||||
int | |||||
vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid, | vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid, | ||||
vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) | vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) | ||||
{ | { | ||||
struct vm_memmap memmap; | struct vm_memmap memmap; | ||||
int error; | int error; | ||||
bzero(&memmap, sizeof(struct vm_memmap)); | bzero(&memmap, sizeof(struct vm_memmap)); | ||||
memmap.gpa = *gpa; | memmap.gpa = *gpa; | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) | ||||
if (ctx->highmem > 0) { | if (ctx->highmem > 0) { | ||||
gpa = 4*GB; | gpa = 4*GB; | ||||
len = ctx->highmem; | len = ctx->highmem; | ||||
error = setup_memory_segment(ctx, gpa, len, baseaddr); | error = setup_memory_segment(ctx, gpa, len, baseaddr); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* Leave a memory hole for VGA memory. | |||||
*/ | |||||
if (ctx->lowmem > VGAMEM_END) { | |||||
gpa = VGAMEM_END; | |||||
len = ctx->lowmem - VGAMEM_END; | |||||
error = setup_memory_segment(ctx, gpa, len, baseaddr); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
/* | |||||
* Add up to 640 KB of base memory. | |||||
*/ | |||||
if (ctx->lowmem > 0) { | if (ctx->lowmem > 0) { | ||||
gpa = 0; | gpa = 0; | ||||
len = ctx->lowmem; | len = min(ctx->lowmem, VGAMEM_START); | ||||
error = setup_memory_segment(ctx, gpa, len, baseaddr); | error = setup_memory_segment(ctx, gpa, len, baseaddr); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
ctx->baseaddr = baseaddr; | ctx->baseaddr = baseaddr; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in | * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in | ||||
* the lowmem or highmem regions. | * the lowmem or highmem regions. | ||||
* | * | ||||
* In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region. | * In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region. | ||||
* The instruction emulation code depends on this behavior. | * The instruction emulation code depends on this behavior. | ||||
*/ | */ | ||||
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) | ||||
{ | { | ||||
if (ctx->lowmem > 0) { | if (ctx->lowmem > 0) { | ||||
if (gaddr < ctx->lowmem && len <= ctx->lowmem && | if (gaddr < ctx->lowmem && len <= ctx->lowmem && | ||||
gaddr + len <= ctx->lowmem) | gaddr + len <= VGAMEM_START) | ||||
return (ctx->baseaddr + gaddr); | return (ctx->baseaddr + gaddr); | ||||
} | } | ||||
if (ctx->lowmem > VGAMEM_END) { | |||||
if (gaddr >= VGAMEM_END && gaddr < ctx->lowmem && | |||||
len <= ctx->lowmem && gaddr + len <= ctx->lowmem) | |||||
return (ctx->baseaddr + gaddr); | |||||
} | |||||
if (ctx->highmem > 0) { | if (ctx->highmem > 0) { | ||||
if (gaddr >= 4*GB) { | if (gaddr >= 4*GB) { | ||||
if (gaddr < 4*GB + ctx->highmem && | if (gaddr < 4*GB + ctx->highmem && | ||||
len <= ctx->highmem && | len <= ctx->highmem && | ||||
gaddr + len <= 4*GB + ctx->highmem) | gaddr + len <= 4*GB + ctx->highmem) | ||||
return (ctx->baseaddr + gaddr); | return (ctx->baseaddr + gaddr); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 515 Lines • ▼ Show 20 Lines | vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, | ||||
pptmmio.gpa = gpa; | pptmmio.gpa = gpa; | ||||
pptmmio.len = len; | pptmmio.len = len; | ||||
pptmmio.hpa = hpa; | pptmmio.hpa = hpa; | ||||
return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); | return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); | ||||
} | } | ||||
int | int | ||||
vm_get_vbios(struct vmctx *ctx, int bus, int slot, int func, | |||||
uint16_t vendor, uint16_t dev_id, void *bios, uint64_t *size) | |||||
{ | |||||
int error; | |||||
struct vm_vbios vbios; | |||||
bzero(&vbios, sizeof(vbios)); | |||||
vbios.bus = bus; | |||||
vbios.slot = slot; | |||||
vbios.func = func; | |||||
vbios.vendor = vendor; | |||||
vbios.dev_id = dev_id; | |||||
vbios.bios = bios; | |||||
if (size != NULL) | |||||
vbios.size = *size; | |||||
else | |||||
vbios.size = 0; | |||||
error = ioctl(ctx->fd, VM_GET_VBIOS, &vbios); | |||||
if (size) | |||||
*size = vbios.size; | |||||
return (error); | |||||
} | |||||
int | |||||
vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, | vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, | ||||
uint64_t addr, uint64_t msg, int numvec) | uint64_t addr, uint64_t msg, int numvec) | ||||
{ | { | ||||
struct vm_pptdev_msi pptmsi; | struct vm_pptdev_msi pptmsi; | ||||
bzero(&pptmsi, sizeof(pptmsi)); | bzero(&pptmsi, sizeof(pptmsi)); | ||||
pptmsi.vcpu = vcpu; | pptmsi.vcpu = vcpu; | ||||
pptmsi.bus = bus; | pptmsi.bus = bus; | ||||
▲ Show 20 Lines • Show All 314 Lines • ▼ Show 20 Lines | vm_gla2gpa_nofault(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, | ||||
error = ioctl(ctx->fd, VM_GLA2GPA_NOFAULT, &gg); | error = ioctl(ctx->fd, VM_GLA2GPA_NOFAULT, &gg); | ||||
if (error == 0) { | if (error == 0) { | ||||
*fault = gg.fault; | *fault = gg.fault; | ||||
*gpa = gg.gpa; | *gpa = gg.gpa; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef min | |||||
#define min(a,b) (((a) < (b)) ? (a) : (b)) | |||||
#endif | |||||
int | int | ||||
vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, | vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, | ||||
uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt, | uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt, | ||||
int *fault) | int *fault) | ||||
{ | { | ||||
void *va; | void *va; | ||||
uint64_t gpa; | uint64_t gpa; | ||||
int error, i, n, off; | int error, i, n, off; | ||||
▲ Show 20 Lines • Show All 310 Lines • ▼ Show 20 Lines | static const cap_ioctl_t vm_ioctl_cmds[] = { VM_RUN, VM_SUSPEND, VM_REINIT, | ||||
VM_SET_REGISTER_SET, VM_GET_REGISTER_SET, | VM_SET_REGISTER_SET, VM_GET_REGISTER_SET, | ||||
VM_SET_KERNEMU_DEV, VM_GET_KERNEMU_DEV, | VM_SET_KERNEMU_DEV, VM_GET_KERNEMU_DEV, | ||||
VM_INJECT_EXCEPTION, VM_LAPIC_IRQ, VM_LAPIC_LOCAL_IRQ, | VM_INJECT_EXCEPTION, VM_LAPIC_IRQ, VM_LAPIC_LOCAL_IRQ, | ||||
VM_LAPIC_MSI, VM_IOAPIC_ASSERT_IRQ, VM_IOAPIC_DEASSERT_IRQ, | VM_LAPIC_MSI, VM_IOAPIC_ASSERT_IRQ, VM_IOAPIC_DEASSERT_IRQ, | ||||
VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ, | VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ, | ||||
VM_ISA_DEASSERT_IRQ, VM_ISA_PULSE_IRQ, VM_ISA_SET_IRQ_TRIGGER, | VM_ISA_DEASSERT_IRQ, VM_ISA_PULSE_IRQ, VM_ISA_SET_IRQ_TRIGGER, | ||||
VM_SET_CAPABILITY, VM_GET_CAPABILITY, VM_BIND_PPTDEV, | VM_SET_CAPABILITY, VM_GET_CAPABILITY, VM_BIND_PPTDEV, | ||||
VM_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_PPTDEV_MSI, | VM_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_PPTDEV_MSI, | ||||
VM_PPTDEV_MSIX, VM_INJECT_NMI, VM_STATS, VM_STAT_DESC, | VM_PPTDEV_MSIX, VM_GET_VBIOS, VM_INJECT_NMI, | ||||
VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE, | VM_STATS, VM_STAT_DESC, VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE, | ||||
VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA, | VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA, | ||||
VM_GLA2GPA_NOFAULT, | VM_GLA2GPA_NOFAULT, | ||||
VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU, | VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU, | ||||
VM_SET_INTINFO, VM_GET_INTINFO, | VM_SET_INTINFO, VM_GET_INTINFO, | ||||
VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME, | VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME, | ||||
VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY }; | VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY }; | ||||
if (len == NULL) { | if (len == NULL) { | ||||
Show All 10 Lines |