Hi tech The following diff allows vmd to specify which ports it can handle or fix "XXX something better than a hardcoded list here, maybe configure via vmd via the device list in vm create params?"
There are currently two implementation of bsearch in the kernel and this patch would add a third, I think these should be consolidated, but i didn't know where to put the new function. the implementations are in: - ieee80211_regdomain.c - sys/kern/kern_pledge.c Cheers Adam Index: sys/arch/amd64/amd64/vmm.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/vmm.c,v retrieving revision 1.221 diff -u -p -u -p -r1.221 vmm.c --- sys/arch/amd64/amd64/vmm.c 7 Oct 2018 22:43:06 -0000 1.221 +++ sys/arch/amd64/amd64/vmm.c 23 Oct 2018 11:37:56 -0000 @@ -114,6 +114,7 @@ int vmmioctl(dev_t, u_long, caddr_t, int int vmmclose(dev_t, int, int, struct proc *); int vmm_start(void); int vmm_stop(void); +int vmm_compare_vei_port(const void *a, const void *b); size_t vm_create_check_mem_ranges(struct vm_create_params *); int vm_create(struct vm_create_params *, struct proc *); int vm_run(struct vm_run_params *); @@ -1116,6 +1117,10 @@ vm_create(struct vm_create_params *vcp, return (ret); } rw_enter_write(&vm->vm_vcpu_lock); + + vcpu->vc_nportranges = vcp->vcp_nportranges; + memcpy(vcpu->vc_portranges, vcp->vcp_portranges, + vcpu->vc_nportranges * sizeof(vcp->vcp_portranges[0])); vcpu->vc_id = vm->vm_vcpu_ct; vm->vm_vcpu_ct++; SLIST_INSERT_HEAD(&vm->vm_vcpu_list, vcpu, vc_vcpu_link); @@ -5059,6 +5064,38 @@ vmm_get_guest_cpu_mode(struct vcpu *vcpu } /* + * XXX this should be consolidated in the kernel + * see + * - ieee80211_regdomain.c + * - sys/kern/kern_pledge.c + */ +#ifndef bsearch +const void *vmm_bsearch(const void *, const void *, size_t, size_t, + int (*)(const void *, const void *)); + +const void * +vmm_bsearch(const void *key, const void *base0, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + const char *base = base0; + int lim, cmp; + const void *p; + + for (lim = nmemb; lim != 0; lim >>= 1) { + p = base + (lim >> 1) * size; + cmp = (*compar)(key, p); + if (cmp == 0) + return ((const void *)p); + if (cmp > 0) { /* key > p: move right */ + base = (const char *)p + size; + lim--; + } /* else move left */ + } + return (NULL); +} +#endif + +/* * svm_handle_inout * * Exit handler for IN/OUT instructions. @@ -5113,28 +5150,15 @@ svm_handle_inout(struct vcpu *vcpu) vcpu->vc_gueststate.vg_rip += insn_length; /* - * The following ports usually belong to devices owned by vmd. + * The ports specified by vc_portranges belong to devices owned by vmd. * Return EAGAIN to signal help needed from userspace (vmd). * Return 0 to indicate we don't care about this port. - * - * XXX something better than a hardcoded list here, maybe - * configure via vmd via the device list in vm create params? */ - switch (vcpu->vc_exit.vei.vei_port) { - case IO_ICU1 ... IO_ICU1 + 1: - case 0x40 ... 0x43: - case PCKBC_AUX: - case IO_RTC ... IO_RTC + 1: - case IO_ICU2 ... IO_ICU2 + 1: - case 0x3f8 ... 0x3ff: - case ELCR0 ... ELCR1: - case 0x500 ... 0x50f: - case 0xcf8: - case 0xcfc ... 0xcff: - case VMM_PCI_IO_BAR_BASE ... VMM_PCI_IO_BAR_END: + if (vmm_bsearch(&vcpu->vc_exit.vei.vei_port, vcpu->vc_portranges, + vcpu->vc_nportranges, sizeof(struct vm_port_range), + vmm_compare_vei_port)) { ret = EAGAIN; - break; - default: + } else { /* Read from unsupported ports returns FFs */ if (vcpu->vc_exit.vei.vei_dir == 1) { switch(vcpu->vc_exit.vei.vei_size) { @@ -5206,28 +5230,15 @@ vmx_handle_inout(struct vcpu *vcpu) vcpu->vc_gueststate.vg_rip += insn_length; /* - * The following ports usually belong to devices owned by vmd. + * The ports specified by vc_portranges belong to devices owned by vmd. * Return EAGAIN to signal help needed from userspace (vmd). * Return 0 to indicate we don't care about this port. - * - * XXX something better than a hardcoded list here, maybe - * configure via vmd via the device list in vm create params? */ - switch (vcpu->vc_exit.vei.vei_port) { - case IO_ICU1 ... IO_ICU1 + 1: - case 0x40 ... 0x43: - case PCKBC_AUX: - case IO_RTC ... IO_RTC + 1: - case IO_ICU2 ... IO_ICU2 + 1: - case 0x3f8 ... 0x3ff: - case ELCR0 ... ELCR1: - case 0xcf8: - case 0xcfc ... 0xcff: - case 0x500 ... 0x50f: - case VMM_PCI_IO_BAR_BASE ... VMM_PCI_IO_BAR_END: + if (vmm_bsearch(&vcpu->vc_exit.vei.vei_port, vcpu->vc_portranges, + vcpu->vc_nportranges, sizeof(struct vm_port_range), + vmm_compare_vei_port)) { ret = EAGAIN; - break; - default: + } else { /* Read from unsupported ports returns FFs */ if (vcpu->vc_exit.vei.vei_dir == VEI_DIR_IN) { if (vcpu->vc_exit.vei.vei_size == 4) @@ -5243,6 +5254,19 @@ vmx_handle_inout(struct vcpu *vcpu) return (ret); } +int +vmm_compare_vei_port(const void *a, const void *b) +{ + const uint16_t vei_port = *(uint16_t*)a; + const struct vm_port_range port_range = *(struct vm_port_range*)b; + + if(vei_port < port_range.vpr_lower_port) + return -1; + if(vei_port > port_range.vpr_upper_port) + return 1; + else + return 0; +} /* * vmx_load_pdptes * Index: sys/arch/amd64/include/vmmvar.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/vmmvar.h,v retrieving revision 1.59 diff -u -p -u -p -r1.59 vmmvar.h --- sys/arch/amd64/include/vmmvar.h 20 Sep 2018 14:32:59 -0000 1.59 +++ sys/arch/amd64/include/vmmvar.h 23 Oct 2018 11:37:57 -0000 @@ -32,6 +32,7 @@ #define VMM_MAX_VCPUS_PER_VM 64 #define VMM_MAX_VM_MEM_SIZE 32768 #define VMM_MAX_NICS_PER_VM 4 +#define VMM_MAX_PORT_RANGES 16 #define VMM_PCI_MMIO_BAR_BASE 0xF0000000ULL #define VMM_PCI_MMIO_BAR_END 0xFFFFFFFFULL @@ -430,6 +431,11 @@ struct vm_mem_range { size_t vmr_size; }; +struct vm_port_range { + uint16_t vpr_lower_port; + uint16_t vpr_upper_port; +}; + /* * struct vm_exit * @@ -450,12 +456,14 @@ struct vm_create_params { size_t vcp_ncpus; size_t vcp_ndisks; size_t vcp_nnics; + size_t vcp_nportranges; struct vm_mem_range vcp_memranges[VMM_MAX_MEM_RANGES]; char vcp_disks[VMM_MAX_DISKS_PER_VM][VMM_MAX_PATH_DISK]; char vcp_cdrom[VMM_MAX_PATH_CDROM]; char vcp_name[VMM_MAX_NAME_LEN]; char vcp_kernel[VMM_MAX_KERNEL_PATH]; uint8_t vcp_macs[VMM_MAX_NICS_PER_VM][6]; + struct vm_port_range vcp_portranges[VMM_MAX_PORT_RANGES]; /* Output parameter from VMM_IOC_CREATE */ uint32_t vcp_id; @@ -840,6 +848,9 @@ struct vcpu { /* MSR bitmap address */ vaddr_t vc_msr_bitmap_va; uint64_t vc_msr_bitmap_pa; + + size_t vc_nportranges; + struct vm_port_range vc_portranges[VMM_MAX_PORT_RANGES]; struct vm *vc_parent; uint32_t vc_id; Index: usr.sbin/vmd/vmd.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/vmd.c,v retrieving revision 1.104 diff -u -p -u -p -r1.104 vmd.c --- usr.sbin/vmd/vmd.c 15 Oct 2018 10:35:41 -0000 1.104 +++ usr.sbin/vmd/vmd.c 23 Oct 2018 11:38:02 -0000 @@ -41,6 +41,8 @@ #include <pwd.h> #include <grp.h> +#include <dev/isa/isareg.h> + #include <machine/specialreg.h> #include <machine/vmmvar.h> @@ -72,6 +74,30 @@ static struct privsep_proc procs[] = { { "vmm", PROC_VMM, vmd_dispatch_vmm, vmm, vmm_shutdown }, }; +/* The following ports belong to devices owned by vmd. */ +static struct vm_port_range port_ranges[] = { + {.vpr_lower_port = IO_ICU1, + .vpr_upper_port = IO_ICU1 + 1}, + {.vpr_lower_port = 0x40, + .vpr_upper_port = 0x43}, + {.vpr_lower_port = PCKBC_AUX, + .vpr_upper_port = PCKBC_AUX}, + {.vpr_lower_port = IO_RTC, + .vpr_upper_port = IO_RTC + 1}, + {.vpr_lower_port = IO_ICU2, + .vpr_upper_port = IO_ICU2 + 1}, + {.vpr_lower_port = 0x3f8, + .vpr_upper_port = 0x3ff}, + {.vpr_lower_port = ELCR0, + .vpr_upper_port = ELCR1}, + {.vpr_lower_port = 0xcf8, + .vpr_upper_port = 0xcf8}, + {.vpr_lower_port = 0xcfc, + .vpr_upper_port = 0xcff}, + {.vpr_lower_port = VMM_PCI_IO_BAR_BASE, + .vpr_upper_port = VMM_PCI_IO_BAR_END} +}; + /* For the privileged process */ static struct privsep_proc *proc_priv = &procs[0]; static struct passwd proc_privpw; @@ -1219,6 +1245,7 @@ vm_register(struct privsep *ps, struct v vcp->vcp_ncpus = 1; if (vcp->vcp_memranges[0].vmr_size == 0) vcp->vcp_memranges[0].vmr_size = VM_DEFAULT_MEMORY; + vcp->vcp_nportranges = sizeof(port_ranges)/sizeof(port_ranges[0]); if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) { log_warnx("invalid number of CPUs"); goto fail; @@ -1239,6 +1266,9 @@ vm_register(struct privsep *ps, struct v *vcp->vcp_name == '_') { log_warnx("invalid VM name"); goto fail; + } else if(vcp->vcp_nportranges > VMM_MAX_PORT_RANGES) { + log_warnx("invalid number of port ranges"); + goto fail; } else { for (s = vcp->vcp_name; *s != '\0'; ++s) { if (!(isalnum(*s) || *s == '.' || *s == '-' || @@ -1248,6 +1278,8 @@ vm_register(struct privsep *ps, struct v } } } + + memcpy(&vcp->vcp_portranges, &port_ranges, sizeof(port_ranges)); /* track active users */ if (uid != 0 && env->vmd_users != NULL &&