summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2020-08-03 23:23:51 +0000
committerPatrick Mooney <pmooney@oxide.computer>2020-08-10 22:55:03 +0000
commitc3d209cab1511045e9bb1a521f1bd85995d4fd7e (patch)
tree71b9a13bff494830762679bb3e0584f30ea463d7
parent40ae3b8f7394f061252c31a21b854ae328f6f269 (diff)
downloadillumos-joyent-c3d209cab1511045e9bb1a521f1bd85995d4fd7e.tar.gz
13008 bhyve devmem could match better
13009 mdb-bhyve mishandles memseg offsets 13010 bhyve should not exit when VM debugged Reviewed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Approved by: Robert Mustacchi <rm@fingolfin.org>
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c12
-rw-r--r--usr/src/cmd/bhyve/gdb.c36
-rw-r--r--usr/src/cmd/bhyve/gdb.h3
-rw-r--r--usr/src/lib/libvmm/libvmm.c30
-rw-r--r--usr/src/uts/i86pc/io/vmm/vm/vm_glue.h5
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c32
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c10
7 files changed, 106 insertions, 22 deletions
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index 3b717560c5..fbc9fab6b1 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -1311,8 +1311,20 @@ main(int argc, char *argv[])
if (dbg_port != 0)
init_dbgport(dbg_port);
+#ifdef __FreeBSD__
if (gdb_port != 0)
init_gdb(ctx, gdb_port, gdb_stop);
+#else
+ if (gdb_port < 0) {
+ /*
+ * Set up the internal gdb state needed for basic debugging, but
+ * skip the step of listening on a port for the GDB server.
+ */
+ init_mdb(ctx, gdb_stop);
+ } else if (gdb_port != 0) {
+ init_gdb(ctx, gdb_port, gdb_stop);
+ }
+#endif
if (bvmcons)
init_bvmcons();
diff --git a/usr/src/cmd/bhyve/gdb.c b/usr/src/cmd/bhyve/gdb.c
index 6f6884eee8..720a55c58b 100644
--- a/usr/src/cmd/bhyve/gdb.c
+++ b/usr/src/cmd/bhyve/gdb.c
@@ -1840,6 +1840,42 @@ limit_gdb_socket(int s)
}
#endif
+
+#ifndef __FreeBSD__
+/*
+ * Equivalent to init_gdb() below, but without configuring the listening socket.
+ * This will allow the bhyve process to tolerate mdb attaching/detaching from
+ * the instance while it is running.
+ */
+void
+init_mdb(struct vmctx *_ctx, bool wait)
+{
+ int error;
+
+ error = pthread_mutex_init(&gdb_lock, NULL);
+ if (error != 0)
+ errc(1, error, "gdb mutex init");
+ error = pthread_cond_init(&idle_vcpus, NULL);
+ if (error != 0)
+ errc(1, error, "gdb cv init");
+
+ ctx = _ctx;
+ stopped_vcpu = -1;
+ TAILQ_INIT(&breakpoints);
+ vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
+ if (wait) {
+ /*
+ * Set vcpu 0 in vcpus_suspended. This will trigger the
+ * logic in gdb_cpu_add() to suspend the first vcpu before
+ * it starts execution. The vcpu will remain suspended
+ * until a debugger connects.
+ */
+ CPU_SET(0, &vcpus_suspended);
+ stopped_vcpu = 0;
+ }
+}
+#endif
+
void
init_gdb(struct vmctx *_ctx, int sport, bool wait)
{
diff --git a/usr/src/cmd/bhyve/gdb.h b/usr/src/cmd/bhyve/gdb.h
index 93396c1c67..95afee7ac2 100644
--- a/usr/src/cmd/bhyve/gdb.h
+++ b/usr/src/cmd/bhyve/gdb.h
@@ -35,5 +35,8 @@ void gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit);
void gdb_cpu_mtrap(int vcpu);
void gdb_cpu_suspend(int vcpu);
void init_gdb(struct vmctx *ctx, int sport, bool wait);
+#ifndef __FreeBSD__
+void init_mdb(struct vmctx *ctx, bool wait);
+#endif
#endif /* !__GDB_H__ */
diff --git a/usr/src/lib/libvmm/libvmm.c b/usr/src/lib/libvmm/libvmm.c
index dc552a8de0..df3d8ec99f 100644
--- a/usr/src/lib/libvmm/libvmm.c
+++ b/usr/src/lib/libvmm/libvmm.c
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Oxide Computer Company
*/
/*
@@ -199,12 +200,31 @@ vmm_map(vmm_t *vmm, boolean_t writable)
for (ms = list_head(&vmm->vmm_memlist);
ms != NULL;
ms = list_next(&vmm->vmm_memlist, ms)) {
- off_t mapoff = ms->vms_gpa;
+ off_t mapoff;
+
+ if ((ms->vms_flags & VMM_MEMSEG_DEVMEM) == 0) {
+ /*
+ * sysmem segments will be located at an offset
+ * equivalent to their GPA.
+ */
+ mapoff = ms->vms_gpa;
+ } else {
+ /*
+ * devmem segments are located in a special region away
+ * from the normal GPA space.
+ */
+ if (vm_get_devmem_offset(vmm->vmm_ctx, ms->vms_segid,
+ &mapoff) != 0) {
+ goto fail;
+ }
+ }
- if ((ms->vms_flags & VMM_MEMSEG_DEVMEM) &&
- vm_get_devmem_offset(vmm->vmm_ctx, ms->vms_segid, &mapoff)
- != 0)
- goto fail;
+ /*
+ * While 'mapoff' points to the front of the segment, the actual
+ * mapping may be at some offset beyond that.
+ */
+ VERIFY(ms->vms_segoff >= 0);
+ mapoff += ms->vms_segoff;
vmm->vmm_memsize += ms->vms_maplen;
diff --git a/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h b/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
index f894fcaf68..436b8e9691 100644
--- a/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
+++ b/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
@@ -12,6 +12,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Oxide Computer Company
*/
#ifndef _VM_GLUE_
@@ -76,8 +77,8 @@ struct vm_page {
};
/* Illumos-specific functions for setup and operation */
-int vm_segmap_obj(struct vmspace *, vm_object_t, struct as *, caddr_t *,
- uint_t, uint_t, uint_t);
+int vm_segmap_obj(vm_object_t, off_t, size_t, struct as *, caddr_t *, uint_t,
+ uint_t, uint_t);
int vm_segmap_space(struct vmspace *, off_t, struct as *, caddr_t *, off_t,
uint_t, uint_t, uint_t);
void *vmspace_find_kva(struct vmspace *, uintptr_t, size_t);
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 4bf3153902..6526188b1c 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -14,6 +14,7 @@
* Copyright 2015 Pluribus Networks Inc.
* Copyright 2019 Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2020 Oxide Computer Company
*/
#include <sys/types.h>
@@ -184,25 +185,30 @@ vmmdev_devmem_create(vmm_softc_t *sc, struct vm_memseg *mseg, const char *name)
}
static boolean_t
-vmmdev_devmem_segid(vmm_softc_t *sc, off_t off, off_t len, int *segidp)
+vmmdev_devmem_segid(vmm_softc_t *sc, off_t off, off_t len, int *segidp,
+ off_t *map_offp)
{
list_t *dl = &sc->vmm_devmem_list;
vmm_devmem_entry_t *de = NULL;
+ const off_t map_end = off + len;
VERIFY(off >= VM_DEVMEM_START);
- for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
- /* XXX: Only hit on direct offset/length matches for now */
- if (de->vde_off == off && de->vde_len == len) {
- break;
- }
- }
- if (de == NULL) {
+ if (map_end < off) {
+ /* No match on overflow */
return (B_FALSE);
}
- *segidp = de->vde_segid;
- return (B_TRUE);
+ for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
+ const off_t item_end = de->vde_off + de->vde_len;
+
+ if (de->vde_off <= off && item_end >= map_end) {
+ *segidp = de->vde_segid;
+ *map_offp = off - de->vde_off;
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
}
static void
@@ -2076,9 +2082,10 @@ vmm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
vms = vm_get_vmspace(vm);
if (off >= VM_DEVMEM_START) {
int segid;
+ off_t map_off = 0;
/* Mapping a devmem "device" */
- if (!vmmdev_devmem_segid(sc, off, len, &segid)) {
+ if (!vmmdev_devmem_segid(sc, off, len, &segid, &map_off)) {
err = ENODEV;
goto out;
}
@@ -2086,7 +2093,8 @@ vmm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
if (err != 0) {
goto out;
}
- err = vm_segmap_obj(vms, vmo, as, addrp, prot, maxprot, flags);
+ err = vm_segmap_obj(vmo, map_off, len, as, addrp, prot, maxprot,
+ flags);
} else {
/* Mapping a part of the guest physical space */
err = vm_segmap_space(vms, off, as, addrp, len, prot, maxprot,
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
index 9bd55c41f2..bedc338474 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
@@ -12,6 +12,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Oxide Computer Company
*/
#include <sys/param.h>
@@ -894,12 +895,15 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags)
/* Provided custom for bhyve 'devmem' segment mapping */
int
-vm_segmap_obj(struct vmspace *vms, vm_object_t vmo, struct as *as,
+vm_segmap_obj(vm_object_t vmo, off_t map_off, size_t size, struct as *as,
caddr_t *addrp, uint_t prot, uint_t maxprot, uint_t flags)
{
- const size_t size = vmo->vmo_size;
int err;
+ VERIFY(map_off >= 0);
+ VERIFY(size <= vmo->vmo_size);
+ VERIFY((size + map_off) <= vmo->vmo_size);
+
if (vmo->vmo_type != OBJT_DEFAULT) {
/* Only support default objects for now */
return (ENOTSUP);
@@ -911,7 +915,7 @@ vm_segmap_obj(struct vmspace *vms, vm_object_t vmo, struct as *as,
if (err == 0) {
segvmm_crargs_t svma;
- svma.kaddr = vmo->vmo_data;
+ svma.kaddr = (caddr_t)vmo->vmo_data + map_off;
svma.prot = prot;
svma.cookie = vmo;
svma.hold = (segvmm_holdfn_t)vm_object_reference;