diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2020-08-03 23:23:51 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@oxide.computer> | 2020-08-10 22:55:03 +0000 |
commit | c3d209cab1511045e9bb1a521f1bd85995d4fd7e (patch) | |
tree | 71b9a13bff494830762679bb3e0584f30ea463d7 | |
parent | 40ae3b8f7394f061252c31a21b854ae328f6f269 (diff) | |
download | illumos-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.c | 12 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/gdb.c | 36 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/gdb.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libvmm/libvmm.c | 30 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/vm/vm_glue.h | 5 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c | 32 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c | 10 |
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; |