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 &&