Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h +++ sys/amd64/include/vmm.h @@ -215,6 +215,7 @@ void *vm_gpa_hold(struct vm *, int vcpuid, vm_paddr_t gpa, size_t len, int prot, void **cookie); void vm_gpa_release(void *cookie); +vm_offset_t vm_gpa_to_kva(struct vm *vm, vm_paddr_t gpa, int len, uint16_t *hint); bool vm_mem_allocated(struct vm *vm, int vcpuid, vm_paddr_t gpa); int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval); @@ -343,6 +344,8 @@ struct vatpit *vm_atpit(struct vm *vm); struct vpmtmr *vm_pmtmr(struct vm *vm); struct vrtc *vm_rtc(struct vm *vm); +struct vtnet_be *vm_vtnet_be(struct vm *vm); +void *vm_ioport(struct vm *vm); /* * Inject exception 'vector' into the guest vcpu. This function returns 0 on Index: sys/amd64/include/vmm_dev.h =================================================================== --- sys/amd64/include/vmm_dev.h +++ sys/amd64/include/vmm_dev.h @@ -46,6 +46,7 @@ }; #define VM_MEMMAP_F_WIRED 0x01 #define VM_MEMMAP_F_IOMMU 0x02 +#define VM_MEMMAP_F_WIRED_KERNEL 0x04 #define VM_MEMSEG_NAME(m) ((m)->name[0] != '\0' ? (m)->name : NULL) struct vm_memseg { Index: sys/amd64/vmm/io/vatpic.h =================================================================== --- sys/amd64/vmm/io/vatpic.h +++ sys/amd64/vmm/io/vatpic.h @@ -40,11 +40,11 @@ void vatpic_cleanup(struct vatpic *vatpic); int vatpic_master_handler(struct vm *vm, int vcpuid, bool in, int port, - int bytes, uint32_t *eax); + int bytes, uint32_t *eax, void *arg); int vatpic_slave_handler(struct vm *vm, int vcpuid, bool in, int port, - int bytes, uint32_t *eax); + int bytes, uint32_t *eax, void *arg); int vatpic_elc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax); + uint32_t *eax, void *arg); int vatpic_assert_irq(struct vm *vm, int irq); int vatpic_deassert_irq(struct vm *vm, int irq); Index: sys/amd64/vmm/io/vatpic.c =================================================================== --- sys/amd64/vmm/io/vatpic.c +++ sys/amd64/vmm/io/vatpic.c @@ -708,7 +708,7 @@ int vatpic_master_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax) + uint32_t *eax, void *arg) { struct vatpic *vatpic; struct atpic *atpic; @@ -728,7 +728,7 @@ int vatpic_slave_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax) + uint32_t *eax, void *arg) { struct vatpic *vatpic; struct atpic *atpic; @@ -748,7 +748,7 @@ int vatpic_elc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax) + uint32_t *eax, void *arg) { struct vatpic *vatpic; bool is_master; Index: sys/amd64/vmm/io/vatpit.h =================================================================== --- sys/amd64/vmm/io/vatpit.h +++ sys/amd64/vmm/io/vatpit.h @@ -38,8 +38,8 @@ void vatpit_cleanup(struct vatpit *vatpit); int vatpit_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax); + uint32_t *eax, void *arg); int vatpit_nmisc_handler(struct vm *vm, int vcpuid, bool in, int port, - int bytes, uint32_t *eax); + int bytes, uint32_t *eax, void *arg); #endif /* _VATPIT_H_ */ Index: sys/amd64/vmm/io/vatpit.c =================================================================== --- sys/amd64/vmm/io/vatpit.c +++ sys/amd64/vmm/io/vatpit.c @@ -317,7 +317,7 @@ int vatpit_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax) + uint32_t *eax, void *arg) { struct vatpit *vatpit; struct channel *c; @@ -400,7 +400,7 @@ int vatpit_nmisc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *eax) + uint32_t *eax, void *arg) { struct vatpit *vatpit; Index: sys/amd64/vmm/io/vpmtmr.h =================================================================== --- sys/amd64/vmm/io/vpmtmr.h +++ sys/amd64/vmm/io/vpmtmr.h @@ -37,6 +37,6 @@ void vpmtmr_cleanup(struct vpmtmr *pmtmr); int vpmtmr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val); + uint32_t *eax, void *arg); #endif Index: sys/amd64/vmm/io/vpmtmr.c =================================================================== --- sys/amd64/vmm/io/vpmtmr.c +++ sys/amd64/vmm/io/vpmtmr.c @@ -79,7 +79,7 @@ int vpmtmr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val) + uint32_t *val, void *arg) { struct vpmtmr *vpmtmr; sbintime_t now, delta; Index: sys/amd64/vmm/io/vrtc.h =================================================================== --- sys/amd64/vmm/io/vrtc.h +++ sys/amd64/vmm/io/vrtc.h @@ -43,8 +43,8 @@ int vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval); int vrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val); + uint32_t *eax, void *arg); int vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val); + uint32_t *eax, void *arg); #endif Index: sys/amd64/vmm/io/vrtc.c =================================================================== --- sys/amd64/vmm/io/vrtc.c +++ sys/amd64/vmm/io/vrtc.c @@ -840,7 +840,7 @@ int vrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val) + uint32_t *val, void *arg) { struct vrtc *vrtc; @@ -863,7 +863,7 @@ int vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, - uint32_t *val) + uint32_t *val, void *arg) { struct vrtc *vrtc; struct rtcdev *rtc; Index: sys/amd64/vmm/net/if_vmnic.h =================================================================== --- /dev/null +++ sys/amd64/vmm/net/if_vmnic.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017-2018 Joyent Inc. + * Copyright (C) 2017-2018 Matthew Macy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VTNETBE_H_ +#define _VTNETBE_H_ +struct iflib_ctx; + +extern struct vtnet_be *(*vtnet_be_init)(struct vm *); +extern void (*vtnet_be_cleanup)(struct vtnet_be *); + +#endif /* _VTNETBE_H_ */ Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c +++ sys/amd64/vmm/vmm.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,7 @@ #include "vhpet.h" #include "vioapic.h" #include "vlapic.h" +#include "if_vmnic.h" #include "vpmtmr.h" #include "vrtc.h" #include "vmm_stat.h" @@ -128,6 +130,7 @@ struct mem_map { vm_paddr_t gpa; + vm_offset_t kva; size_t len; vm_ooffset_t segoff; int segid; @@ -166,13 +169,18 @@ struct vmspace *vmspace; /* (o) guest's address space */ char name[VM_MAX_NAMELEN]; /* (o) virtual machine name */ struct vcpu vcpu[VM_MAXCPU]; /* (i) guest vcpus */ + void *ioport; /* (i) ioport exit hook */ + void *vtnet_be; /* (i) vmnic hook */ /* The following describe the vm cpu topology */ uint16_t sockets; /* (o) num of sockets */ uint16_t cores; /* (o) num of cores/socket */ uint16_t threads; /* (o) num of threads/core */ uint16_t maxcpus; /* (o) max pluggable cpus */ + }; +void (*vtnet_be_cleanup)(struct vtnet_be *); +struct vtnet_be *(*vtnet_be_init)(struct vm *vm); static int vmm_initialized; static struct vmm_ops *ops; @@ -421,6 +429,9 @@ vm->vpmtmr = vpmtmr_init(vm); if (create) vm->vrtc = vrtc_init(vm); + vm->ioport = vm_ioport_init(vm); + if (vtnet_be_init) + vm->vtnet_be = vtnet_be_init(vm); CPU_ZERO(&vm->active_cpus); CPU_ZERO(&vm->debug_cpus); @@ -520,6 +531,9 @@ vhpet_cleanup(vm->vhpet); vatpic_cleanup(vm->vatpic); vioapic_cleanup(vm->vioapic); + vm_ioport_cleanup(vm, vm->ioport); + if (vtnet_be_cleanup) + vtnet_be_cleanup(vm->vtnet_be); for (i = 0; i < VM_MAXCPU; i++) vcpu_cleanup(vm, i, destroy); @@ -702,6 +716,7 @@ struct mem_seg *seg; struct mem_map *m, *map; vm_ooffset_t last; + vm_offset_t kva; int i, error; if (prot == 0 || (prot & ~(VM_PROT_ALL)) != 0) @@ -736,29 +751,92 @@ if (map == NULL) return (ENOSPC); + vm_object_reference(seg->object); error = vm_map_find(&vm->vmspace->vm_map, seg->object, first, &gpa, len, 0, VMFS_NO_SPACE, prot, prot, 0); if (error != KERN_SUCCESS) - return (EFAULT); - - vm_object_reference(seg->object); + goto mapfail; + kva = 0; if (flags & VM_MEMMAP_F_WIRED) { error = vm_map_wire(&vm->vmspace->vm_map, gpa, gpa + len, VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); if (error != KERN_SUCCESS) { - vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); - return (EFAULT); + printf("failed to wire kva 0x%012lx to 0x%012lx\n", gpa, gpa + len); + goto kernfail; + } + } + if (flags & VM_MEMMAP_F_WIRED_KERNEL) { + /* 256G after first usable address post direct map */ + kva = 0xfffffe4000000000; + vm_object_reference(seg->object); + error = vm_map_find(kernel_map, seg->object, first, &kva, + len, 0, VMFS_ANY_SPACE, VM_PROT_RW, VM_PROT_RW, 0); + if (error != KERN_SUCCESS) { + printf("failed to map 0x%lx bytes in to kernel map first: 0x%lx error: %d\n", + len, first, error); + goto kernfail; + } + error = vm_map_wire(kernel_map, kva, kva + len, + VM_MAP_WIRE_NOHOLES); + if (error != KERN_SUCCESS) { + printf("failed to wire kva 0x%012lx to 0x%012lx\n", kva, kva + len); + goto wirefail; } } map->gpa = gpa; + map->kva = kva; map->len = len; map->segoff = first; map->segid = segid; map->prot = prot; map->flags = flags; return (0); + wirefail: + vm_map_remove(kernel_map, kva, kva + len); + vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); + return (vm_mmap_to_errno(error)); + kernfail: + vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); + mapfail: + vm_object_deallocate(seg->object); + return (vm_mmap_to_errno(error)); +} + +vm_offset_t +vm_gpa_to_kva(struct vm *vm, vm_paddr_t gpa, int len, uint16_t *hint) +{ + vm_paddr_t curgpa; + vm_offset_t curkva; + struct mem_map *mm; + size_t curlen; + int i; + + if (__predict_true(*hint < VM_MAX_MEMMAPS)) { + mm = &vm->mem_maps[*hint]; + curlen = mm->len; + curgpa = mm->gpa; + curkva = mm->kva; + if (__predict_true((mm->flags & VM_MEMMAP_F_WIRED) && curlen && + !(gpa < curgpa || gpa + len > curgpa + curlen))) + return (curkva + (gpa - curgpa)); + } + for (i = 0; i < VM_MAX_MEMMAPS; i++) { + mm = &vm->mem_maps[i]; + if (__predict_false(mm->flags & VM_MEMMAP_F_WIRED) == 0) + continue; + curlen = mm->len; + curgpa = mm->gpa; + curkva = mm->kva; + if (curlen && !(gpa < curgpa || gpa + len > curgpa + curlen)) + break; + } + *hint = i; + if (i == VM_MAX_MEMMAPS) + return (0); + MPASS(curkva); + return (curkva + (gpa - curgpa)); } int @@ -802,13 +880,22 @@ int error; mm = &vm->mem_maps[ident]; - if (mm->len) { - error = vm_map_remove(&vm->vmspace->vm_map, mm->gpa, - mm->gpa + mm->len); + if (mm->len == 0) + return; + + error = vm_map_remove(&vm->vmspace->vm_map, mm->gpa, + mm->gpa + mm->len); + KASSERT(error == KERN_SUCCESS, ("%s: vm_map_remove error %d", + __func__, error)); + if (mm->flags & VM_MEMMAP_F_WIRED_KERNEL) { + MPASS(mm->kva); + error = vm_map_remove(kernel_map, mm->kva, + mm->kva + mm->len); KASSERT(error == KERN_SUCCESS, ("%s: vm_map_remove error %d", - __func__, error)); - bzero(mm, sizeof(struct mem_map)); + __func__, error)); + } + bzero(mm, sizeof(struct mem_map)); } static __inline bool @@ -2569,6 +2656,13 @@ return (vm->vrtc); } +void * +vm_ioport(struct vm *vm) +{ + + return (vm->ioport); +} + enum vm_reg_name vm_segment_name(int seg) { Index: sys/amd64/vmm/vmm_ioport.h =================================================================== --- sys/amd64/vmm/vmm_ioport.h +++ sys/amd64/vmm/vmm_ioport.h @@ -30,8 +30,13 @@ #define _VMM_IOPORT_H_ typedef int (*ioport_handler_func_t)(struct vm *vm, int vcpuid, - bool in, int port, int bytes, uint32_t *val); + bool in, int port, int bytes, uint32_t *val, void *arg); int vm_handle_inout(struct vm *vm, int vcpuid, struct vm_exit *vme, bool *retu); +int vm_register_ioport(struct vm *vm, ioport_handler_func_t func, void *arg, + uint16_t start, uint16_t size); + +void *vm_ioport_init(struct vm *vm); +void vm_ioport_cleanup(struct vm *vm, void *hdl); #endif /* _VMM_IOPORT_H_ */ Index: sys/amd64/vmm/vmm_ioport.c =================================================================== --- sys/amd64/vmm/vmm_ioport.c +++ sys/amd64/vmm/vmm_ioport.c @@ -29,6 +29,9 @@ #include #include +#include +#include +#include #include #include @@ -42,6 +45,8 @@ #define MAX_IOPORTS 1280 +static MALLOC_DEFINE(M_VM_IOPORT, "vm_ioport", "vm_ioport"); + ioport_handler_func_t ioport_handler[MAX_IOPORTS] = { [TIMER_MODE] = vatpit_handler, [TIMER_CNTR0] = vatpit_handler, @@ -59,6 +64,17 @@ [IO_RTC + 1] = vrtc_data_handler, }; +#define MAX_SEGS 20 +struct ioport_segs { + int numsegs; + struct { + uint16_t start; + uint16_t size; + ioport_handler_func_t func; + void *arg; + } seg[MAX_SEGS]; +}; + #ifdef KTR static const char * inout_instruction(struct vm_exit *vmexit) @@ -97,19 +113,47 @@ } #endif /* KTR */ +static ioport_handler_func_t +inout_search(struct vm *vm, uint16_t port, void **arg) +{ + struct ioport_segs *segs; + ioport_handler_func_t handler; + int i; + + segs = vm_ioport(vm); + handler = NULL; + + for (i = 0; i < segs->numsegs; i++) { + if (port >= segs->seg[i].start && + port < (segs->seg[i].start + segs->seg[i].size)) { + handler = segs->seg[i].func; + *arg = segs->seg[i].arg; + break; + } + } + + return (handler); +} + static int emulate_inout_port(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) { ioport_handler_func_t handler; + void *arg; uint32_t mask, val; int error; /* * If there is no handler for the I/O port then punt to userspace. */ - if (vmexit->u.inout.port >= MAX_IOPORTS || - (handler = ioport_handler[vmexit->u.inout.port]) == NULL) { + if (vmexit->u.inout.port < MAX_IOPORTS) { + handler = ioport_handler[vmexit->u.inout.port]; + arg = NULL; + } else + handler = inout_search(vm, vmexit->u.inout.port, &arg); + + if (handler == NULL) { *retu = true; return (0); } @@ -121,7 +165,8 @@ } error = (*handler)(vm, vcpuid, vmexit->u.inout.in, - vmexit->u.inout.port, vmexit->u.inout.bytes, &val); + vmexit->u.inout.port, vmexit->u.inout.bytes, &val, arg); + if (error) { /* * The value returned by this function is also the return value @@ -174,3 +219,50 @@ return (error); } + +void * +vm_ioport_init(struct vm *vm) +{ + + return (malloc(sizeof(struct ioport_segs), M_VM_IOPORT, + M_WAITOK | M_ZERO)); +} + +void +vm_ioport_cleanup(struct vm *vm, void *hdl) +{ + + free(hdl, M_VM_IOPORT); +} + +int +vm_register_ioport(struct vm *vm, ioport_handler_func_t func, void *arg, + uint16_t start, uint16_t size) +{ + struct ioport_segs *segs; + int i; + + segs = vm_ioport(vm); + + if (segs->numsegs == MAX_SEGS) + return (ENOSPC); + + /* + * No locking needed - assumes all operations are done + * prior to running or in UP context + */ + for (i = 0; i < segs->numsegs; i++) { + /* Make sure existing mappings don't overlap */ + if (!(start >= (segs->seg[i].start + segs->seg[i].size) || + (start + size) < segs->seg[i].start)) + return (EINVAL); + } + + segs->seg[i].start = start; + segs->seg[i].size = size; + segs->seg[i].func = func; + segs->seg[i].arg = arg; + segs->numsegs++; + + return (0); +} Index: sys/modules/vmm/Makefile =================================================================== --- sys/modules/vmm/Makefile +++ sys/modules/vmm/Makefile @@ -11,6 +11,7 @@ CFLAGS+= -I${SRCTOP}/sys/amd64/vmm/io CFLAGS+= -I${SRCTOP}/sys/amd64/vmm/intel CFLAGS+= -I${SRCTOP}/sys/amd64/vmm/amd +CFLAGS+= -I${SRCTOP}/sys/amd64/vmm/net # generic vmm support .PATH: ${SRCTOP}/sys/amd64/vmm