summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@joyent.com>2019-01-15 16:29:40 +0100
committerPatrick Mooney <pmooney@pfmooney.com>2020-05-22 18:59:54 +0000
commit9c3024a3457d2d1269be18124a1ac69e33000da7 (patch)
treeb655da9bdab2b38e793d29c0af87e4e5b615c67d /usr
parent88d6421c15f1c4daea9c8128e715662091258054 (diff)
downloadillumos-joyent-9c3024a3457d2d1269be18124a1ac69e33000da7.tar.gz
12682 want mdb-bhyve module
Portions contributed by: Andy Fiddaman <omnios@citrus-it.co.uk> Portions contributed by: John Levon <john.levon@joyent.com> Portions contributed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: John Levon <john.levon@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr')
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c30
-rw-r--r--usr/src/cmd/bhyve/bhyverun.h5
-rw-r--r--usr/src/cmd/bhyve/gdb.c4
-rw-r--r--usr/src/cmd/bhyve/spinup_ap.c4
-rw-r--r--usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c2
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c7
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_create.c9
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_fmt.c6
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_kproc.c3
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_kvm.c2
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_main.c32
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_rawfile.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_target.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_target.h13
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile3
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix.c79
-rw-r--r--usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile3
-rw-r--r--usr/src/cmd/mdb/intel/Makefile.kmdb3
-rw-r--r--usr/src/cmd/mdb/intel/amd64/Makefile.kmdb5
-rw-r--r--usr/src/cmd/mdb/intel/amd64/mdb/Makefile17
-rw-r--r--usr/src/cmd/mdb/intel/kmdb/kaif.c34
-rw-r--r--usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c1
-rw-r--r--usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c1
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c35
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c1461
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c83
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_isautil.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_kreg.h12
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_x86util.c215
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_x86util.h68
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c4
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c6
-rw-r--r--usr/src/compat/freebsd/amd64/machine/specialreg.h1
-rw-r--r--usr/src/lib/Makefile3
-rw-r--r--usr/src/lib/libvmm/Makefile43
-rw-r--r--usr/src/lib/libvmm/Makefile.com51
-rw-r--r--usr/src/lib/libvmm/amd64/Makefile19
-rw-r--r--usr/src/lib/libvmm/libvmm.c860
-rw-r--r--usr/src/lib/libvmm/libvmm.h122
-rw-r--r--usr/src/lib/libvmm/mapfile-vers60
-rw-r--r--usr/src/lib/libvmmapi/common/mapfile-vers2
-rw-r--r--usr/src/lib/libvmmapi/common/vmmapi.c51
-rw-r--r--usr/src/lib/libvmmapi/common/vmmapi.h10
-rw-r--r--usr/src/man/man1/mdb.126
-rw-r--r--usr/src/pkg/manifests/system-library-bhyve.mf1
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm.c4
-rw-r--r--usr/src/uts/intel/sys/controlregs.h22
-rw-r--r--usr/src/uts/intel/sys/debugreg.h7
50 files changed, 3271 insertions, 187 deletions
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index 928d2dc811..07489ad8d5 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -251,6 +251,9 @@ usage(int code)
" -A: create ACPI tables\n"
" -c: number of cpus and/or topology specification\n"
" -C: include guest memory in core file\n"
+#ifndef __FreeBSD__
+ " -d: suspend cpu at boot\n"
+#endif
" -e: exit on unhandled I/O access\n"
" -g: gdb port\n"
" -h: help\n"
@@ -500,8 +503,14 @@ fbsdrun_start_thread(void *param)
return (NULL);
}
+#ifdef __FreeBSD__
void
fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip)
+#else
+void
+fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip,
+ bool suspend)
+#endif
{
int error;
@@ -519,6 +528,11 @@ fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip)
CPU_SET_ATOMIC(newcpu, &cpumask);
+#ifndef __FreeBSD__
+ if (suspend)
+ (void) vm_suspend_cpu(ctx, newcpu);
+#endif
+
/*
* Set up the vmexit struct to allow execution to start
* at the given RIP
@@ -1057,6 +1071,9 @@ main(int argc, char *argv[])
int max_vcpus, mptgen, memflags;
int rtc_localtime;
bool gdb_stop;
+#ifndef __FreeBSD__
+ bool suspend = false;
+#endif
struct vmctx *ctx;
uint64_t rip;
size_t memsize;
@@ -1078,7 +1095,7 @@ main(int argc, char *argv[])
#ifdef __FreeBSD__
optstr = "abehuwxACHIPSWYp:g:G:c:s:m:l:B:U:";
#else
- optstr = "abehuwxACHIPSWYg:G:c:s:m:l:B:U:";
+ optstr = "abdehuwxACHIPSWYg:G:c:s:m:l:B:U:";
#endif
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
@@ -1097,7 +1114,11 @@ main(int argc, char *argv[])
"configuration '%s'", optarg);
}
break;
-#ifdef __FreeBSD__
+#ifndef __FreeBSD__
+ case 'd':
+ suspend = true;
+ break;
+#else
case 'p':
if (pincpu_parse(optarg) != 0) {
errx(EX_USAGE, "invalid vcpu pinning "
@@ -1331,8 +1352,11 @@ main(int argc, char *argv[])
/*
* Add CPU 0
*/
+#ifdef __FreeBSD__
fbsdrun_addcpu(ctx, BSP, BSP, rip);
-
+#else
+ fbsdrun_addcpu(ctx, BSP, BSP, rip, suspend);
+#endif
/*
* Head off to the main event dispatch loop
*/
diff --git a/usr/src/cmd/bhyve/bhyverun.h b/usr/src/cmd/bhyve/bhyverun.h
index 78b3f1111f..8df8e01a73 100644
--- a/usr/src/cmd/bhyve/bhyverun.h
+++ b/usr/src/cmd/bhyve/bhyverun.h
@@ -61,7 +61,12 @@ extern pthread_cond_t bcons_wait_done;
void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len);
void fbsdrun_set_capabilities(struct vmctx *ctx, int cpu);
+#ifdef __FreeBSD__
void fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip);
+#else
+void fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip,
+ bool suspend);
+#endif
int fbsdrun_muxed(void);
int fbsdrun_vmexit_on_hlt(void);
int fbsdrun_vmexit_on_pause(void);
diff --git a/usr/src/cmd/bhyve/gdb.c b/usr/src/cmd/bhyve/gdb.c
index 20c2de1dec..71cb780544 100644
--- a/usr/src/cmd/bhyve/gdb.c
+++ b/usr/src/cmd/bhyve/gdb.c
@@ -75,7 +75,11 @@ static cpuset_t vcpus_active, vcpus_suspended, vcpus_waiting;
static pthread_mutex_t gdb_lock;
static pthread_cond_t idle_vcpus;
static bool stop_pending, first_stop;
+#ifdef __FreeBSD__
static int stepping_vcpu, stopped_vcpu;
+#else
+static int stepping_vcpu = -1, stopped_vcpu = -1;
+#endif
/*
* An I/O buffer contains 'capacity' bytes of room at 'data'. For a
diff --git a/usr/src/cmd/bhyve/spinup_ap.c b/usr/src/cmd/bhyve/spinup_ap.c
index 7c4186f5ed..ecdd05694c 100644
--- a/usr/src/cmd/bhyve/spinup_ap.c
+++ b/usr/src/cmd/bhyve/spinup_ap.c
@@ -100,7 +100,11 @@ spinup_ap(struct vmctx *ctx, int vcpu, int newcpu, uint64_t rip)
spinup_ap_realmode(ctx, newcpu, &rip);
+#ifdef __FreeBSD__
fbsdrun_addcpu(ctx, vcpu, newcpu, rip);
+#else
+ fbsdrun_addcpu(ctx, vcpu, newcpu, rip, false);
+#endif
return (newcpu);
}
diff --git a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
index 90fd098d1c..628503d179 100644
--- a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
+++ b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
@@ -286,6 +286,8 @@ kmt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
case (uintptr_t)MDB_TGT_AS_IO:
return (set_errno(EINVAL));
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
if ((asp = (struct as *)kmt_read_kas(t)) == NULL)
return (-1); /* errno is set for us */
break;
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index b7b15aa507..10c622443a 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -2090,7 +2090,7 @@ cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
if (opt_f)
as = MDB_TGT_AS_FILE;
else
- as = MDB_TGT_AS_VIRT;
+ as = MDB_TGT_AS_VIRT_I;
if (opt_w == FALSE) {
n++;
@@ -2635,8 +2635,9 @@ tgt_status(const mdb_tgt_status_t *tsp)
return (DCMD_OK);
if (tsp->st_pc != 0) {
- if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
- buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
+ if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
+ MDB_TGT_AS_VIRT_I, buf, sizeof (buf), tsp->st_pc) !=
+ tsp->st_pc)
format = "target stopped at:\n%-#16a%8T%s\n";
else
format = "target stopped at %a:\n";
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_create.c b/usr/src/cmd/mdb/common/mdb/mdb_create.c
index ea30457ef0..86490bf825 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_create.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_create.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
#include <mdb/mdb.h>
#include <mdb/mdb_conf.h>
@@ -51,6 +53,11 @@ mdb_create_builtin_tgts(void)
if ((mp = mdb_module_load_builtin("mdb_raw")) != NULL)
mp->mod_tgt_ctor = mdb_rawfile_tgt_create;
+
+#ifdef __amd64
+ if ((mp = mdb_module_load_builtin("mdb_bhyve")) != NULL)
+ mp->mod_tgt_ctor = mdb_bhyve_tgt_create;
+#endif
}
void
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
index 662cf7bea5..6a745b2ac4 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
@@ -411,6 +411,9 @@ fmt_instr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
char buf[BUFSIZ];
uintptr_t naddr;
+ if (as == MDB_TGT_AS_VIRT)
+ as = MDB_TGT_AS_VIRT_I;
+
while (cnt-- != 0) {
naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
buf, sizeof (buf), addr);
@@ -431,6 +434,9 @@ fmt_dotinstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
uintptr_t naddr;
uint32_t i;
+ if (as == MDB_TGT_AS_VIRT)
+ as = MDB_TGT_AS_VIRT_I;
+
for (mdb_iob_clrflags(mdb.m_out, oflags); cnt-- != 0; addr = naddr) {
if (mdb_tgt_aread(t, as, &i, sizeof (i), addr) != sizeof (i)) {
warn("failed to read data from target");
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
index e13dcea53f..4eeb8ac708 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
@@ -553,7 +553,8 @@ kp_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
kp_data_t *kp = t->t_data;
physaddr_t pa;
- if (as != MDB_TGT_AS_VIRT)
+ if (as != MDB_TGT_AS_VIRT && as != MDB_TGT_AS_VIRT_I &&
+ as != MDB_TGT_AS_VIRT_S)
return (set_errno(EINVAL));
if ((pa = kvm_physaddr(kp->kp_cookie, kp->kp_as, va)) != -1ULL) {
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
index fe280c05c7..27ca238ca9 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
@@ -814,6 +814,8 @@ kt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
case (uintptr_t)MDB_TGT_AS_IO:
return (set_errno(EINVAL));
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
asp = kt->k_as;
break;
default:
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_main.c b/usr/src/cmd/mdb/common/mdb/mdb_main.c
index eea4b5b60e..8747464328 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_main.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c
@@ -322,12 +322,13 @@ static void
usage(int status)
{
mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
- "[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
+ "[-b VM] [-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
"[-R root] [-V dis-version] [-e expr] "
"[object [core] | core | suffix]\n\n",
mdb.m_pname);
mdb_iob_puts(mdb.m_err,
+ "\t-b attach to specified bhyve VM\n"
"\t-e evaluate expr and return status\n"
"\t-f force raw file debugging mode\n"
"\t-k force kernel debugging mode\n"
@@ -405,6 +406,19 @@ identify_xvm_file(const char *file, int *longmode)
}
#endif /* __x86 */
+#ifndef __amd64
+/*
+ * There is no bhyve target in a 32bit x86 or any SPARC mdb. This dummy helps
+ * keep the code simpler.
+ */
+/*ARGSUSED*/
+static int
+mdb_bhyve_tgt_create(mdb_tgt_t *t, int argc, const char *argv[])
+{
+ return (set_errno(EINVAL));
+}
+#endif
+
int
main(int argc, char *argv[], char *envp[])
{
@@ -424,6 +438,7 @@ main(int argc, char *argv[], char *envp[])
const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL;
const char *eflag = NULL;
int fflag = 0, Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0;
+ int bflag = 0;
int ttylike;
int longmode = 0;
@@ -513,8 +528,12 @@ main(int argc, char *argv[], char *envp[])
while (optind < argc) {
while ((c = getopt(argc, argv,
- "e:fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
+ "be:fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
switch (c) {
+ case 'b':
+ bflag++;
+ tgt_ctor = mdb_bhyve_tgt_create;
+ break;
case 'e':
if (eflag != NULL) {
warn("-e already specified\n");
@@ -830,6 +849,15 @@ main(int argc, char *argv[], char *envp[])
if (fflag)
goto tcreate; /* skip re-exec and just create target */
+ /* bhyve: directly create target, or re-exec in case of 32bit */
+ if (bflag) {
+#ifndef __amd64
+ goto reexec;
+#else
+ goto tcreate;
+#endif
+ }
+
/*
* If we just have an object file name, and that file doesn't
* exist, and it's a string of digits, infer it to be a
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c b/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
index 086639de74..d21ad0f38a 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
@@ -143,6 +143,8 @@ rf_aread(mdb_tgt_t *t, mdb_tgt_as_t as, void *buf,
{
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
case (uintptr_t)MDB_TGT_AS_PHYS:
if (RF_CORE(t->t_data) != NULL)
return (rf_read(RF_CORE(t->t_data), buf, len, addr));
@@ -160,6 +162,8 @@ rf_awrite(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf,
{
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
case (uintptr_t)MDB_TGT_AS_PHYS:
if (RF_CORE(t->t_data) != NULL)
return (rf_write(RF_CORE(t->t_data), buf, len, addr));
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target.c b/usr/src/cmd/mdb/common/mdb/mdb_target.c
index 17aef0aac1..e0ae29bd99 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_target.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target.c
@@ -398,6 +398,8 @@ mdb_tgt_aread(mdb_tgt_t *t, mdb_tgt_as_t as,
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
return (t->t_ops->t_vread(t, buf, n, addr));
case (uintptr_t)MDB_TGT_AS_PHYS:
return (t->t_ops->t_pread(t, buf, n, addr));
@@ -421,6 +423,8 @@ mdb_tgt_awrite(mdb_tgt_t *t, mdb_tgt_as_t as,
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
return (t->t_ops->t_vwrite(t, buf, n, addr));
case (uintptr_t)MDB_TGT_AS_PHYS:
return (t->t_ops->t_pwrite(t, buf, n, addr));
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target.h b/usr/src/cmd/mdb/common/mdb/mdb_target.h
index c36b85e2f3..e385caa38e 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_target.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target.h
@@ -64,6 +64,9 @@ extern int mdb_kvm_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_proc_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_kproc_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_rawfile_tgt_create(mdb_tgt_t *, int, const char *[]);
+#ifdef __amd64
+extern int mdb_bhyve_tgt_create(mdb_tgt_t *, int, const char *[]);
+#endif
#else
extern int kmdb_kvm_create(mdb_tgt_t *, int, const char *[]);
#endif
@@ -139,10 +142,12 @@ typedef void * mdb_tgt_as_t; /* Opaque address space id */
typedef uint64_t mdb_tgt_addr_t; /* Generic unsigned address */
typedef uint64_t physaddr_t; /* Physical memory address */
-#define MDB_TGT_AS_VIRT ((mdb_tgt_as_t)-1L) /* Virtual address space */
-#define MDB_TGT_AS_PHYS ((mdb_tgt_as_t)-2L) /* Physical address space */
-#define MDB_TGT_AS_FILE ((mdb_tgt_as_t)-3L) /* Object file address space */
-#define MDB_TGT_AS_IO ((mdb_tgt_as_t)-4L) /* I/o address space */
+#define MDB_TGT_AS_VIRT ((mdb_tgt_as_t)-1L) /* Virtual address space: */
+#define MDB_TGT_AS_VIRT_I ((mdb_tgt_as_t)-2L) /* special case for code */
+#define MDB_TGT_AS_VIRT_S ((mdb_tgt_as_t)-3L) /* special case for stack */
+#define MDB_TGT_AS_PHYS ((mdb_tgt_as_t)-4L) /* Physical address space */
+#define MDB_TGT_AS_FILE ((mdb_tgt_as_t)-5L) /* Object file address space */
+#define MDB_TGT_AS_IO ((mdb_tgt_as_t)-6L) /* I/o address space */
extern ssize_t mdb_tgt_aread(mdb_tgt_t *, mdb_tgt_as_t,
void *, size_t, mdb_tgt_addr_t);
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile b/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
index efcfad5375..54bc62a086 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
@@ -22,7 +22,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
MODULE = unix.so
MDBTGT = kvm
@@ -38,6 +38,7 @@ include ../../../../Makefile.module
CPPFLAGS += -DMP -D_MACHDEP
CPPFLAGS += -I../../../../common
+CPPFLAGS += -I../../../../intel
CPPFLAGS += -I$(SRC)/uts/i86pc
CPPFLAGS += -I$(SRC)/uts/intel
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
index e91321b235..c3b7e809e4 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
@@ -20,11 +20,13 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2019 Joyent, Inc.
*/
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_x86util.h>
#include <sys/cpuvar.h>
#include <sys/systm.h>
#include <sys/traptrace.h>
@@ -963,73 +965,24 @@ x86_featureset_dcmd(uintptr_t addr, uint_t flags, int argc,
static int
sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
- ulong_t cr0, cr2, cr3, cr4;
+ struct sysregs sregs = { 0 };
desctbr_t gdtr;
+ boolean_t longmode = B_FALSE;
- static const mdb_bitmask_t cr0_flag_bits[] = {
- { "PE", CR0_PE, CR0_PE },
- { "MP", CR0_MP, CR0_MP },
- { "EM", CR0_EM, CR0_EM },
- { "TS", CR0_TS, CR0_TS },
- { "ET", CR0_ET, CR0_ET },
- { "NE", CR0_NE, CR0_NE },
- { "WP", CR0_WP, CR0_WP },
- { "AM", CR0_AM, CR0_AM },
- { "NW", CR0_NW, CR0_NW },
- { "CD", CR0_CD, CR0_CD },
- { "PG", CR0_PG, CR0_PG },
- { NULL, 0, 0 }
- };
-
- static const mdb_bitmask_t cr3_flag_bits[] = {
- { "PCD", CR3_PCD, CR3_PCD },
- { "PWT", CR3_PWT, CR3_PWT },
- { NULL, 0, 0, }
- };
-
- static const mdb_bitmask_t cr4_flag_bits[] = {
- { "VME", CR4_VME, CR4_VME },
- { "PVI", CR4_PVI, CR4_PVI },
- { "TSD", CR4_TSD, CR4_TSD },
- { "DE", CR4_DE, CR4_DE },
- { "PSE", CR4_PSE, CR4_PSE },
- { "PAE", CR4_PAE, CR4_PAE },
- { "MCE", CR4_MCE, CR4_MCE },
- { "PGE", CR4_PGE, CR4_PGE },
- { "PCE", CR4_PCE, CR4_PCE },
- { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
- { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
- { "VMXE", CR4_VMXE, CR4_VMXE },
- { "SMXE", CR4_SMXE, CR4_SMXE },
- { "PCIDE", CR4_PCIDE, CR4_PCIDE },
- { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
- { "SMEP", CR4_SMEP, CR4_SMEP },
- { "SMAP", CR4_SMAP, CR4_SMAP },
- { NULL, 0, 0 }
- };
-
- cr0 = kmdb_unix_getcr0();
- cr2 = kmdb_unix_getcr2();
- cr3 = kmdb_unix_getcr3();
- cr4 = kmdb_unix_getcr4();
-
- kmdb_unix_getgdtr(&gdtr);
+#ifdef __amd64
+ longmode = B_TRUE;
+#endif
- mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
- mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
+ sregs.sr_cr0 = kmdb_unix_getcr0();
+ sregs.sr_cr2 = kmdb_unix_getcr2();
+ sregs.sr_cr3 = kmdb_unix_getcr3();
+ sregs.sr_cr4 = kmdb_unix_getcr4();
- if ((cr4 & CR4_PCIDE)) {
- mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3,
- cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET);
- } else {
- mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3,
- cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits);
- }
-
- mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
+ kmdb_unix_getgdtr(&gdtr);
+ sregs.sr_gdtr.d_base = gdtr.dtr_base;
+ sregs.sr_gdtr.d_lim = gdtr.dtr_limit;
- mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n",
- gdtr.dtr_base, gdtr.dtr_limit);
+ mdb_x86_print_sysregs(&sregs, longmode);
return (DCMD_OK);
}
diff --git a/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile b/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
index 32c1fe33fd..5854a1610e 100644
--- a/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
+++ b/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
@@ -22,7 +22,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
MODULE = unix.so
MDBTGT = kvm
@@ -40,6 +40,7 @@ MODSRCS_DIR = ../../../../i86pc/modules/unix/
CPPFLAGS += -DMP -D_MACHDEP -D__xpv
CPPFLAGS += -I../../../../common
+CPPFLAGS += -I../../../../intel
CPPFLAGS += -I$(SRC)/uts/common
CPPFLAGS += -I$(SRC)/uts/i86xpv
CPPFLAGS += -I$(SRC)/uts/i86pc
diff --git a/usr/src/cmd/mdb/intel/Makefile.kmdb b/usr/src/cmd/mdb/intel/Makefile.kmdb
index 1e9efcbc83..6151a2e46a 100644
--- a/usr/src/cmd/mdb/intel/Makefile.kmdb
+++ b/usr/src/cmd/mdb/intel/Makefile.kmdb
@@ -22,7 +22,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2019, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
PROMSRCS += \
@@ -68,6 +68,7 @@ KMDBLIBS = $(STANDLIBS) ../mdb_ks/kmod/mdb_ks
MAPFILE_SOURCES = \
$(MAPFILE_SOURCES_COMMON) \
../../kmdb/kmdb_dpi_isadep.h \
+ ../../mdb/mdb_x86util.h \
$(MAPFILE_SOURCES_$(MACH))
%.o: ../../../../../uts/intel/promif/%.c
diff --git a/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb b/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
index 61cf1541a2..8cee9ff049 100644
--- a/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
+++ b/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
@@ -22,6 +22,8 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
KMDBML += \
kaif_invoke.s \
@@ -29,6 +31,7 @@ KMDBML += \
KMDBSRCS += \
kmdb_makecontext.c \
- mdb_amd64util.c
+ mdb_amd64util.c \
+ mdb_x86util.c
SACPPFLAGS = -D__$(MACH64) -U__$(MACH)
diff --git a/usr/src/cmd/mdb/intel/amd64/mdb/Makefile b/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
index 3dfa7a34d5..918aa71ea1 100644
--- a/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
+++ b/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
@@ -22,10 +22,15 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
SRCS = kvm_amd64dep.c \
kvm_isadep.c \
mdb_amd64util.c \
+ mdb_ia32util.c \
+ mdb_x86util.c \
+ mdb_bhyve.c \
proc_amd64dep.c
%.o: %.c
@@ -42,12 +47,14 @@ SRCS = kvm_amd64dep.c \
%.ln: ../../mdb/%.c
$(LINT.c) -c $<
-include ../../../../Makefile.cmd
-include ../../../../Makefile.cmd.64
-include ../../Makefile.amd64
-include ../../../Makefile.mdb
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/cmd/Makefile.cmd.64
+include $(SRC)/cmd/mdb/intel/Makefile.amd64
+include $(SRC)/cmd/mdb/Makefile.mdb
+include $(SRC)/Makefile.psm
CPPFLAGS += -I../../mdb
-LDLIBS += -lsaveargs
+
+LDLIBS += -lsaveargs -lvmm
install: all $(ISAEXEC) $(ROOTPROG64) $(ROOTLINK64)
diff --git a/usr/src/cmd/mdb/intel/kmdb/kaif.c b/usr/src/cmd/mdb/intel/kmdb/kaif.c
index 39cc9b620a..e4f80ad228 100644
--- a/usr/src/cmd/mdb/intel/kmdb/kaif.c
+++ b/usr/src/cmd/mdb/intel/kmdb/kaif.c
@@ -296,12 +296,12 @@ kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
return (set_errno(EMDB_TGTNOTSUP));
}
- if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, instrp,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
- if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_I, &bkpt,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
return (0);
@@ -310,8 +310,8 @@ kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
static int
kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
{
- if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_I, &instrp,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
return (0);
@@ -486,7 +486,7 @@ kaif_step(void)
}
if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
- MDB_TGT_AS_VIRT, pc)) == pc) {
+ MDB_TGT_AS_VIRT_I, pc)) == pc) {
warn("failed to decode instruction at %a for step\n", pc);
return (set_errno(EINVAL));
}
@@ -498,8 +498,8 @@ kaif_step(void)
* versus their 64-bit counterparts.
*/
do {
- if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
- pc + pcoff) != sizeof (mdb_instr_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, &instr,
+ sizeof (mdb_instr_t), pc + pcoff) != sizeof (mdb_instr_t)) {
warn("failed to read at %p for step",
(void *)(pc + pcoff));
return (-1);
@@ -518,8 +518,8 @@ kaif_step(void)
return (set_errno(EMDB_TGTNOTSUP));
case M_ESC:
- if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
- pc + pcoff) != sizeof (mdb_instr_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, &instr,
+ sizeof (mdb_instr_t), pc + pcoff) != sizeof (mdb_instr_t)) {
warn("failed to read at %p for step",
(void *)(pc + pcoff));
return (-1);
@@ -568,8 +568,8 @@ kaif_step(void)
(void) kmdb_dpi_get_register("sp", &sp);
(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
- if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_S, &newfl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to read " FLAGS_REG_NAME
" at %p for popfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
@@ -577,8 +577,8 @@ kaif_step(void)
fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
- if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_S, &fl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to update " FLAGS_REG_NAME
" at %p for popfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
@@ -617,8 +617,8 @@ kaif_step(void)
*/
(void) kmdb_dpi_get_register("sp", &sp);
- if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_S, &oldfl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to update pushed " FLAGS_REG_NAME
" at %p after pushfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
diff --git a/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
index f3352b6e21..0382c7e0fb 100644
--- a/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
@@ -46,6 +46,7 @@
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/kvm_isadep.h>
#include <mdb/mdb_kvm.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
index 2dfced82d3..7a6ecaeb6b 100644
--- a/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
@@ -45,6 +45,7 @@
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/kvm_isadep.h>
#include <mdb/mdb_kvm.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
index 14c81f47fd..7740a82d8f 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
@@ -39,6 +39,7 @@
#include <mdb/mdb_kreg_impl.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/mdb_ctf.h>
#include <mdb/mdb_err.h>
@@ -244,7 +245,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
while (fp != 0) {
int args_style = 0;
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) !=
+ sizeof (fr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -259,8 +261,9 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (advance_tortoise != 0) {
struct fr tfr;
- if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
- tortoise_fp) != sizeof (tfr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
+ sizeof (tfr), tortoise_fp) !=
+ sizeof (tfr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -330,7 +333,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
pc - s.st_value);
- if (mdb_tgt_vread(t, ins, insnsize, s.st_value) != insnsize)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, insnsize,
+ s.st_value) != insnsize)
argc = 0;
if ((argc != 0) &&
@@ -349,8 +353,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (args_style == SAVEARGS_STRUCT_ARGS)
size += sizeof (long);
- if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
- != size)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, fr_argv, size,
+ (fp - size)) != size)
return (-1); /* errno has been set for us */
/*
@@ -369,7 +373,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
sizeof (fr_argv) -
(reg_argc * sizeof (long)));
- if (mdb_tgt_vread(t, &fr_argv[reg_argc], size,
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S,
+ &fr_argv[reg_argc], size,
fp + sizeof (fr)) != size)
return (-1); /* errno has been set */
}
@@ -434,14 +439,15 @@ mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
fp = sp - 8;
else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
- if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
- pc + 1) == sizeof (curinstr) && curinstr ==
- M_MOVL_RBP)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
+ sizeof (curinstr), pc + 1) == sizeof (curinstr) &&
+ curinstr == M_MOVL_RBP)
fp = sp;
}
}
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
+ sizeof (fr)) {
*p = fr.fr_savpc;
return (0);
}
@@ -476,8 +482,8 @@ mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
/* Skip the rex prefix, if any */
callpc = pc;
while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
- if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
- sizeof (curinstr))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
+ sizeof (curinstr), ++callpc) != sizeof (curinstr))
return (-1); /* errno is set for us */
}
@@ -486,7 +492,8 @@ mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
return (set_errno(EAGAIN));
}
- if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
+ npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT_I, pc);
+ if (npc == pc)
return (-1); /* errno is set for us */
*p = npc;
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
index f8c6097cef..b3f060bf05 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
@@ -22,12 +22,13 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_AMD64UTIL_H
#define _MDB_AMD64UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_target_impl.h>
@@ -35,8 +36,6 @@
extern "C" {
#endif
-typedef uchar_t mdb_instr_t;
-
extern const mdb_tgt_regdesc_t mdb_amd64_kregs[];
extern void mdb_amd64_printregs(const mdb_tgt_gregset_t *);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c b/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c
new file mode 100644
index 0000000000..9477bf5056
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c
@@ -0,0 +1,1461 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * bhyve target
+ *
+ * The bhyve target is used to examine and manipulate a bhyve VM. Access to
+ * a bhyve VM is provided by libvmm, which itself uses libvmmapi, which uses
+ * the vmm driver's ioctl interface to carry out requests.
+ *
+ * The bhyve target does not know about threads or processes, but it handles
+ * multiple vCPUs and can switch between them. Execution control is currently
+ * limited to completely stopping or resuming all vCPUs of a VM, or single-
+ * stepping a particular vCPU while all other vCPUs remain stopped. Breakpoints
+ * are not implemented yet, and as such step-out and step-over don't work yet.
+ * All known x86 instruction sets are support, legacy IA-16, IA-32 and AMD64.
+ * The current CPU instruction set is automatically determined by parsing the
+ * code segment (CS) attributes in the current vCPU.
+ *
+ * All of the VMs physical memory and device memory segments are mapped R/W
+ * into mdb's address space by libvmm. All accesses to those memory are
+ * facilitated through libvmm calls, which may include virtual address
+ * translation according to the current vCPU mode. Both real-mode and protected-
+ * mode segmentation are understood and used for translating virtual addresses
+ * into linear addresses, which may further be translated using 2-level, 3-level
+ * or 4-level paging.
+ *
+ * To handle disassembly and stack tracing properly when segmentation is used by
+ * a vCPU (always in real mode, sometimes in protected mode) the bhyve target
+ * has a notion of three virtual address spaces used for reading/writing memory:
+ * - MDB_TGT_AS_VIRT, the default virtual address space uses the DS segment
+ * by default, but this default can be changed with the ::defseg dcmd.
+ * - MDB_TGT_AS_VIRT_I, the virtual address space for instructions always
+ * uses the code segment (CS) for translation
+ * - MDB_TGT_AS_VIRT_S, the virtual address space for the stack always uses
+ * the stack segment (SS) for translation
+ *
+ * Register printing and stack tracing is using the common x86 ISA-specific code
+ * in IA-32 and AMD64 modes. There is no stack tracing for IA-16 mode yet.
+ *
+ * Todo:
+ * - support for breakpoint, step-out, and step-over
+ * - support for x86 stack tracing
+ */
+#include <mdb/mdb_conf.h>
+#include <mdb/mdb_err.h>
+#include <mdb/mdb_signal.h>
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_io_impl.h>
+#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_target_impl.h>
+#include <mdb/mdb_isautil.h>
+#include <mdb/mdb_amd64util.h>
+#include <mdb/mdb_ia32util.h>
+#include <mdb/mdb_x86util.h>
+#include <mdb/mdb.h>
+
+#include <sys/controlregs.h>
+#include <sys/debugreg.h>
+#include <sys/sysmacros.h>
+#include <sys/note.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <libvmm.h>
+
+#define MDB_DEF_PROMPT "[%<_cpuid>]> "
+
+typedef struct bhyve_data {
+ vmm_t *bd_vmm;
+ uint_t bd_curcpu;
+ int bd_defseg;
+
+ /* must be last */
+ char bd_name[];
+} bhyve_data_t;
+
+
+const mdb_tgt_regdesc_t bhyve_kregs[] = {
+ { "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
+ { "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "di", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
+ { "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "si", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
+ { "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "dx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "dh", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "dl", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
+ { "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "cx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "ch", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "cl", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r8", KREG_R8, MDB_TGT_R_EXPORT },
+ { "r8d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r8w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r8l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r9", KREG_R9, MDB_TGT_R_EXPORT },
+ { "r9d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r9w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r9l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rax", KREG_RAX, MDB_TGT_R_EXPORT },
+ { "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "ax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "ah", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "al", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
+ { "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "bx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "bh", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "bl", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
+ { "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "bp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r10", KREG_R10, MDB_TGT_R_EXPORT },
+ { "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r11", KREG_R11, MDB_TGT_R_EXPORT },
+ { "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r12", KREG_R12, MDB_TGT_R_EXPORT },
+ { "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r13", KREG_R13, MDB_TGT_R_EXPORT },
+ { "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r14", KREG_R14, MDB_TGT_R_EXPORT },
+ { "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r15", KREG_R15, MDB_TGT_R_EXPORT },
+ { "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "ds", KREG_DS, MDB_TGT_R_EXPORT },
+ { "es", KREG_ES, MDB_TGT_R_EXPORT },
+ { "fs", KREG_FS, MDB_TGT_R_EXPORT },
+ { "gs", KREG_GS, MDB_TGT_R_EXPORT },
+ { "rip", KREG_RIP, MDB_TGT_R_EXPORT },
+ { "cs", KREG_CS, MDB_TGT_R_EXPORT },
+ { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
+ { "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
+ { "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "sp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "ss", KREG_SS, MDB_TGT_R_EXPORT },
+ { "cr2", KREG_CR2, MDB_TGT_R_EXPORT },
+ { "cr3", KREG_CR3, MDB_TGT_R_EXPORT },
+ { NULL, 0, 0 }
+};
+
+static const char *segments[] = { "CS", "DS", "ES", "FS", "GS", "SS" };
+
+
+/*ARGSUSED*/
+static uintmax_t
+bhyve_cpuid_get(const mdb_var_t *v)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+
+ return (bd->bd_curcpu);
+}
+
+static const mdb_nv_disc_t bhyve_cpuid_disc = {
+ .disc_get = bhyve_cpuid_get
+};
+
+
+static uintmax_t
+bhyve_reg_get(const mdb_var_t *v)
+{
+ mdb_tgt_reg_t r = 0;
+
+ if (mdb_tgt_getareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), &r) == -1)
+ mdb_warn("failed to get %%%s register", mdb_nv_get_name(v));
+
+ return (r);
+}
+
+static void
+bhyve_reg_set(mdb_var_t *v, uintmax_t r)
+{
+ if (mdb_tgt_putareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), r) == -1)
+ mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v));
+}
+
+static const mdb_nv_disc_t bhyve_reg_disc = {
+ .disc_set = bhyve_reg_set,
+ .disc_get = bhyve_reg_get
+};
+
+static int
+bhyve_get_gregset(bhyve_data_t *bd, int cpu, mdb_tgt_gregset_t *gregs)
+{
+ vmm_desc_t fs, gs;
+
+ /*
+ * Register numbers to get, the order must match the definitions of
+ * KREG_* in mdb_kreg.h so that we get a proper mdb_tgt_gregset_t
+ * that the register printing functions will understand.
+ *
+ * There are a few fields in mdb_tgt_gregset_t that can't be accessed
+ * with vmm_get_regset(), either because they don't exist in bhyve or
+ * or because they need to be accessed with vmm_get_desc(). For these
+ * cases we ask for RAX instead and fill it with 0 or the real value,
+ * respectively.
+ */
+ static const int regnums[] = {
+ KREG_RAX, /* dummy for SAVFP */
+ KREG_RAX, /* dummy for SAVFP */
+ KREG_RDI,
+ KREG_RSI,
+ KREG_RDX,
+ KREG_RCX,
+ KREG_R8,
+ KREG_R9,
+ KREG_RAX,
+ KREG_RBX,
+ KREG_RBP,
+ KREG_R10,
+ KREG_R11,
+ KREG_R12,
+ KREG_R13,
+ KREG_R14,
+ KREG_R15,
+ KREG_RAX, /* dummy for FSBASE */
+ KREG_RAX, /* dummy for GSBASE */
+ KREG_RAX, /* dummy for KGSBASE */
+ KREG_CR2,
+ KREG_CR3,
+ KREG_DS,
+ KREG_ES,
+ KREG_FS,
+ KREG_GS,
+ KREG_RAX, /* dummy for TRAPNO */
+ KREG_RAX, /* dummy for ERR */
+ KREG_RIP,
+ KREG_CS,
+ KREG_RFLAGS,
+ KREG_RSP,
+ KREG_SS
+ };
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, KREG_NGREG, regnums,
+ &gregs->kregs[0]) != 0) {
+ mdb_warn("failed to get general-purpose registers for CPU %d",
+ cpu);
+ return (-1);
+ }
+
+ if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS, &fs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS, &gs) != 0) {
+ mdb_warn("failed to get FS/GS descriptors for CPU %d", cpu);
+ return (-1);
+ }
+
+ gregs->kregs[KREG_SAVFP] = 0;
+ gregs->kregs[KREG_SAVPC] = 0;
+ gregs->kregs[KREG_KGSBASE] = 0;
+ gregs->kregs[KREG_TRAPNO] = 0;
+ gregs->kregs[KREG_ERR] = 0;
+
+ gregs->kregs[KREG_FSBASE] = fs.vd_base;
+ gregs->kregs[KREG_GSBASE] = gs.vd_base;
+
+ return (0);
+}
+
+static int
+bhyve_cpuregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ mdb_tgt_gregset_t gregs;
+ int i;
+
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ if (bhyve_get_gregset(bd, cpu, &gregs) != 0)
+ return (DCMD_ERR);
+
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, cpu)) {
+ case VMM_ISA_64:
+ mdb_amd64_printregs(&gregs);
+ break;
+ case VMM_ISA_32:
+ case VMM_ISA_16:
+ mdb_ia32_printregs(&gregs);
+ break;
+ default:
+ mdb_warn("CPU %d mode unknown", cpu);
+ return (DCMD_ERR);
+ }
+
+ return (0);
+}
+
+static int
+bhyve_regs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ if ((flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ return (bhyve_cpuregs_dcmd(addr, flags, argc, argv));
+}
+
+static int
+bhyve_stack_common(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv, int vcpu, boolean_t verbose)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ void *arg = (void *)(uintptr_t)mdb.m_nargs;
+
+ mdb_tgt_gregset_t gregs;
+ mdb_tgt_stack_f *func;
+
+ if (vcpu == -1)
+ vcpu = bd->bd_curcpu;
+
+ if (flags & DCMD_ADDRSPEC) {
+ bzero(&gregs, sizeof (gregs));
+ gregs.kregs[KREG_RBP] = addr;
+ } else if (bhyve_get_gregset(bd, vcpu, &gregs) != 0)
+ return (DCMD_ERR);
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, vcpu)) {
+ case VMM_ISA_64:
+ func = verbose ? mdb_amd64_kvm_framev : mdb_amd64_kvm_frame;
+ (void) mdb_amd64_kvm_stack_iter(mdb.m_target, &gregs, func,
+ arg);
+ break;
+ case VMM_ISA_32:
+ func = verbose ? mdb_ia32_kvm_framev : mdb_amd64_kvm_frame;
+ (void) mdb_ia32_kvm_stack_iter(mdb.m_target, &gregs, func, arg);
+ break;
+ case VMM_ISA_16:
+ mdb_warn("IA16 stack tracing not implemented\n");
+ return (DCMD_ERR);
+ default:
+ mdb_warn("CPU %d mode unknown", vcpu);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+bhyve_cpustack_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ boolean_t verbose;
+ int i;
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (addr < vmm_ncpu(bd->bd_vmm)) {
+ cpu = (uint64_t)addr;
+ flags &= ~DCMD_ADDRSPEC;
+ }
+ }
+
+ i = mdb_getopts(argc, argv,
+ 'c', MDB_OPT_UINT64, &cpu,
+ 'v', MDB_OPT_SETBITS, 1, &verbose,
+ NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ return (bhyve_stack_common(addr, flags, argc, argv, cpu, verbose));
+}
+
+static int
+bhyve_stack_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_FALSE));
+}
+
+static int
+bhyve_stackv_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE));
+}
+
+static int
+bhyve_stackr_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE));
+}
+
+static int
+bhyve_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ vmm_mode_t mode;
+ vmm_isa_t isa;
+
+ static const char *modes[] = {
+ "unknown mode",
+ "real mode",
+ "protected mode, no PAE",
+ "protected mode, PAE",
+ "long mode"
+ };
+ static const char *isas[] = {
+ "unknown ISA",
+ "IA16",
+ "IA32",
+ "AMD64"
+ };
+
+ if ((flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ mode = vmm_vcpu_mode(bd->bd_vmm, bd->bd_curcpu);
+ isa = vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu);
+
+ mdb_printf("debugging live VM '%s'\n", bd->bd_name);
+ mdb_printf("VM memory size: %d MB\n",
+ vmm_memsize(bd->bd_vmm) / 1024 / 1024);
+ mdb_printf("vCPUs: %d\n", vmm_ncpu(bd->bd_vmm));
+ mdb_printf("current CPU: %d (%s, %s)\n", bd->bd_curcpu, modes[mode],
+ isas[isa]);
+ mdb_printf("default segment: %s",
+ segments[bd->bd_defseg - VMM_DESC_CS]);
+
+ return (DCMD_OK);
+}
+
+
+static int
+bhyve_sysregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ int ret = DCMD_ERR;
+ struct sysregs sregs;
+ int i;
+
+ /*
+ * This array must use the order of the elements of struct sysregs.
+ */
+ static const int regnums[] = {
+ VMM_REG_CR0,
+ VMM_REG_CR2,
+ VMM_REG_CR3,
+ VMM_REG_CR4,
+ VMM_REG_DR0,
+ VMM_REG_DR1,
+ VMM_REG_DR2,
+ VMM_REG_DR3,
+ VMM_REG_DR6,
+ VMM_REG_DR7,
+ VMM_REG_EFER,
+ VMM_REG_PDPTE0,
+ VMM_REG_PDPTE1,
+ VMM_REG_PDPTE2,
+ VMM_REG_PDPTE3,
+ VMM_REG_INTR_SHADOW
+ };
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums,
+ (uint64_t *)&sregs) != 0)
+ goto fail;
+
+ if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GDTR,
+ (vmm_desc_t *)&sregs.sr_gdtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_IDTR,
+ (vmm_desc_t *)&sregs.sr_idtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_LDTR,
+ (vmm_desc_t *)&sregs.sr_ldtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_TR,
+ (vmm_desc_t *)&sregs.sr_tr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_CS,
+ (vmm_desc_t *)&sregs.sr_cs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_DS,
+ (vmm_desc_t *)&sregs.sr_ds) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_ES,
+ (vmm_desc_t *)&sregs.sr_es) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS,
+ (vmm_desc_t *)&sregs.sr_fs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS,
+ (vmm_desc_t *)&sregs.sr_gs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_SS,
+ (vmm_desc_t *)&sregs.sr_ss) != 0)
+ goto fail;
+
+ mdb_x86_print_sysregs(&sregs, vmm_vcpu_mode(bd->bd_vmm, cpu) ==
+ VMM_MODE_LONG);
+
+ ret = DCMD_OK;
+
+fail:
+ if (ret != DCMD_OK)
+ mdb_warn("failed to get system registers for CPU %d\n", cpu);
+ return (ret);
+}
+
+static int
+bhyve_dbgregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ int ret = DCMD_ERR;
+ vmm_desc_t gdtr, ldtr, idtr, tr, cs, ds, es, fs, gs, ss;
+ uint64_t *regvals;
+ int i;
+
+ /*
+ * This array must use the order of definitions set in libvmm.h
+ * to make GETREG() work.
+ */
+#define GETREG(r) (regvals[r - VMM_REG_DR0])
+ static const int regnums[] = {
+ VMM_REG_DR0,
+ VMM_REG_DR1,
+ VMM_REG_DR2,
+ VMM_REG_DR3,
+ VMM_REG_DR6,
+ VMM_REG_DR7,
+ };
+
+ static const mdb_bitmask_t dr6_flag_bits[] = {
+ { "DR0", DR_TRAP0, DR_TRAP0 },
+ { "DR1", DR_TRAP1, DR_TRAP1 },
+ { "DR2", DR_TRAP2, DR_TRAP2 },
+ { "DR3", DR_TRAP3, DR_TRAP3 },
+ { "debug reg", DR_ICEALSO, DR_ICEALSO },
+ { "single step", DR_SINGLESTEP, DR_SINGLESTEP },
+ { "task switch", DR_TASKSWITCH, DR_TASKSWITCH },
+ { NULL, 0, 0 }
+ };
+
+#define DR_RW(x, m) \
+ ((DR_RW_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE))
+#define DR_LEN(x, m) \
+ ((DR_LEN_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE))
+
+ static const mdb_bitmask_t dr7_flag_bits[] = {
+ { "L0", DR_ENABLE0, DR_LOCAL_ENABLE_MASK & DR_ENABLE0 },
+ { "G0", DR_ENABLE0, DR_GLOBAL_ENABLE_MASK & DR_ENABLE0 },
+ { "L1", DR_ENABLE1, DR_LOCAL_ENABLE_MASK & DR_ENABLE1 },
+ { "G1", DR_ENABLE1, DR_GLOBAL_ENABLE_MASK & DR_ENABLE1 },
+ { "L2", DR_ENABLE2, DR_LOCAL_ENABLE_MASK & DR_ENABLE2 },
+ { "G2", DR_ENABLE2, DR_GLOBAL_ENABLE_MASK & DR_ENABLE2 },
+ { "L3", DR_ENABLE3, DR_LOCAL_ENABLE_MASK & DR_ENABLE3 },
+ { "G3", DR_ENABLE3, DR_GLOBAL_ENABLE_MASK & DR_ENABLE3 },
+ { "LE", DR_LOCAL_SLOWDOWN, DR_LOCAL_SLOWDOWN },
+ { "GE", DR_GLOBAL_SLOWDOWN, DR_GLOBAL_SLOWDOWN },
+ { "RTM", DR_RTM, DR_RTM },
+ { "GD", DR_GENERAL_DETECT, DR_GENERAL_DETECT },
+ { "0:X", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_EXECUTE) },
+ { "0:W", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_WRITE) },
+ { "0:IO", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_IO_RW) },
+ { "0:RW", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_READ) },
+ { "1:X", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_EXECUTE) },
+ { "1:W", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_WRITE) },
+ { "1:IO", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_IO_RW) },
+ { "1:RW", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_READ) },
+ { "2:X", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_EXECUTE) },
+ { "2:W", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_WRITE) },
+ { "2:IO", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_IO_RW) },
+ { "2:RW", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_READ) },
+ { "3:X", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_EXECUTE) },
+ { "3:W", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_WRITE) },
+ { "3:IO", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_IO_RW) },
+ { "3:RW", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_READ) },
+ { "0:1", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_1) },
+ { "0:2", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_2) },
+ { "0:4", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_4) },
+ { "0:8", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_8) },
+ { "1:1", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_1) },
+ { "1:2", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_2) },
+ { "1:4", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_4) },
+ { "1:8", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_8) },
+ { "2:1", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_1) },
+ { "2:2", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_2) },
+ { "2:4", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_4) },
+ { "2:8", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_8) },
+ { "3:1", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_1) },
+ { "3:2", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_2) },
+ { "3:4", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_4) },
+ { "3:8", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_8) },
+ { NULL, 0, 0 },
+ };
+
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ regvals = mdb_zalloc(ARRAY_SIZE(regnums) * sizeof (uint64_t), UM_SLEEP);
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums,
+ regvals) != 0)
+ goto fail;
+
+ mdb_printf("%%dr0 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR0), GETREG(VMM_REG_DR0));
+ mdb_printf("%%dr1 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR1), GETREG(VMM_REG_DR1));
+ mdb_printf("%%dr2 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR2), GETREG(VMM_REG_DR2));
+ mdb_printf("%%dr3 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR3), GETREG(VMM_REG_DR3));
+ mdb_printf("%%dr6 = 0x%0lx <%b>\n",
+ GETREG(VMM_REG_DR6), GETREG(VMM_REG_DR6), dr6_flag_bits);
+ mdb_printf("%%dr7 = 0x%0lx <%b>\n",
+ GETREG(VMM_REG_DR7), GETREG(VMM_REG_DR7), dr7_flag_bits);
+#undef GETREG
+
+ ret = DCMD_OK;
+
+fail:
+ if (ret != DCMD_OK)
+ mdb_warn("failed to get debug registers for CPU %d\n", cpu);
+ mdb_free(regvals, ARRAY_SIZE(regnums) * sizeof (uint64_t));
+ return (ret);
+}
+
+static int
+bhyve_switch_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ size_t cpu = (int)addr;
+
+ if (!(flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ bd->bd_curcpu = cpu;
+ return (DCMD_OK);
+
+}
+
+static int
+bhyve_seg2reg(const char *seg)
+{
+ if (strcasecmp(seg, "cs") == 0)
+ return (VMM_DESC_CS);
+ else if (strcasecmp(seg, "ds") == 0)
+ return (VMM_DESC_DS);
+ else if (strcasecmp(seg, "es") == 0)
+ return (VMM_DESC_ES);
+ else if (strcasecmp(seg, "fs") == 0)
+ return (VMM_DESC_FS);
+ else if (strcasecmp(seg, "gs") == 0)
+ return (VMM_DESC_GS);
+ else if (strcasecmp(seg, "ss") == 0)
+ return (VMM_DESC_SS);
+ else
+ return (-1);
+}
+
+static int
+bhyve_vtol_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ uint64_t laddr;
+ int i;
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+ }
+
+ if (vmm_vtol(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &laddr) != 0) {
+ if (errno == EFAULT)
+ (void) set_errno(EMDB_NOMAP);
+ return (DCMD_ERR);
+ }
+
+ if (flags & DCMD_PIPE_OUT)
+ mdb_printf("%llr\n", laddr);
+ else
+ mdb_printf("virtual %lr mapped to linear %llr\n", addr, laddr);
+
+ return (DCMD_OK);
+}
+
+static int
+bhyve_vtop_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ physaddr_t pa;
+ int i;
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+ }
+
+ if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &pa) == -1) {
+ mdb_warn("failed to get physical mapping");
+ return (DCMD_ERR);
+ }
+
+ if (flags & DCMD_PIPE_OUT)
+ mdb_printf("%llr\n", pa);
+ else
+ mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
+ return (DCMD_OK);
+}
+
+static int
+bhyve_defseg_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ int i;
+
+ if (flags & DCMD_ADDRSPEC)
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+
+ bd->bd_defseg = segreg;
+ }
+
+ mdb_printf("using segment %s for virtual to linear address translation",
+ segments[bd->bd_defseg - VMM_DESC_CS]);
+
+ return (DCMD_OK);
+}
+
+static const mdb_dcmd_t bhyve_dcmds[] = {
+ { "$c", NULL, "print stack backtrace", bhyve_stack_dcmd },
+ { "$C", NULL, "print stack backtrace", bhyve_stackv_dcmd },
+ { "$r", NULL, "print general-purpose registers", bhyve_regs_dcmd },
+ { "$?", NULL, "print status and registers", bhyve_regs_dcmd },
+ { ":x", ":", "change the active CPU", bhyve_switch_dcmd },
+ { "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a "
+ "specific CPU", bhyve_cpustack_dcmd },
+ { "cpuregs", "?[-c cpuid]", "print general-purpose registers for a "
+ "specific CPU", bhyve_cpuregs_dcmd },
+ { "dbgregs", "?[-c cpuid]", "print debug registers for a specific CPU",
+ bhyve_dbgregs_dcmd },
+ { "defseg", "?[-s segment]", "change the default segment used to "
+ "translate addresses", bhyve_defseg_dcmd },
+ { "regs", NULL, "print general-purpose registers", bhyve_regs_dcmd },
+ { "stack", NULL, "print stack backtrace", bhyve_stack_dcmd },
+ { "stackregs", NULL, "print stack backtrace and registers",
+ bhyve_stackr_dcmd },
+ { "status", NULL, "print summary of current target",
+ bhyve_status_dcmd },
+ { "sysregs", "?[-c cpuid]", "print system registers for a specific CPU",
+ bhyve_sysregs_dcmd },
+ { "switch", ":", "change the active CPU", bhyve_switch_dcmd },
+ { "vtol", ":[-s segment]", "print linear mapping of virtual address",
+ bhyve_vtol_dcmd },
+ { "vtop", ":[-s segment]", "print physical mapping of virtual "
+ "address", bhyve_vtop_dcmd },
+ { NULL }
+};
+
+
+/*
+ * t_setflags: change target flags
+ */
+static int
+bhyve_setflags(mdb_tgt_t *tgt, int flags)
+{
+ bhyve_data_t *bd = tgt->t_data;
+
+ if (((tgt->t_flags ^ flags) & MDB_TGT_F_RDWR) != 0) {
+ boolean_t writable = (flags & MDB_TGT_F_RDWR) != 0;
+
+ vmm_unmap(bd->bd_vmm);
+ if (vmm_map(bd->bd_vmm, writable) != 0) {
+ mdb_warn("failed to map guest memory");
+ return (set_errno(EMDB_TGT));
+ }
+ }
+
+ tgt->t_flags = flags;
+
+ return (0);
+}
+
+/*
+ * t_activate: activate target
+ */
+static void
+bhyve_activate(mdb_tgt_t *tgt)
+{
+ mdb_tgt_status_t *tsp = &tgt->t_status;
+ bhyve_data_t *bd = tgt->t_data;
+ const char *format;
+ char buf[BUFSIZ];
+
+ (void) mdb_set_prompt(MDB_DEF_PROMPT);
+
+ (void) mdb_tgt_register_dcmds(tgt, bhyve_dcmds, MDB_MOD_FORCE);
+ mdb_tgt_register_regvars(tgt, bhyve_kregs, &bhyve_reg_disc, 0);
+
+ (void) vmm_stop(bd->bd_vmm);
+
+ if (mdb_tgt_status(tgt, tsp) != 0)
+ return;
+
+ if (tsp->st_pc != 0) {
+ if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
+ MDB_TGT_AS_VIRT_I, buf, sizeof (buf), tsp->st_pc) !=
+ tsp->st_pc)
+ format = "target stopped at:\n%-#16a%8T%s\n";
+ else
+ format = "target stopped at %a:\n";
+ mdb_warn(format, tsp->st_pc, buf);
+ }
+}
+
+/*
+ * t_deactivate: deactivate target
+ */
+static void
+bhyve_deactivate(mdb_tgt_t *tgt)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ const mdb_tgt_regdesc_t *rd;
+ const mdb_dcmd_t *dc;
+
+ for (rd = bhyve_kregs; rd->rd_name != NULL; rd++) {
+ mdb_var_t *var;
+
+ if (!(rd->rd_flags & MDB_TGT_R_EXPORT))
+ continue; /* didn't export register as variable */
+
+ if ((var = mdb_nv_lookup(&mdb.m_nv, rd->rd_name)) != NULL) {
+ var->v_flags &= ~MDB_NV_PERSIST;
+ mdb_nv_remove(&mdb.m_nv, var);
+ }
+ }
+
+ for (dc = bhyve_dcmds; dc->dc_name != NULL; dc++)
+ if (mdb_module_remove_dcmd(tgt->t_module, dc->dc_name) == -1)
+ mdb_warn("failed to remove dcmd %s", dc->dc_name);
+
+ (void) vmm_cont(bd->bd_vmm);
+}
+
+/*
+ * t_name: return name of target
+ */
+static const char *
+bhyve_name(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return ("bhyve");
+}
+
+/*
+ * t_destroy: cleanup target private resources
+ */
+static void
+bhyve_destroy(mdb_tgt_t *tgt)
+{
+ bhyve_data_t *bd = tgt->t_data;
+
+ (void) vmm_cont(bd->bd_vmm);
+ vmm_unmap(bd->bd_vmm);
+ vmm_close_vm(bd->bd_vmm);
+ mdb_free(bd, sizeof (bhyve_data_t));
+ tgt->t_data = NULL;
+}
+
+/*
+ * t_isa: return name of target ISA
+ */
+const char *
+bhyve_isa(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return ("amd64");
+}
+
+/*
+ * t_dmodel: return target data model
+ */
+static int
+bhyve_dmodel(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return (MDB_TGT_MODEL_LP64);
+}
+
+/*ARGSUSED*/
+static ssize_t
+bhyve_aread(mdb_tgt_t *tgt, mdb_tgt_as_t as, void *buf, size_t nbytes,
+ mdb_tgt_addr_t addr)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ ssize_t cnt;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_PHYS:
+ cnt = vmm_pread(bd->bd_vmm, buf, nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_FILE:
+ case (uintptr_t)MDB_TGT_AS_IO:
+ return (set_errno(EMDB_TGTNOTSUP));
+ }
+
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+
+ return (cnt);
+}
+
+/*ARGSUSED*/
+static ssize_t
+bhyve_awrite(mdb_tgt_t *tgt, mdb_tgt_as_t as, const void *buf, size_t nbytes,
+ mdb_tgt_addr_t addr)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ ssize_t cnt;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_PHYS:
+ cnt = vmm_pwrite(bd->bd_vmm, buf, nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_FILE:
+ case (uintptr_t)MDB_TGT_AS_IO:
+ return (set_errno(EMDB_TGTNOTSUP));
+ }
+
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+
+ return (cnt);
+}
+
+/*
+ * t_vread: read from virtual memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_vread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr));
+}
+
+/*
+ * t_vwrite: write to virtual memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_vwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr));
+}
+
+/*
+ * t_pread: read from physical memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_pread(mdb_tgt_t *tgt, void *buf, size_t nbytes, physaddr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr));
+}
+
+/*
+ * t_pwrite: write to physical memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_pwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, physaddr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr));
+}
+
+/*
+ * t_fread: read from core/object file
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_fread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr));
+}
+
+/*
+ * t_fwrite: write to core/object file
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_fwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr));
+}
+
+/*
+ * t_ioread: read from I/O space
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_ioread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_IO, buf, nbytes, addr));
+}
+
+/*
+ * t_iowrite: write to I/O space
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_iowrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_IO, buf, nbytes, addr));
+}
+
+/*
+ * t_vtop: translate virtual to physical address
+ */
+static int
+bhyve_vtop(mdb_tgt_t *tgt, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pa)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int seg;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ seg = bd->bd_defseg;
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ seg = VMM_DESC_CS;
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ seg = VMM_DESC_SS;
+ break;
+
+ default:
+ return (set_errno(EINVAL));
+ }
+
+ if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, seg, va, pa) != 0) {
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+ else
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * t_status: get target status
+ */
+static int
+bhyve_status(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ mdb_tgt_reg_t rip;
+ vmm_desc_t cs;
+ int ret;
+
+ bzero(tsp, sizeof (mdb_tgt_status_t));
+
+ ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, KREG_RIP, &rip);
+ if (ret != 0) {
+ tsp->st_state = MDB_TGT_UNDEAD;
+ } else {
+ tsp->st_state = MDB_TGT_STOPPED;
+ tsp->st_pc = rip;
+ }
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu)) {
+ case VMM_ISA_16:
+ (void) mdb_dis_select("ia16");
+ break;
+ case VMM_ISA_32:
+ (void) mdb_dis_select("ia32");
+ break;
+ case VMM_ISA_64:
+ (void) mdb_dis_select("amd64");
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static void
+bhyve_sighdl(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *tgt)
+{
+ mdb_tgt_status_t *tsp = &tgt->t_status;
+ bhyve_data_t *bd = tgt->t_data;
+
+ switch (sig) {
+ case SIGINT:
+ /*
+ * vmm_stop() may fail if the VM was destroyed while we were
+ * waiting. This will be handled by mdb_tgt_status().
+ */
+ (void) vmm_stop(bd->bd_vmm);
+ (void) mdb_tgt_status(tgt, tsp);
+ break;
+ }
+}
+
+/*
+ * t_step: single-step target
+ */
+static int
+bhyve_step(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int ret;
+
+ ret = vmm_step(bd->bd_vmm, bd->bd_curcpu);
+ (void) mdb_tgt_status(tgt, tsp);
+
+ return (ret);
+}
+
+/*
+ * t_cont: continue target execution
+ *
+ * Catch SIGINT so that the target can be stopped with Ctrl-C.
+ */
+static int
+bhyve_cont(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ mdb_signal_f *intf;
+ void *intd;
+ int ret;
+
+ intf = mdb_signal_gethandler(SIGINT, &intd);
+ (void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)bhyve_sighdl, tgt);
+
+ if (ret = vmm_cont(bd->bd_vmm) != 0) {
+ mdb_warn("failed to continue target execution: %d", ret);
+ return (set_errno(EMDB_TGT));
+ }
+
+ tsp->st_state = MDB_TGT_RUNNING;
+ (void) pause();
+
+ (void) mdb_signal_sethandler(SIGINT, intf, intd);
+ (void) mdb_tgt_status(tgt, tsp);
+
+ return (ret);
+}
+
+static int
+bhyve_lookup_reg(mdb_tgt_t *tgt, const char *rname)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ const mdb_tgt_regdesc_t *rd;
+
+ for (rd = bhyve_kregs; rd->rd_name != NULL; rd++)
+ if (strcmp(rd->rd_name, rname) == 0)
+ return (rd->rd_num);
+
+ return (-1);
+}
+
+/*
+ * t_getareg: get the value of a single register
+ */
+static int
+bhyve_getareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname,
+ mdb_tgt_reg_t *rp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int reg = bhyve_lookup_reg(tgt, rname);
+ int ret;
+
+ if (reg == -1)
+ return (set_errno(EMDB_BADREG));
+
+ ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, reg, rp);
+ if (ret == -1)
+ return (set_errno(EMDB_BADREG));
+
+ return (0);
+}
+
+/*
+ * t_putareg: set the value of a single register
+ */
+static int
+bhyve_putareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname,
+ mdb_tgt_reg_t r)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int reg = bhyve_lookup_reg(tgt, rname);
+ int ret;
+
+ if ((tgt->t_flags & MDB_TGT_F_RDWR) == 0)
+ return (set_errno(EMDB_TGTRDONLY));
+
+ if (reg == -1)
+ return (set_errno(EMDB_BADREG));
+
+ ret = vmm_setreg(bd->bd_vmm, bd->bd_curcpu, reg, r);
+ if (ret == -1)
+ return (set_errno(EMDB_BADREG));
+
+ return (0);
+}
+
+static const mdb_tgt_ops_t bhyve_ops = {
+ .t_setflags = bhyve_setflags,
+ .t_setcontext = (int (*)()) mdb_tgt_notsup,
+ .t_activate = bhyve_activate,
+ .t_deactivate = bhyve_deactivate,
+ .t_periodic = (void (*)()) mdb_tgt_nop,
+ .t_destroy = bhyve_destroy,
+ .t_name = bhyve_name,
+ .t_isa = bhyve_isa,
+ .t_platform = (const char *(*)()) mdb_conf_platform,
+ .t_uname = (int (*)()) mdb_tgt_notsup,
+ .t_dmodel = bhyve_dmodel,
+ .t_aread = bhyve_aread,
+ .t_awrite = bhyve_awrite,
+ .t_vread = bhyve_vread,
+ .t_vwrite = bhyve_vwrite,
+ .t_pread = bhyve_pread,
+ .t_pwrite = bhyve_pwrite,
+ .t_fread = bhyve_fread,
+ .t_fwrite = bhyve_fwrite,
+ .t_ioread = bhyve_ioread,
+ .t_iowrite = bhyve_iowrite,
+ .t_vtop = bhyve_vtop,
+ .t_lookup_by_name = (int (*)()) mdb_tgt_notsup,
+ .t_lookup_by_addr = (int (*)()) mdb_tgt_notsup,
+ .t_symbol_iter = (int (*)()) mdb_tgt_notsup,
+ .t_mapping_iter = (int (*)()) mdb_tgt_notsup,
+ .t_object_iter = (int (*)()) mdb_tgt_notsup,
+ .t_addr_to_map = (const mdb_map_t *(*)()) mdb_tgt_null,
+ .t_name_to_map = (const mdb_map_t *(*)()) mdb_tgt_null,
+ .t_addr_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null,
+ .t_name_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null,
+ .t_status = bhyve_status,
+ .t_run = (int (*)()) mdb_tgt_notsup,
+ .t_step = bhyve_step,
+ .t_step_out = (int (*)()) mdb_tgt_notsup,
+ .t_next = (int (*)()) mdb_tgt_notsup,
+ .t_cont = bhyve_cont,
+ .t_signal = (int (*)()) mdb_tgt_notsup,
+ .t_add_vbrkpt = (int (*)()) mdb_tgt_null,
+ .t_add_sbrkpt = (int (*)()) mdb_tgt_null,
+ .t_add_pwapt = (int (*)()) mdb_tgt_null,
+ .t_add_vwapt = (int (*)()) mdb_tgt_null,
+ .t_add_iowapt = (int (*)()) mdb_tgt_null,
+ .t_add_sysenter = (int (*)()) mdb_tgt_null,
+ .t_add_sysexit = (int (*)()) mdb_tgt_null,
+ .t_add_signal = (int (*)()) mdb_tgt_null,
+ .t_add_fault = (int (*)()) mdb_tgt_null,
+ .t_getareg = bhyve_getareg,
+ .t_putareg = bhyve_putareg,
+ .t_stack_iter = (int (*)()) mdb_tgt_notsup,
+ .t_auxv = (int (*)()) mdb_tgt_notsup
+};
+
+int
+mdb_bhyve_tgt_create(mdb_tgt_t *tgt, int argc, const char *argv[])
+{
+ bhyve_data_t *bd;
+ vmm_t *vmm = NULL;
+ boolean_t writable = (tgt->t_flags & MDB_TGT_F_RDWR) != 0;
+
+ if (argc != 1)
+ return (set_errno(EINVAL));
+
+ vmm = vmm_open_vm(argv[0]);
+ if (vmm == NULL) {
+ mdb_warn("failed to open %s", argv[0]);
+ return (set_errno(EMDB_TGT));
+ }
+
+ if (vmm_map(vmm, writable) != 0) {
+ mdb_warn("failed to map %s", argv[0]);
+ vmm_close_vm(vmm);
+ return (set_errno(EMDB_TGT));
+ }
+
+ bd = mdb_zalloc(sizeof (bhyve_data_t) + strlen(argv[0]) + 1, UM_SLEEP);
+ (void) strcpy(bd->bd_name, argv[0]);
+ bd->bd_vmm = vmm;
+ bd->bd_curcpu = 0;
+ bd->bd_defseg = VMM_DESC_DS;
+
+ tgt->t_ops = &bhyve_ops;
+ tgt->t_data = bd;
+ tgt->t_flags |= MDB_TGT_F_ASIO;
+
+ (void) mdb_nv_insert(&mdb.m_nv, "cpuid", &bhyve_cpuid_disc, 0,
+ MDB_NV_PERSIST | MDB_NV_RDONLY);
+
+ return (0);
+}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
index d6db4811b2..22e56a0eda 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
@@ -23,16 +23,18 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
+#include <sys/types32.h>
#include <sys/reg.h>
#include <sys/privregs.h>
#include <sys/stack.h>
#include <sys/frame.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/mdb_target_impl.h>
#include <mdb/mdb_kreg_impl.h>
@@ -41,10 +43,14 @@
#include <mdb/mdb_err.h>
#include <mdb/mdb.h>
+#ifndef __amd64
/*
* We also define an array of register names and their corresponding
* array indices. This is used by the getareg and putareg entry points,
* and also by our register variable discipline.
+ *
+ * When built into an amd64 mdb this won't be used as it's only a subset of
+ * mdb_amd64_kregs, hence the #ifdef.
*/
const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
@@ -87,6 +93,7 @@ const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
{ NULL, 0, 0 }
};
+#endif
void
mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
@@ -94,27 +101,27 @@ mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
const kreg_t *kregs = &gregs->kregs[0];
kreg_t eflags = kregs[KREG_EFLAGS];
- mdb_printf("%%cs = 0x%04x\t\t%%eax = 0x%0?p %A\n",
+ mdb_printf("%%cs = 0x%04x\t\t%%eax = 0x%08p %A\n",
kregs[KREG_CS], kregs[KREG_EAX], kregs[KREG_EAX]);
- mdb_printf("%%ds = 0x%04x\t\t%%ebx = 0x%0?p %A\n",
+ mdb_printf("%%ds = 0x%04x\t\t%%ebx = 0x%08p %A\n",
kregs[KREG_DS], kregs[KREG_EBX], kregs[KREG_EBX]);
- mdb_printf("%%ss = 0x%04x\t\t%%ecx = 0x%0?p %A\n",
+ mdb_printf("%%ss = 0x%04x\t\t%%ecx = 0x%08p %A\n",
kregs[KREG_SS], kregs[KREG_ECX], kregs[KREG_ECX]);
- mdb_printf("%%es = 0x%04x\t\t%%edx = 0x%0?p %A\n",
+ mdb_printf("%%es = 0x%04x\t\t%%edx = 0x%08p %A\n",
kregs[KREG_ES], kregs[KREG_EDX], kregs[KREG_EDX]);
- mdb_printf("%%fs = 0x%04x\t\t%%esi = 0x%0?p %A\n",
+ mdb_printf("%%fs = 0x%04x\t\t%%esi = 0x%08p %A\n",
kregs[KREG_FS], kregs[KREG_ESI], kregs[KREG_ESI]);
- mdb_printf("%%gs = 0x%04x\t\t%%edi = 0x%0?p %A\n\n",
+ mdb_printf("%%gs = 0x%04x\t\t%%edi = 0x%08p %A\n\n",
kregs[KREG_GS], kregs[KREG_EDI], kregs[KREG_EDI]);
- mdb_printf("%%eip = 0x%0?p %A\n", kregs[KREG_EIP], kregs[KREG_EIP]);
- mdb_printf("%%ebp = 0x%0?p\n", kregs[KREG_EBP]);
- mdb_printf("%%esp = 0x%0?p\n\n", kregs[KREG_ESP]);
+ mdb_printf("%%eip = 0x%08p %A\n", kregs[KREG_EIP], kregs[KREG_EIP]);
+ mdb_printf("%%ebp = 0x%08p\n", kregs[KREG_EBP]);
+ mdb_printf("%%esp = 0x%08p\n\n", kregs[KREG_ESP]);
mdb_printf("%%eflags = 0x%08x\n", eflags);
mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
@@ -138,8 +145,8 @@ mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
(eflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
(eflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
-#ifndef _KMDB
- mdb_printf(" %%uesp = 0x%0?x\n", kregs[KREG_UESP]);
+#if !defined(__amd64) && !defined(_KMDB)
+ mdb_printf(" %%uesp = 0x%08x\n", kregs[KREG_UESP]);
#endif
mdb_printf("%%trapno = 0x%x\n", kregs[KREG_TRAPNO]);
mdb_printf(" %%err = 0x%x\n", kregs[KREG_ERR]);
@@ -166,7 +173,8 @@ kvm_argcount(mdb_tgt_t *t, uintptr_t eip, ssize_t size)
M_ADD_IMM8 = 0x83 /* ADD imm8 to r/m32 */
};
- if (mdb_tgt_vread(t, ins, sizeof (ins), eip) != sizeof (ins))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, sizeof (ins), eip) !=
+ sizeof (ins))
return (0);
if (ins[1] != M_MODRM_ESP)
@@ -185,7 +193,7 @@ kvm_argcount(mdb_tgt_t *t, uintptr_t eip, ssize_t size)
n = 0;
}
- return (MIN((ssize_t)n, size) / sizeof (long));
+ return (MIN((ssize_t)n, size) / sizeof (uint32_t));
}
int
@@ -198,9 +206,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
int err;
struct fr {
- uintptr_t fr_savfp;
- uintptr_t fr_savpc;
- long fr_argv[32];
+ uintptr32_t fr_savfp;
+ uintptr32_t fr_savpc;
+ uint32_t fr_argv[32];
} fr;
uintptr_t fp = gsp->kregs[KREG_EBP];
@@ -226,9 +234,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
err = EMDB_STKALIGN;
goto badfp;
}
- if ((size = mdb_tgt_vread(t, &fr, sizeof (fr), fp)) >=
- (ssize_t)(2 * sizeof (uintptr_t))) {
- size -= (ssize_t)(2 * sizeof (uintptr_t));
+ if ((size = mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr,
+ sizeof (fr), fp)) >= (ssize_t)(2 * sizeof (uintptr32_t))) {
+ size -= (ssize_t)(2 * sizeof (uintptr32_t));
argc = kvm_argcount(t, fr.fr_savpc, size);
} else {
err = EMDB_NOMAP;
@@ -245,8 +253,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (advance_tortoise != 0) {
struct fr tfr;
- if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
- tortoise_fp) != sizeof (tfr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
+ sizeof (tfr), tortoise_fp) !=
+ sizeof (tfr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -262,7 +271,8 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
advance_tortoise = !advance_tortoise;
- if (got_pc && func(arg, pc, argc, fr.fr_argv, &gregs) != 0)
+ if (got_pc &&
+ func(arg, pc, argc, (const long *)fr.fr_argv, &gregs) != 0)
break;
kregs[KREG_ESP] = kregs[KREG_EBP];
@@ -294,6 +304,12 @@ badfp:
return (set_errno(err));
}
+#ifndef __amd64
+/*
+ * The functions mdb_ia32_step_out and mdb_ia32_next haven't yet been adapted
+ * to work when built for an amd64 mdb. They are unused by the amd64-only bhyve
+ * target, hence the #ifdef.
+ */
/*
* Determine the return address for the current frame. Typically this is the
* fr_savpc value from the current frame, but we also perform some special
@@ -321,7 +337,8 @@ mdb_ia32_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
fp = sp;
}
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
+ sizeof (fr)) {
*p = fr.fr_savpc;
return (0);
}
@@ -372,7 +389,8 @@ mdb_ia32_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
* read the subsequent Mod/RM byte to perform additional decoding.
*/
if (curinstr == M_CALL_REG) {
- if (mdb_tgt_vread(t, &m, sizeof (m), pc + 1) != sizeof (m))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &m, sizeof (m), pc + 1)
+ != sizeof (m))
return (-1); /* errno is set for us */
/*
@@ -404,13 +422,16 @@ mdb_ia32_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
return (set_errno(EAGAIN));
}
+#endif
/*ARGSUSED*/
int
-mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
+mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *largv,
const mdb_tgt_gregset_t *gregs)
{
- argc = MIN(argc, (uint_t)arglim);
+ const uint32_t *argv = (const uint32_t *)largv;
+
+ argc = MIN(argc, (uintptr_t)arglim);
mdb_printf("%a(", pc);
if (argc != 0) {
@@ -424,11 +445,13 @@ mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
}
int
-mdb_ia32_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
+mdb_ia32_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *largv,
const mdb_tgt_gregset_t *gregs)
{
- argc = MIN(argc, (uint_t)arglim);
- mdb_printf("%0?lr %a(", gregs->kregs[KREG_EBP], pc);
+ const uint32_t *argv = (const uint32_t *)largv;
+
+ argc = MIN(argc, (uintptr_t)arglim);
+ mdb_printf("%08lr %a(", gregs->kregs[KREG_EBP], pc);
if (argc != 0) {
mdb_printf("%lr", *argv++);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
index 597b234b3e..1645b86d8d 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
@@ -22,12 +22,13 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_IA32UTIL_H
#define _MDB_IA32UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_target_impl.h>
@@ -35,8 +36,6 @@
extern "C" {
#endif
-typedef uchar_t mdb_instr_t;
-
extern const mdb_tgt_regdesc_t mdb_ia32_kregs[];
extern void mdb_ia32_printregs(const mdb_tgt_gregset_t *);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h b/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
index b6d17e1045..237e6663ae 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
@@ -23,16 +23,19 @@
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_ISAUTIL_H
#define _MDB_ISAUTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
+typedef uchar_t mdb_instr_t;
+
#ifdef __amd64
#include <mdb/mdb_amd64util.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h b/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
index a3edf864d7..3db7d6a1d6 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
@@ -75,6 +75,7 @@ typedef uint32_t kreg_t;
#define KREG_ES KDIREG_ES
#define KREG_FS KDIREG_FS
#define KREG_GS KDIREG_GS
+#define KREG_FSBASE KDIREG_FSBASE
#define KREG_GSBASE KDIREG_GSBASE
#define KREG_KGSBASE KDIREG_KGSBASE
#define KREG_TRAPNO KDIREG_TRAPNO
@@ -91,6 +92,17 @@ typedef uint32_t kreg_t;
#define KREG_SP KREG_RSP
#define KREG_FP KREG_RBP
+#define KREG_EAX KREG_RAX
+#define KREG_EBX KREG_RBX
+#define KREG_ECX KREG_RCX
+#define KREG_EDX KREG_RDX
+#define KREG_ESI KREG_RSI
+#define KREG_EDI KREG_RDI
+#define KREG_EBP KREG_RBP
+#define KREG_ESP KREG_RSP
+#define KREG_EFLAGS KREG_RFLAGS
+#define KREG_EIP KREG_RIP
+
#else /* __amd64 */
#define KREG_SAVFP KDIREG_SAVFP
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c
new file mode 100644
index 0000000000..a01ee6cffb
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c
@@ -0,0 +1,215 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * ISA-independent utility functions for the x86 architecture
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_x86util.h>
+
+#include <sys/controlregs.h>
+#include <inttypes.h>
+
+#define MMU_PAGESHIFT 12
+#define MMU_PAGESIZE (1 << MMU_PAGESHIFT)
+#define MMU_PAGEOFFSET (MMU_PAGESIZE - 1)
+#define MMU_PAGEMASK (~MMU_PAGEOFFSET)
+
+#ifndef _KMDB
+static void
+mdb_x86_print_desc(const char *name, const mdb_x86_desc_t *desc, uint_t width)
+{
+ const char *type;
+ const mdb_bitmask_t *bits;
+
+ static const mdb_bitmask_t mem_desc_flag_bits[] = {
+ { "P", 0x80, 0x80 },
+ { "16b", 0x6000, 0x0 },
+ { "32b", 0x6000, 0x4000 },
+ { "64b", 0x6000, 0x2000 },
+ { "G", 0x8000, 0x8000 },
+ { "A", 0x1, 0x1 },
+ { NULL, 0, 0 },
+ };
+
+ static const char *mem_desc_types[] = {
+ "data, up, read-only",
+ "data, up, read-write",
+ "data, down, read-only",
+ "data, down, read-write",
+ "code, non-conforming, execute-only",
+ "code, non-conforming, execute-read",
+ "code, conforming, execute-only",
+ "code, conforming, execute-read"
+ };
+
+ static const mdb_bitmask_t sys_desc_flag_bits[] = {
+ { "P", 0x80, 0x80 },
+ { "16b", 0x6000, 0x0 },
+ { "32b", 0x6000, 0x4000 },
+ { "64b", 0x6000, 0x2000 },
+ { "G", 0x8000, 0x8000 },
+ { NULL, 0, 0 },
+ };
+
+ static const char *sys_desc_types[] = {
+ "reserved",
+ "16b TSS, available",
+ "LDT",
+ "16b TSS, busy",
+ "16b call gate",
+ "task gate",
+ "16b interrupt gate",
+ "16b trap gate",
+ "reserved",
+ "32b/64b TSS, available",
+ "reserved",
+ "32b/64b TSS, busy",
+ "32b/64b call gate",
+ "reserved",
+ "32b/64b interrupt gate"
+ "32b/64b trap gate",
+ };
+
+ if (desc->d_acc & 0x10) {
+ type = mem_desc_types[(desc->d_acc >> 1) & 7];
+ bits = mem_desc_flag_bits;
+ } else {
+ type = sys_desc_types[desc->d_acc & 0xf];
+ bits = sys_desc_flag_bits;
+ }
+
+ mdb_printf("%%%s = 0x%0*lx/0x%0*x 0x%05x "
+ "<%susable, %s, dpl %d, flags: %b>\n",
+ name, width, desc->d_base, width / 2, desc->d_lim, desc->d_acc,
+ (desc->d_acc >> 16) & 1 ? "un" : "", type,
+ (desc->d_acc >> 5) & 3, desc->d_acc, bits);
+}
+#endif
+
+void
+mdb_x86_print_sysregs(struct sysregs *sregs, boolean_t long_mode)
+{
+ const uint_t width =
+ 2 * (long_mode ? sizeof (uint64_t) : sizeof (uint32_t));
+
+
+#ifndef _KMDB
+ static const mdb_bitmask_t efer_flag_bits[] = {
+ { "SCE", AMD_EFER_SCE, AMD_EFER_SCE },
+ { "LME", AMD_EFER_LME, AMD_EFER_LME },
+ { "LMA", AMD_EFER_LMA, AMD_EFER_LMA },
+ { "NXE", AMD_EFER_NXE, AMD_EFER_NXE },
+ { "SVME", AMD_EFER_SVME, AMD_EFER_SVME },
+ { "LMSLE", AMD_EFER_LMSLE, AMD_EFER_LMSLE },
+ { "FFXSR", AMD_EFER_FFXSR, AMD_EFER_FFXSR },
+ { "TCE", AMD_EFER_TCE, AMD_EFER_TCE },
+ { NULL, 0, 0 }
+ };
+#endif
+
+ static const mdb_bitmask_t cr0_flag_bits[] = {
+ { "PE", CR0_PE, CR0_PE },
+ { "MP", CR0_MP, CR0_MP },
+ { "EM", CR0_EM, CR0_EM },
+ { "TS", CR0_TS, CR0_TS },
+ { "ET", CR0_ET, CR0_ET },
+ { "NE", CR0_NE, CR0_NE },
+ { "WP", CR0_WP, CR0_WP },
+ { "AM", CR0_AM, CR0_AM },
+ { "NW", CR0_NW, CR0_NW },
+ { "CD", CR0_CD, CR0_CD },
+ { "PG", CR0_PG, CR0_PG },
+ { NULL, 0, 0 }
+ };
+
+ static const mdb_bitmask_t cr3_flag_bits[] = {
+ { "PCD", CR3_PCD, CR3_PCD },
+ { "PWT", CR3_PWT, CR3_PWT },
+ { NULL, 0, 0, }
+ };
+
+ static const mdb_bitmask_t cr4_flag_bits[] = {
+ { "VME", CR4_VME, CR4_VME },
+ { "PVI", CR4_PVI, CR4_PVI },
+ { "TSD", CR4_TSD, CR4_TSD },
+ { "DE", CR4_DE, CR4_DE },
+ { "PSE", CR4_PSE, CR4_PSE },
+ { "PAE", CR4_PAE, CR4_PAE },
+ { "MCE", CR4_MCE, CR4_MCE },
+ { "PGE", CR4_PGE, CR4_PGE },
+ { "PCE", CR4_PCE, CR4_PCE },
+ { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
+ { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
+ { "UMIP", CR4_UMIP, CR4_UMIP },
+ { "VMXE", CR4_VMXE, CR4_VMXE },
+ { "SMXE", CR4_SMXE, CR4_SMXE },
+ { "FSGSBASE", CR4_FSGSBASE, CR4_FSGSBASE },
+ { "PCIDE", CR4_PCIDE, CR4_PCIDE },
+ { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
+ { "SMEP", CR4_SMEP, CR4_SMEP },
+ { "SMAP", CR4_SMAP, CR4_SMAP },
+ { "PKE", CR4_PKE, CR4_PKE },
+ { NULL, 0, 0 }
+ };
+
+#ifndef _KMDB
+ mdb_printf("%%efer = 0x%0lx <%b>\n",
+ sregs->sr_efer, sregs->sr_efer, efer_flag_bits);
+#endif
+ mdb_printf("%%cr0 = 0x%0lx <%b>\n",
+ sregs->sr_cr0, sregs->sr_cr0, cr0_flag_bits);
+ mdb_printf("%%cr2 = 0x%0*x <%a>\n", width,
+ sregs->sr_cr2, sregs->sr_cr2);
+ mdb_printf("%%cr3 = 0x%0lx <pfn:0x%lx ",
+ sregs->sr_cr3, sregs->sr_cr3 >> MMU_PAGESHIFT);
+ if (sregs->sr_cr4 & CR4_PCIDE)
+ mdb_printf("pcid:%lu>\n", sregs->sr_cr3 & MMU_PAGEOFFSET);
+ else
+ mdb_printf("flags:%b>\n", sregs->sr_cr3, cr3_flag_bits);
+ mdb_printf("%%cr4 = 0x%0lx <%b>\n",
+ sregs->sr_cr4, sregs->sr_cr4, cr4_flag_bits);
+
+#ifndef _KMDB
+ mdb_printf("\n");
+ mdb_printf("%%pdpte0 = 0x%0?lx\t%%pdpte2 = 0x%0?lx\n",
+ sregs->sr_pdpte0, sregs->sr_pdpte2);
+ mdb_printf("%%pdpte1 = 0x%0?lx\t%%pdpte3 = 0x%0?lx\n",
+ sregs->sr_pdpte1, sregs->sr_pdpte3);
+ mdb_printf("\n");
+
+ mdb_printf("%%gdtr = 0x%0*lx/0x%hx\n",
+ width, sregs->sr_gdtr.d_base, sregs->sr_gdtr.d_lim);
+#else
+ mdb_printf("%%gdtr.base = 0x%0*lx, %%gdtr.limit = 0x%hx\n",
+ width, sregs->sr_gdtr.d_base, sregs->sr_gdtr.d_lim);
+#endif
+#ifndef _KMDB
+ mdb_printf("%%idtr = 0x%0*lx/0x%hx\n",
+ width, sregs->sr_idtr.d_base, sregs->sr_idtr.d_lim);
+ mdb_x86_print_desc("ldtr", &sregs->sr_ldtr, width);
+ mdb_x86_print_desc("tr ", &sregs->sr_tr, width);
+ mdb_x86_print_desc("cs ", &sregs->sr_cs, width);
+ mdb_x86_print_desc("ss ", &sregs->sr_ss, width);
+ mdb_x86_print_desc("ds ", &sregs->sr_ds, width);
+ mdb_x86_print_desc("es ", &sregs->sr_es, width);
+ mdb_x86_print_desc("fs ", &sregs->sr_fs, width);
+ mdb_x86_print_desc("gs ", &sregs->sr_gs, width);
+
+ mdb_printf("%%intr_shadow = 0x%lx\n",
+ sregs->sr_intr_shadow);
+#endif
+}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h
new file mode 100644
index 0000000000..7641595d2a
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h
@@ -0,0 +1,68 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#ifndef _MDB_X86UTIL_H
+#define _MDB_X86UTIL_H
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mdb_x86_desc {
+ uint64_t d_base;
+ uint32_t d_lim;
+ uint32_t d_acc;
+} mdb_x86_desc_t;
+
+struct sysregs {
+ uint64_t sr_cr0;
+ uint64_t sr_cr2;
+ uint64_t sr_cr3;
+ uint64_t sr_cr4;
+ uint64_t sr_dr0;
+ uint64_t sr_dr1;
+ uint64_t sr_dr2;
+ uint64_t sr_dr3;
+ uint64_t sr_dr6;
+ uint64_t sr_dr7;
+ uint64_t sr_efer;
+ uint64_t sr_pdpte0;
+ uint64_t sr_pdpte1;
+ uint64_t sr_pdpte2;
+ uint64_t sr_pdpte3;
+ uint64_t sr_intr_shadow;
+ mdb_x86_desc_t sr_gdtr;
+ mdb_x86_desc_t sr_idtr;
+ mdb_x86_desc_t sr_ldtr;
+ mdb_x86_desc_t sr_tr;
+ mdb_x86_desc_t sr_cs;
+ mdb_x86_desc_t sr_ss;
+ mdb_x86_desc_t sr_ds;
+ mdb_x86_desc_t sr_es;
+ mdb_x86_desc_t sr_fs;
+ mdb_x86_desc_t sr_gs;
+};
+
+extern void mdb_x86_print_sysregs(struct sysregs *, boolean_t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MDB_X86UTIL_H */
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
index cb613e2f0c..b19498b96e 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
@@ -38,6 +38,7 @@
#include <mdb/mdb_proc.h>
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_err.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/mdb.h>
@@ -144,7 +145,8 @@ pt_read_instr(mdb_tgt_t *t)
const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
uint8_t ret = 0;
- (void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[REG_RIP]);
+ (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret),
+ psp->pr_reg[REG_RIP]);
return (ret);
}
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
index 7f505b950f..c03a73f31e 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
@@ -24,8 +24,8 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
* Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
+ * Copyright 2018 Joyent, Inc.
*/
/*
@@ -38,6 +38,7 @@
#include <mdb/mdb_proc.h>
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_err.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/mdb.h>
@@ -99,7 +100,8 @@ pt_read_instr(mdb_tgt_t *t)
const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
uint8_t ret = 0;
- (void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[EIP]);
+ (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret),
+ psp->pr_reg[EIP]);
return (ret);
}
diff --git a/usr/src/compat/freebsd/amd64/machine/specialreg.h b/usr/src/compat/freebsd/amd64/machine/specialreg.h
index 871573ea6b..ead63aaaab 100644
--- a/usr/src/compat/freebsd/amd64/machine/specialreg.h
+++ b/usr/src/compat/freebsd/amd64/machine/specialreg.h
@@ -38,6 +38,7 @@
#undef CR4_SMEP
#undef CR4_SMAP
#undef CR4_PKE
+#undef CR4_FSGSBASE
#undef CR4_PCIDE
#endif /* _SYS_CONTROLREGS_H */
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index c40721fd55..374c46d532 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -282,6 +282,7 @@ SUBDIRS += \
i386_SUBDIRS= \
libfdisk \
libsaveargs \
+ libvmm \
libvmmapi
sparc_SUBDIRS= \
@@ -508,6 +509,7 @@ HDRSUBDIRS= \
i386_HDRSUBDIRS= \
libfdisk \
libsaveargs \
+ libvmm \
libvmmapi
sparc_HDRSUBDIRS= \
@@ -694,6 +696,7 @@ libtsnet: libtsol libsecdb
libtsol: libsecdb
libuuid: libdlpi
libv12n: libds libuuid
+libvmm: libvmmapi
libvolmgt: libadm
libvrrpadm: libdladm libscf
libvscan: libscf libsecdb
diff --git a/usr/src/lib/libvmm/Makefile b/usr/src/lib/libvmm/Makefile
new file mode 100644
index 0000000000..66bd60eb46
--- /dev/null
+++ b/usr/src/lib/libvmm/Makefile
@@ -0,0 +1,43 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+include ../Makefile.lib
+include ../Makefile.rootfs
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+HDRS = libvmm.h
+HDRDIR = .
+CHECKHDRS = $(HDRS:%.h=%.check)
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libvmm/Makefile.com b/usr/src/lib/libvmm/Makefile.com
new file mode 100644
index 0000000000..d85abae8ce
--- /dev/null
+++ b/usr/src/lib/libvmm/Makefile.com
@@ -0,0 +1,51 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+LIBRARY = libvmm.a
+VERS = .1
+OBJECTS = libvmm.o list.o
+
+SRCDIR = .
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+LIBS = $(DYNLIB)
+
+# The FreeBSD compat and contrib headers need to be first in the search
+# path, hence we can't just append them to CPPFLAGS. So we assign CPPFLAGS
+# directly and pull in CPPFLAGS.master at the appropriate place.
+CPPFLAGS = -I$(COMPAT)/freebsd -I$(CONTRIB)/freebsd \
+ -I$(COMPAT)/freebsd/amd64 -I$(CONTRIB)/freebsd/amd64 \
+ $(CPPFLAGS.master) -I$(SRC)/uts/i86pc
+
+LDLIBS += -lc -lvmmapi
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+pics/%.o: $(SRC)/common/list/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# include library targets
+include ../../Makefile.targ
diff --git a/usr/src/lib/libvmm/amd64/Makefile b/usr/src/lib/libvmm/amd64/Makefile
new file mode 100644
index 0000000000..5ba4f14479
--- /dev/null
+++ b/usr/src/lib/libvmm/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libvmm/libvmm.c b/usr/src/lib/libvmm/libvmm.c
new file mode 100644
index 0000000000..dc552a8de0
--- /dev/null
+++ b/usr/src/lib/libvmm/libvmm.c
@@ -0,0 +1,860 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Library for native code to access bhyve VMs, without the need to use
+ * FreeBSD compat headers
+ */
+
+#include <sys/param.h>
+#include <sys/list.h>
+#include <sys/stddef.h>
+#include <sys/mman.h>
+#include <sys/kdi_regs.h>
+#include <sys/sysmacros.h>
+#include <sys/controlregs.h>
+#include <sys/note.h>
+#include <sys/debug.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <machine/vmm.h>
+#include <vmmapi.h>
+
+#include <libvmm.h>
+
+typedef struct vmm_memseg vmm_memseg_t;
+
+#define VMM_MEMSEG_DEVMEM 0x1
+
+struct vmm_memseg {
+ list_node_t vms_list;
+ int vms_segid;
+ int vms_prot;
+ int vms_flags;
+ uintptr_t vms_gpa;
+ off_t vms_segoff;
+ size_t vms_seglen;
+ size_t vms_maplen;
+ char vms_name[64];
+};
+
+struct vmm {
+ struct vmctx *vmm_ctx;
+ list_t vmm_memlist;
+ char *vmm_mem;
+ size_t vmm_memsize;
+ size_t vmm_ncpu;
+};
+
+
+/*
+ * This code relies on two assumptions:
+ * - CPUs are never removed from the "active set", not even when suspended.
+ * A CPU being active just means that it has been used by the guest OS.
+ * - The CPU numbering is consecutive.
+ */
+static void
+vmm_update_ncpu(vmm_t *vmm)
+{
+ cpuset_t cpuset;
+
+ assert(vm_active_cpus(vmm->vmm_ctx, &cpuset) == 0);
+
+ for (vmm->vmm_ncpu = 0;
+ CPU_ISSET(vmm->vmm_ncpu, &cpuset) == 1;
+ vmm->vmm_ncpu++)
+ ;
+}
+
+vmm_t *
+vmm_open_vm(const char *name)
+{
+ vmm_t *vmm = NULL;
+
+ vmm = malloc(sizeof (vmm_t));
+ if (vmm == NULL)
+ return (NULL);
+
+ bzero(vmm, sizeof (vmm_t));
+ vmm->vmm_mem = MAP_FAILED;
+
+ list_create(&vmm->vmm_memlist, sizeof (vmm_memseg_t),
+ offsetof(vmm_memseg_t, vms_list));
+
+ vmm->vmm_ctx = vm_open(name);
+ if (vmm->vmm_ctx == NULL) {
+ free(vmm);
+ return (NULL);
+ }
+
+ vmm_update_ncpu(vmm);
+
+ /*
+ * If we open a VM that has just been created we may see a state
+ * where it has no CPUs configured yet. We'll just wait for 10ms
+ * and retry until we get a non-zero CPU count.
+ */
+ if (vmm->vmm_ncpu == 0) {
+ do {
+ (void) usleep(10000);
+ vmm_update_ncpu(vmm);
+ } while (vmm->vmm_ncpu == 0);
+ }
+
+ return (vmm);
+}
+
+void
+vmm_close_vm(vmm_t *vmm)
+{
+ vmm_unmap(vmm);
+
+ list_destroy(&vmm->vmm_memlist);
+
+ if (vmm->vmm_ctx != NULL)
+ vm_close(vmm->vmm_ctx);
+
+ free(vmm);
+}
+
+static vmm_memseg_t *
+vmm_get_memseg(vmm_t *vmm, uintptr_t gpa)
+{
+ vmm_memseg_t ms, *ret;
+ int error, flags;
+
+ bzero(&ms, sizeof (vmm_memseg_t));
+ ms.vms_gpa = gpa;
+ error = vm_mmap_getnext(vmm->vmm_ctx, &ms.vms_gpa, &ms.vms_segid,
+ &ms.vms_segoff, &ms.vms_maplen, &ms.vms_prot, &flags);
+ if (error)
+ return (NULL);
+
+ error = vm_get_memseg(vmm->vmm_ctx, ms.vms_segid, &ms.vms_seglen,
+ ms.vms_name, sizeof (ms.vms_name));
+ if (error)
+ return (NULL);
+
+ /*
+ * Regular memory segments don't have a name, but devmem segments do.
+ * We can use that information to set the DEVMEM flag if necessary.
+ */
+ ms.vms_flags = ms.vms_name[0] != '\0' ? VMM_MEMSEG_DEVMEM : 0;
+
+ ret = malloc(sizeof (vmm_memseg_t));
+ if (ret == NULL)
+ return (NULL);
+
+ *ret = ms;
+
+ return (ret);
+}
+
+int
+vmm_map(vmm_t *vmm, boolean_t writable)
+{
+ uintptr_t last_gpa = 0;
+ vmm_memseg_t *ms;
+ int prot_write = writable ? PROT_WRITE : 0;
+
+ if (vmm->vmm_mem != MAP_FAILED) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ assert(list_is_empty(&vmm->vmm_memlist));
+
+ for (;;) {
+ ms = vmm_get_memseg(vmm, last_gpa);
+
+ if (ms == NULL)
+ break;
+
+ last_gpa = ms->vms_gpa + ms->vms_maplen;
+ list_insert_tail(&vmm->vmm_memlist, ms);
+ }
+
+ vmm->vmm_mem = mmap(NULL, last_gpa, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
+
+ if (vmm->vmm_mem == MAP_FAILED)
+ goto fail;
+
+ for (ms = list_head(&vmm->vmm_memlist);
+ ms != NULL;
+ ms = list_next(&vmm->vmm_memlist, ms)) {
+ off_t mapoff = ms->vms_gpa;
+
+ if ((ms->vms_flags & VMM_MEMSEG_DEVMEM) &&
+ vm_get_devmem_offset(vmm->vmm_ctx, ms->vms_segid, &mapoff)
+ != 0)
+ goto fail;
+
+ vmm->vmm_memsize += ms->vms_maplen;
+
+ if (mmap(vmm->vmm_mem + ms->vms_gpa, ms->vms_maplen,
+ PROT_READ | prot_write, MAP_SHARED | MAP_FIXED,
+ vm_get_device_fd(vmm->vmm_ctx), mapoff) == MAP_FAILED)
+ goto fail;
+ }
+
+ return (0);
+
+fail:
+ vmm_unmap(vmm);
+
+ return (-1);
+}
+
+void
+vmm_unmap(vmm_t *vmm)
+{
+ while (!list_is_empty(&vmm->vmm_memlist)) {
+ vmm_memseg_t *ms = list_remove_head(&vmm->vmm_memlist);
+
+ if (vmm->vmm_mem != MAP_FAILED) {
+ (void) munmap(vmm->vmm_mem + ms->vms_gpa,
+ ms->vms_maplen);
+ }
+
+ free(ms);
+ }
+
+ if (vmm->vmm_mem != MAP_FAILED)
+ (void) munmap(vmm->vmm_mem, vmm->vmm_memsize);
+
+ vmm->vmm_mem = MAP_FAILED;
+ vmm->vmm_memsize = 0;
+}
+
+ssize_t
+vmm_pread(vmm_t *vmm, void *buf, size_t len, uintptr_t addr)
+{
+ ssize_t count = 0;
+ vmm_memseg_t *ms;
+ ssize_t res = len;
+
+ for (ms = list_head(&vmm->vmm_memlist);
+ ms != NULL && len != 0;
+ ms = list_next(&vmm->vmm_memlist, ms)) {
+
+ if (addr >= ms->vms_gpa &&
+ addr < ms->vms_gpa + ms->vms_maplen) {
+ res = (addr + len) - (ms->vms_gpa + ms->vms_maplen);
+
+ if (res < 0)
+ res = 0;
+
+ bcopy(vmm->vmm_mem + addr, buf, len - res);
+ count += len - res;
+ addr += len - res;
+ len = res;
+ }
+ }
+
+ if (res)
+ errno = EFAULT;
+ else
+ errno = 0;
+
+ return (count);
+}
+
+ssize_t
+vmm_pwrite(vmm_t *vmm, const void *buf, size_t len, uintptr_t addr)
+{
+ ssize_t count = 0;
+ vmm_memseg_t *ms;
+ ssize_t res = len;
+
+ for (ms = list_head(&vmm->vmm_memlist);
+ ms != NULL;
+ ms = list_next(&vmm->vmm_memlist, ms)) {
+ if (addr >= ms->vms_gpa &&
+ addr < ms->vms_gpa + ms->vms_maplen) {
+ res = (addr + len) - (ms->vms_gpa + ms->vms_maplen);
+
+ if (res < 0)
+ res = 0;
+
+ bcopy(buf, vmm->vmm_mem + addr, len - res);
+ count += len - res;
+ addr += len - res;
+ len = res;
+ }
+ }
+
+ if (res)
+ errno = EFAULT;
+ else
+ errno = 0;
+
+ return (count);
+}
+
+size_t
+vmm_ncpu(vmm_t *vmm)
+{
+ return (vmm->vmm_ncpu);
+}
+
+size_t
+vmm_memsize(vmm_t *vmm)
+{
+ return (vmm->vmm_memsize);
+}
+
+int
+vmm_cont(vmm_t *vmm)
+{
+ return (vm_resume_cpu(vmm->vmm_ctx, -1));
+}
+
+int
+vmm_step(vmm_t *vmm, int vcpu)
+{
+ cpuset_t cpuset;
+ int ret;
+
+ if (vcpu >= vmm->vmm_ncpu) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = vm_set_capability(vmm->vmm_ctx, vcpu, VM_CAP_MTRAP_EXIT, 1);
+ if (ret != 0)
+ return (-1);
+
+ assert(vm_resume_cpu(vmm->vmm_ctx, vcpu) == 0);
+
+ do {
+ (void) vm_debug_cpus(vmm->vmm_ctx, &cpuset);
+ } while (!CPU_ISSET(vcpu, &cpuset));
+
+ (void) vm_set_capability(vmm->vmm_ctx, vcpu, VM_CAP_MTRAP_EXIT, 0);
+
+ return (ret);
+}
+
+int
+vmm_stop(vmm_t *vmm)
+{
+ int ret = vm_suspend_cpu(vmm->vmm_ctx, -1);
+
+ if (ret == 0)
+ vmm_update_ncpu(vmm);
+
+ return (ret);
+}
+
+/*
+ * Mapping of KDI-defined registers to vmmapi-defined registers.
+ * Registers not known to vmmapi use VM_REG_LAST, which is invalid and
+ * causes an error in vm_{get,set}_register_set().
+ *
+ * This array must be kept in sync with the definitions in kdi_regs.h.
+ */
+static int vmm_kdi_regmap[] = {
+ VM_REG_LAST, /* KDIREG_SAVFP */
+ VM_REG_LAST, /* KDIREG_SAVPC */
+ VM_REG_GUEST_RDI, /* KDIREG_RDI */
+ VM_REG_GUEST_RSI, /* KDIREG_RSI */
+ VM_REG_GUEST_RDX, /* KDIREG_RDX */
+ VM_REG_GUEST_RCX, /* KDIREG_RCX */
+ VM_REG_GUEST_R8, /* KDIREG_R8 */
+ VM_REG_GUEST_R9, /* KDIREG_R9 */
+ VM_REG_GUEST_RAX, /* KDIREG_RAX */
+ VM_REG_GUEST_RBX, /* KDIREG_RBX */
+ VM_REG_GUEST_RBP, /* KDIREG_RBP */
+ VM_REG_GUEST_R10, /* KDIREG_R10 */
+ VM_REG_GUEST_R11, /* KDIREG_R11 */
+ VM_REG_GUEST_R12, /* KDIREG_R12 */
+ VM_REG_GUEST_R13, /* KDIREG_R13 */
+ VM_REG_GUEST_R14, /* KDIREG_R14 */
+ VM_REG_GUEST_R15, /* KDIREG_R15 */
+ VM_REG_LAST, /* KDIREG_FSBASE */
+ VM_REG_LAST, /* KDIREG_GSBASE */
+ VM_REG_LAST, /* KDIREG_KGSBASE */
+ VM_REG_GUEST_CR2, /* KDIREG_CR2 */
+ VM_REG_GUEST_CR3, /* KDIREG_CR3 */
+ VM_REG_GUEST_DS, /* KDIREG_DS */
+ VM_REG_GUEST_ES, /* KDIREG_ES */
+ VM_REG_GUEST_FS, /* KDIREG_FS */
+ VM_REG_GUEST_GS, /* KDIREG_GS */
+ VM_REG_LAST, /* KDIREG_TRAPNO */
+ VM_REG_LAST, /* KDIREG_ERR */
+ VM_REG_GUEST_RIP, /* KDIREG_RIP */
+ VM_REG_GUEST_CS, /* KDIREG_CS */
+ VM_REG_GUEST_RFLAGS, /* KDIREG_RFLAGS */
+ VM_REG_GUEST_RSP, /* KDIREG_RSP */
+ VM_REG_GUEST_SS /* KDIREG_SS */
+};
+CTASSERT(ARRAY_SIZE(vmm_kdi_regmap) == KDIREG_NGREG);
+
+/*
+ * Mapping of libvmm-defined registers to vmmapi-defined registers.
+ *
+ * This array must be kept in sync with the definitions in libvmm.h
+ */
+static int vmm_sys_regmap[] = {
+ VM_REG_GUEST_CR0, /* VMM_REG_CR0 */
+ VM_REG_GUEST_CR2, /* VMM_REG_CR2 */
+ VM_REG_GUEST_CR3, /* VMM_REG_CR3 */
+ VM_REG_GUEST_CR4, /* VMM_REG_CR4 */
+ VM_REG_GUEST_DR0, /* VMM_REG_DR0 */
+ VM_REG_GUEST_DR1, /* VMM_REG_DR1 */
+ VM_REG_GUEST_DR2, /* VMM_REG_DR2 */
+ VM_REG_GUEST_DR3, /* VMM_REG_DR3 */
+ VM_REG_GUEST_DR6, /* VMM_REG_DR6 */
+ VM_REG_GUEST_DR7, /* VMM_REG_DR7 */
+ VM_REG_GUEST_EFER, /* VMM_REG_EFER */
+ VM_REG_GUEST_PDPTE0, /* VMM_REG_PDPTE0 */
+ VM_REG_GUEST_PDPTE1, /* VMM_REG_PDPTE1 */
+ VM_REG_GUEST_PDPTE2, /* VMM_REG_PDPTE2 */
+ VM_REG_GUEST_PDPTE3, /* VMM_REG_PDPTE3 */
+ VM_REG_GUEST_INTR_SHADOW, /* VMM_REG_INTR_SHADOW */
+};
+
+/*
+ * Mapping of libvmm-defined descriptors to vmmapi-defined descriptors.
+ *
+ * This array must be kept in sync with the definitions in libvmm.h
+ */
+static int vmm_descmap[] = {
+ VM_REG_GUEST_GDTR,
+ VM_REG_GUEST_LDTR,
+ VM_REG_GUEST_IDTR,
+ VM_REG_GUEST_TR,
+ VM_REG_GUEST_CS,
+ VM_REG_GUEST_DS,
+ VM_REG_GUEST_ES,
+ VM_REG_GUEST_FS,
+ VM_REG_GUEST_GS,
+ VM_REG_GUEST_SS
+};
+
+static int
+vmm_mapreg(int reg)
+{
+ errno = 0;
+
+ if (reg < 0)
+ goto fail;
+
+ if (reg < KDIREG_NGREG)
+ return (vmm_kdi_regmap[reg]);
+
+ if (reg >= VMM_REG_OFFSET &&
+ reg < VMM_REG_OFFSET + ARRAY_SIZE(vmm_sys_regmap))
+ return (vmm_sys_regmap[reg - VMM_REG_OFFSET]);
+
+fail:
+ errno = EINVAL;
+ return (VM_REG_LAST);
+}
+
+static int
+vmm_mapdesc(int desc)
+{
+ errno = 0;
+
+ if (desc >= VMM_DESC_OFFSET &&
+ desc < VMM_DESC_OFFSET + ARRAY_SIZE(vmm_descmap))
+ return (vmm_descmap[desc - VMM_DESC_OFFSET]);
+
+ errno = EINVAL;
+ return (VM_REG_LAST);
+}
+
+int
+vmm_getreg(vmm_t *vmm, int vcpu, int reg, uint64_t *val)
+{
+ reg = vmm_mapreg(reg);
+
+ if (reg == VM_REG_LAST)
+ return (-1);
+
+ return (vm_get_register(vmm->vmm_ctx, vcpu, reg, val));
+}
+
+int
+vmm_setreg(vmm_t *vmm, int vcpu, int reg, uint64_t val)
+{
+ reg = vmm_mapreg(reg);
+
+ if (reg == VM_REG_LAST)
+ return (-1);
+
+ return (vm_set_register(vmm->vmm_ctx, vcpu, reg, val));
+}
+
+int
+vmm_get_regset(vmm_t *vmm, int vcpu, size_t nregs, const int *regnums,
+ uint64_t *regvals)
+{
+ int *vm_regnums;
+ int i;
+ int ret = -1;
+
+ vm_regnums = malloc(sizeof (int) * nregs);
+ if (vm_regnums == NULL)
+ return (ret);
+
+ for (i = 0; i != nregs; i++) {
+ vm_regnums[i] = vmm_mapreg(regnums[i]);
+ if (vm_regnums[i] == VM_REG_LAST)
+ goto fail;
+ }
+
+ ret = vm_get_register_set(vmm->vmm_ctx, vcpu, nregs, vm_regnums,
+ regvals);
+
+fail:
+ free(vm_regnums);
+ return (ret);
+}
+
+int
+vmm_set_regset(vmm_t *vmm, int vcpu, size_t nregs, const int *regnums,
+ uint64_t *regvals)
+{
+ int *vm_regnums;
+ int i;
+ int ret = -1;
+
+ vm_regnums = malloc(sizeof (int) * nregs);
+ if (vm_regnums == NULL)
+ return (ret);
+
+ for (i = 0; i != nregs; i++) {
+ vm_regnums[i] = vmm_mapreg(regnums[i]);
+ if (vm_regnums[i] == VM_REG_LAST)
+ goto fail;
+ }
+
+ ret = vm_set_register_set(vmm->vmm_ctx, vcpu, nregs, vm_regnums,
+ regvals);
+
+fail:
+ free(vm_regnums);
+ return (ret);
+}
+
+int
+vmm_get_desc(vmm_t *vmm, int vcpu, int desc, vmm_desc_t *vd)
+{
+ desc = vmm_mapdesc(desc);
+ if (desc == VM_REG_LAST)
+ return (-1);
+
+ return (vm_get_desc(vmm->vmm_ctx, vcpu, desc, &vd->vd_base, &vd->vd_lim,
+ &vd->vd_acc));
+}
+
+int
+vmm_set_desc(vmm_t *vmm, int vcpu, int desc, vmm_desc_t *vd)
+{
+ desc = vmm_mapdesc(desc);
+ if (desc == VM_REG_LAST)
+ return (-1);
+
+ return (vm_set_desc(vmm->vmm_ctx, vcpu, desc, vd->vd_base, vd->vd_lim,
+ vd->vd_acc));
+}
+
+/*
+ * Structure to hold MMU state during address translation.
+ * The contents of vmm_mmu_regnum[] must be kept in sync with this.
+ */
+typedef struct vmm_mmu {
+ uint64_t vm_cr0;
+ uint64_t vm_cr3;
+ uint64_t vm_cr4;
+ uint64_t vm_efer;
+} vmm_mmu_t;
+
+static const int vmm_mmu_regnum[] = {
+ VMM_REG_CR0,
+ VMM_REG_CR3,
+ VMM_REG_CR4,
+ VMM_REG_EFER
+};
+
+#define X86_PTE_P 0x001ULL
+#define X86_PTE_PS 0x080ULL
+
+#define X86_PTE_PHYSMASK 0x000ffffffffff000ULL
+#define X86_PAGE_SHIFT 12
+#define X86_PAGE_SIZE (1ULL << X86_PAGE_SHIFT)
+
+#define X86_SEG_CODE_DATA (1ULL << 4)
+#define X86_SEG_PRESENT (1ULL << 7)
+#define X86_SEG_LONG (1ULL << 13)
+#define X86_SEG_BIG (1ULL << 14)
+#define X86_SEG_GRANULARITY (1ULL << 15)
+#define X86_SEG_UNUSABLE (1ULL << 16)
+
+#define X86_SEG_USABLE (X86_SEG_PRESENT | X86_SEG_CODE_DATA)
+#define X86_SEG_USABLE_MASK (X86_SEG_UNUSABLE | X86_SEG_USABLE)
+
+/*
+ * vmm_pte2paddr:
+ *
+ * Recursively calculate the physical address from a virtual address,
+ * starting at the given PTE level using the given PTE.
+ */
+static int
+vmm_pte2paddr(vmm_t *vmm, uint64_t pte, boolean_t ia32, int level,
+ uint64_t vaddr, uint64_t *paddr)
+{
+ int pte_size = ia32 ? sizeof (uint32_t) : sizeof (uint64_t);
+ int off_bits = ia32 ? 10 : 9;
+ boolean_t hugepage = B_FALSE;
+ uint64_t offset;
+ uint64_t off_mask, off_shift;
+
+ if (level < 4 && (pte & X86_PTE_P) == 0) {
+ errno = EFAULT;
+ return (-1);
+ }
+
+ off_shift = X86_PAGE_SHIFT + off_bits * level;
+ off_mask = (1ULL << off_shift) - 1;
+
+ offset = vaddr & off_mask;
+
+ if ((level == 1 || level == 2) && (pte & X86_PTE_PS) != 0) {
+ hugepage = B_TRUE;
+ } else {
+ if (level > 0) {
+ offset >>= off_shift - off_bits;
+ offset <<= X86_PAGE_SHIFT - off_bits;
+ }
+ off_mask = 0xfff;
+ }
+
+ *paddr = (pte & X86_PTE_PHYSMASK & ~off_mask) + offset;
+
+ if (level == 0 || hugepage)
+ return (0);
+
+ pte = 0;
+ if (vmm_pread(vmm, &pte, pte_size, *paddr) != pte_size)
+ return (-1);
+ return (vmm_pte2paddr(vmm, pte, ia32, level - 1, vaddr, paddr));
+}
+
+static vmm_mode_t
+vmm_vcpu_mmu_mode(vmm_t *vmm, int vcpu, vmm_mmu_t *mmu)
+{
+ if ((mmu->vm_cr0 & CR0_PE) == 0)
+ return (VMM_MODE_REAL);
+ else if ((mmu->vm_cr4 & CR4_PAE) == 0)
+ return (VMM_MODE_PROT);
+ else if ((mmu->vm_efer & AMD_EFER_LME) == 0)
+ return (VMM_MODE_PAE);
+ else
+ return (VMM_MODE_LONG);
+}
+
+vmm_mode_t
+vmm_vcpu_mode(vmm_t *vmm, int vcpu)
+{
+ vmm_mmu_t mmu = { 0 };
+
+ if (vmm_get_regset(vmm, vcpu, ARRAY_SIZE(vmm_mmu_regnum),
+ vmm_mmu_regnum, (uint64_t *)&mmu) != 0)
+ return (VMM_MODE_UNKNOWN);
+
+ return (vmm_vcpu_mmu_mode(vmm, vcpu, &mmu));
+}
+
+vmm_isa_t
+vmm_vcpu_isa(vmm_t *vmm, int vcpu)
+{
+ vmm_desc_t cs;
+
+ if (vmm_get_desc(vmm, vcpu, VMM_DESC_CS, &cs) != 0)
+ return (VMM_ISA_UNKNOWN);
+
+ switch (cs.vd_acc & (X86_SEG_BIG | X86_SEG_LONG)) {
+ case 0x0: /* 16b code segment */
+ return (VMM_ISA_16);
+ case X86_SEG_LONG: /* 64b code segment */
+ return (VMM_ISA_64);
+ case X86_SEG_BIG: /* 32b code segment */
+ return (VMM_ISA_32);
+ }
+
+ return (VMM_ISA_UNKNOWN);
+}
+
+/*
+ * vmm_vtol:
+ *
+ * Translate a virtual address to a physical address on a certain vCPU,
+ * using the specified segment register or descriptor according to the mode.
+ *
+ */
+int
+vmm_vtol(vmm_t *vmm, int vcpu, int seg, uint64_t vaddr, uint64_t *laddr)
+{
+ vmm_desc_t desc;
+ uint64_t limit;
+
+ if (vmm_get_desc(vmm, vcpu, seg, &desc) != 0)
+ return (-1);
+
+ switch (vmm_vcpu_mode(vmm, vcpu)) {
+ case VMM_MODE_REAL:
+ if (seg == VMM_DESC_FS || seg == VMM_DESC_GS)
+ goto fault;
+ /* FALLTHRU */
+ case VMM_MODE_PROT:
+ case VMM_MODE_PAE:
+ if ((desc.vd_acc & X86_SEG_USABLE_MASK) != X86_SEG_USABLE)
+ /* unusable, system segment, or not present */
+ goto fault;
+
+ limit = desc.vd_lim;
+ if (desc.vd_acc & X86_SEG_GRANULARITY)
+ limit *= 4096;
+
+ if (vaddr > limit)
+ goto fault;
+ /* FALLTHRU */
+ case VMM_MODE_LONG:
+ *laddr = desc.vd_base + vaddr;
+ return (0);
+
+ default:
+ fault:
+ errno = EFAULT;
+ return (-1);
+ }
+
+}
+
+/*
+ * vmm_vtop:
+ *
+ * Translate a virtual address to a guest physical address on a certain vCPU,
+ * according to the mode the vCPU is in.
+ */
+int
+vmm_vtop(vmm_t *vmm, int vcpu, int seg, uint64_t vaddr, uint64_t *paddr)
+{
+ vmm_mmu_t mmu = { 0 };
+ int ret = 0;
+
+ if (vmm_vtol(vmm, vcpu, seg, vaddr, &vaddr) != 0)
+ return (-1);
+
+ if (vmm_get_regset(vmm, vcpu, ARRAY_SIZE(vmm_mmu_regnum),
+ vmm_mmu_regnum, (uint64_t *)&mmu) != 0)
+ return (-1);
+
+ if ((mmu.vm_cr0 & CR0_PG) == 0) {
+ /* no paging, physical equals virtual */
+ *paddr = vaddr;
+ return (0);
+ }
+
+ switch (vmm_vcpu_mmu_mode(vmm, vcpu, &mmu)) {
+ case VMM_MODE_PROT:
+ /* protected mode, no PAE: 2-level paging, 32bit PTEs */
+ ret = vmm_pte2paddr(vmm, mmu.vm_cr3, B_TRUE, 2, vaddr, paddr);
+ break;
+ case VMM_MODE_PAE:
+ /* protected mode with PAE: 3-level paging, 64bit PTEs */
+ ret = vmm_pte2paddr(vmm, mmu.vm_cr3, B_FALSE, 3, vaddr, paddr);
+ break;
+ case VMM_MODE_LONG:
+ /* long mode: 4-level paging, 64bit PTEs */
+ ret = vmm_pte2paddr(vmm, mmu.vm_cr3, B_FALSE, 4, vaddr, paddr);
+ break;
+ default:
+ ret = -1;
+ }
+
+ return (ret);
+}
+
+ssize_t
+vmm_vread(vmm_t *vmm, int vcpu, int seg, void *buf, size_t len, uintptr_t addr)
+{
+ ssize_t res = 0;
+ uint64_t paddr;
+ size_t plen;
+ uint64_t boundary;
+
+ while (len != 0) {
+ if (vmm_vtop(vmm, vcpu, seg, addr, &paddr) != 0) {
+ errno = EFAULT;
+ return (0);
+ }
+
+ boundary = (addr + X86_PAGE_SIZE) & ~(X86_PAGE_SIZE - 1);
+ if (addr + len > boundary)
+ plen = boundary - addr;
+ else
+ plen = len;
+
+ if (vmm_pread(vmm, buf, plen, paddr) != plen)
+ return (0);
+ len -= plen;
+ addr += plen;
+ buf += plen;
+ res += plen;
+ }
+
+ return (res);
+}
+
+ssize_t
+vmm_vwrite(vmm_t *vmm, int vcpu, int seg, const void *buf, size_t len,
+ uintptr_t addr)
+{
+ ssize_t res = 0;
+ uint64_t paddr;
+ size_t plen;
+ uint64_t boundary;
+
+ while (len != 0) {
+ if (vmm_vtop(vmm, vcpu, seg, addr, &paddr) != 0) {
+ errno = EFAULT;
+ return (0);
+ }
+
+ boundary = (addr + X86_PAGE_SIZE) & ~(X86_PAGE_SIZE - 1);
+ if (addr + len > boundary)
+ plen = boundary - addr;
+ else
+ plen = len;
+
+ if (vmm_pwrite(vmm, buf, plen, paddr) != plen)
+ return (0);
+ len -= plen;
+ addr += plen;
+ buf += plen;
+ res += plen;
+ }
+
+ return (res);
+}
diff --git a/usr/src/lib/libvmm/libvmm.h b/usr/src/lib/libvmm/libvmm.h
new file mode 100644
index 0000000000..352b09e970
--- /dev/null
+++ b/usr/src/lib/libvmm/libvmm.h
@@ -0,0 +1,122 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#ifndef _LIBVMM_H
+#define _LIBVMM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct vmm vmm_t;
+
+typedef struct vmm_desc {
+ uint64_t vd_base;
+ uint32_t vd_lim;
+ uint32_t vd_acc;
+} vmm_desc_t;
+
+
+/*
+ * This enum must be kept in sync with vmm_sys_regmap[] in libvmm.c.
+ */
+#define VMM_REG_OFFSET 0x100
+enum vmm_regs {
+ VMM_REG_CR0 = VMM_REG_OFFSET,
+ VMM_REG_CR2,
+ VMM_REG_CR3,
+ VMM_REG_CR4,
+ VMM_REG_DR0,
+ VMM_REG_DR1,
+ VMM_REG_DR2,
+ VMM_REG_DR3,
+ VMM_REG_DR6,
+ VMM_REG_DR7,
+ VMM_REG_EFER,
+ VMM_REG_PDPTE0,
+ VMM_REG_PDPTE1,
+ VMM_REG_PDPTE2,
+ VMM_REG_PDPTE3,
+ VMM_REG_INTR_SHADOW
+};
+
+/*
+ * This enum must be kept in sync with vmm_descmap[] in libvmm.c.
+ */
+#define VMM_DESC_OFFSET 0x200
+enum vmm_descs {
+ VMM_DESC_GDTR = VMM_DESC_OFFSET,
+ VMM_DESC_LDTR,
+ VMM_DESC_IDTR,
+ VMM_DESC_TR,
+ VMM_DESC_CS,
+ VMM_DESC_DS,
+ VMM_DESC_ES,
+ VMM_DESC_FS,
+ VMM_DESC_GS,
+ VMM_DESC_SS
+};
+
+typedef enum {
+ VMM_MODE_UNKNOWN = 0,
+ VMM_MODE_REAL,
+ VMM_MODE_PROT,
+ VMM_MODE_PAE,
+ VMM_MODE_LONG
+} vmm_mode_t;
+
+typedef enum {
+ VMM_ISA_UNKNOWN = 0,
+ VMM_ISA_16,
+ VMM_ISA_32,
+ VMM_ISA_64
+} vmm_isa_t;
+
+vmm_t *vmm_open_vm(const char *);
+void vmm_close_vm(vmm_t *);
+
+int vmm_map(vmm_t *, boolean_t);
+void vmm_unmap(vmm_t *);
+
+ssize_t vmm_pread(vmm_t *, void *, size_t, uintptr_t);
+ssize_t vmm_pwrite(vmm_t *, const void *, size_t, uintptr_t);
+ssize_t vmm_vread(vmm_t *, int, int, void *, size_t, uintptr_t);
+ssize_t vmm_vwrite(vmm_t *, int, int, const void *, size_t, uintptr_t);
+
+size_t vmm_ncpu(vmm_t *);
+size_t vmm_memsize(vmm_t *);
+
+int vmm_cont(vmm_t *);
+int vmm_step(vmm_t *, int);
+int vmm_stop(vmm_t *);
+
+int vmm_getreg(vmm_t *, int, int, uint64_t *);
+int vmm_setreg(vmm_t *, int, int, uint64_t);
+int vmm_get_regset(vmm_t *, int, size_t, const int *, uint64_t *);
+int vmm_set_regset(vmm_t *, int, size_t, const int *, uint64_t *);
+
+int vmm_get_desc(vmm_t *, int, int, vmm_desc_t *);
+int vmm_set_desc(vmm_t *, int, int, vmm_desc_t *);
+
+vmm_mode_t vmm_vcpu_mode(vmm_t *, int);
+vmm_isa_t vmm_vcpu_isa(vmm_t *, int);
+int vmm_vtol(vmm_t *, int, int, uint64_t, uint64_t *);
+int vmm_vtop(vmm_t *, int, int, uint64_t, uint64_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVMM_H */
diff --git a/usr/src/lib/libvmm/mapfile-vers b/usr/src/lib/libvmm/mapfile-vers
new file mode 100644
index 0000000000..19a15802ac
--- /dev/null
+++ b/usr/src/lib/libvmm/mapfile-vers
@@ -0,0 +1,60 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate {
+ global:
+ vmm_open_vm;
+ vmm_close_vm;
+ vmm_map;
+ vmm_unmap;
+ vmm_pread;
+ vmm_pwrite;
+ vmm_ncpu;
+ vmm_memsize;
+ vmm_cont;
+ vmm_step;
+ vmm_stop;
+ vmm_setreg;
+ vmm_getreg;
+ vmm_set_regset;
+ vmm_get_regset;
+ vmm_set_desc;
+ vmm_get_desc;
+ vmm_vcpu_isa;
+ vmm_vcpu_mode;
+ vmm_vtol;
+ vmm_vtop;
+ vmm_vread;
+ vmm_vwrite;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/libvmmapi/common/mapfile-vers b/usr/src/lib/libvmmapi/common/mapfile-vers
index 397ebd7d59..f8fe636386 100644
--- a/usr/src/lib/libvmmapi/common/mapfile-vers
+++ b/usr/src/lib/libvmmapi/common/mapfile-vers
@@ -40,6 +40,7 @@ SYMBOL_VERSION ILLUMOSprivate {
vm_assign_pptdev;
vm_capability_name2type;
vm_capability_type2name;
+ vm_close;
vm_copy_setup;
vm_copy_teardown;
vm_copyin;
@@ -53,6 +54,7 @@ SYMBOL_VERSION ILLUMOSprivate {
vm_get_capability;
vm_get_desc;
vm_get_device_fd;
+ vm_get_devmem_offset;
vm_get_gpa_pmap;
vm_get_hpet_capabilities;
vm_get_highmem_size;
diff --git a/usr/src/lib/libvmmapi/common/vmmapi.c b/usr/src/lib/libvmmapi/common/vmmapi.c
index ceac495746..bae214aba0 100644
--- a/usr/src/lib/libvmmapi/common/vmmapi.c
+++ b/usr/src/lib/libvmmapi/common/vmmapi.c
@@ -179,10 +179,32 @@ vm_open(const char *name)
return (vm);
err:
+#ifdef __FreeBSD__
vm_destroy(vm);
+#else
+ /*
+ * As libvmmapi is used by other programs to query and control bhyve
+ * VMs, destroying a VM just because the open failed isn't useful. We
+ * have to free what we have allocated, though.
+ */
+ free(vm);
+#endif
return (NULL);
}
+#ifndef __FreeBSD__
+void
+vm_close(struct vmctx *vm)
+{
+ assert(vm != NULL);
+ assert(vm->fd >= 0);
+
+ (void) close(vm->fd);
+
+ free(vm);
+}
+#endif
+
void
vm_destroy(struct vmctx *vm)
{
@@ -551,6 +573,22 @@ vm_get_highmem_size(struct vmctx *ctx)
return (ctx->highmem);
}
+#ifndef __FreeBSD__
+int
+vm_get_devmem_offset(struct vmctx *ctx, int segid, off_t *mapoff)
+{
+ struct vm_devmem_offset vdo;
+ int error;
+
+ vdo.segid = segid;
+ error = ioctl(ctx->fd, VM_DEVMEM_GETOFFSET, &vdo);
+ if (error == 0)
+ *mapoff = vdo.offset;
+
+ return (error);
+}
+#endif
+
void *
vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len)
{
@@ -583,17 +621,8 @@ vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len)
if (fd < 0)
goto done;
#else
- {
- struct vm_devmem_offset vdo;
-
- vdo.segid = segid;
- error = ioctl(ctx->fd, VM_DEVMEM_GETOFFSET, &vdo);
- if (error == 0) {
- mapoff = vdo.offset;
- } else {
- goto done;
- }
- }
+ if (vm_get_devmem_offset(ctx, segid, &mapoff) != 0)
+ goto done;
#endif
/*
diff --git a/usr/src/lib/libvmmapi/common/vmmapi.h b/usr/src/lib/libvmmapi/common/vmmapi.h
index 1b08a9cae5..6cb7a1186d 100644
--- a/usr/src/lib/libvmmapi/common/vmmapi.h
+++ b/usr/src/lib/libvmmapi/common/vmmapi.h
@@ -114,6 +114,13 @@ int vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid,
void *vm_create_devmem(struct vmctx *ctx, int segid, const char *name,
size_t len);
+#ifndef __FreeBSD__
+/*
+ * Return the map offset for the device memory segment 'segid'.
+ */
+int vm_get_devmem_offset(struct vmctx *ctx, int segid, off_t *mapoff);
+#endif
+
/*
* Map the memory segment identified by 'segid' into the guest address space
* at [gpa,gpa+len) with protection 'prot'.
@@ -124,6 +131,9 @@ int vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid,
int vm_create(const char *name);
int vm_get_device_fd(struct vmctx *ctx);
struct vmctx *vm_open(const char *name);
+#ifndef __FreeBSD__
+void vm_close(struct vmctx *ctx);
+#endif
void vm_destroy(struct vmctx *ctx);
int vm_parse_memsize(const char *optarg, size_t *memsize);
int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
diff --git a/usr/src/man/man1/mdb.1 b/usr/src/man/man1/mdb.1
index 8fdd91e661..54f00f4b61 100644
--- a/usr/src/man/man1/mdb.1
+++ b/usr/src/man/man1/mdb.1
@@ -5,13 +5,13 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH MDB 1 "Feb 21, 2019"
+.TH MDB 1 "May 20, 2020"
.SH NAME
mdb \- modular debugger
.SH SYNOPSIS
.LP
.nf
-\fBmdb\fR [\fB-fkmuwyAFKMSUW\fR] [\(+-o \fIoption\fR] [\fB-p\fR \fIpid\fR] [\fB-s\fR \fIdistance\fR]
+\fBmdb\fR [\fB-fkmuwyAFKMSUW\fR] [\(+-o \fIoption\fR] [\fB-b\fR \fIVM\fR] [\fB-p\fR \fIpid\fR] [\fB-s\fR \fIdistance\fR]
[\fB-I\fR \fIpath\fR] [\fB-L\fR \fIpath\fR] [\fB-P\fR \fIprompt\fR] [\fB-R\fR \fIroot\fR]
[\fB-V\fR \fIdis-version\fR] [\fB-e\fR \fIexpr\fR] [object [core] | core | suffix]
.fi
@@ -50,12 +50,13 @@ different contexts, including live and post-mortem.
.LP
The \fItarget\fR is the program being inspected by the debugger. \fBmdb\fR
currently provides support for the following types of targets: user processes,
-user process core files, the live operating system (via \fB/dev/kmem\fR and
-\fB/dev/ksyms\fR), operating system crash dumps, user process images recorded
-inside an operating system crash dump, \fBELF\fR object files, and raw binary
-files. Each target exports a standard set of properties, including one or more
-address spaces, one or more symbol tables, a set of load objects, and a set of
-threads that can be examined using the debugger commands described below.
+user process core files, live bhyve VMs, the live operating system (via
+\fB/dev/kmem\fR and \fB/dev/ksyms\fR), operating system crash dumps, user
+process images recorded inside an operating system crash dump, \fBELF\fR object
+files, and raw binary files. Each target exports a standard set of properties,
+including one or more address spaces, one or more symbol tables, a set of load
+objects, and a set of threads that can be examined using the debugger commands
+described below.
.sp
.LP
A debugger command, or \fIdcmd\fR (pronounced dee-command) in \fBmdb\fR
@@ -3698,6 +3699,15 @@ system or an operating system crash dump.
.sp
.ne 2
.na
+\fB\fB-b\fR \fIVM\fR\fR
+.ad
+.RS 15n
+Attaches to and stops the specified bhyve VM.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fB-e\fR \fIexpr\fR\fR
.ad
.RS 15n
diff --git a/usr/src/pkg/manifests/system-library-bhyve.mf b/usr/src/pkg/manifests/system-library-bhyve.mf
index 3c7e52c938..5408778c90 100644
--- a/usr/src/pkg/manifests/system-library-bhyve.mf
+++ b/usr/src/pkg/manifests/system-library-bhyve.mf
@@ -28,6 +28,7 @@ dir path=lib/$(ARCH64) group=bin
dir path=usr group=sys
dir path=usr/lib group=bin
dir path=usr/lib/$(ARCH64) group=bin
+file path=lib/$(ARCH64)/libvmm.so.1
file path=lib/$(ARCH64)/libvmmapi.so.1
file path=usr/lib/$(ARCH64)/libppt.so.1
file path=usr/lib/libppt.so.1
diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c
index dd24a18f6a..47a5f26cb7 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm.c
@@ -2116,6 +2116,10 @@ restart:
break;
}
+ case VM_EXITCODE_MTRAP:
+ vm_suspend_cpu(vm, vcpuid);
+ retu = true;
+ break;
#endif
default:
retu = true; /* handled in userland */
diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h
index 43b5247274..0be7b3b650 100644
--- a/usr/src/uts/intel/sys/controlregs.h
+++ b/usr/src/uts/intel/sys/controlregs.h
@@ -86,8 +86,8 @@ extern "C" {
/* CR3 Register */
-#define CR3_PCD 0x00000010 /* cache disable */
-#define CR3_PWT 0x00000008 /* write through */
+#define CR3_PCD 0x00000010 /* cache disable */
+#define CR3_PWT 0x00000008 /* write through */
#if defined(_ASM)
#define CR3_NOINVL_BIT 0x8000000000000000
#else
@@ -110,18 +110,22 @@ extern "C" {
#define CR4_PCE 0x0100 /* perf-monitoring counter enable */
#define CR4_OSFXSR 0x0200 /* OS fxsave/fxrstor support */
#define CR4_OSXMMEXCPT 0x0400 /* OS unmasked exception support */
- /* 0x0800 reserved */
+#define CR4_UMIP 0x0800 /* user-mode instruction prevention */
/* 0x1000 reserved */
-#define CR4_VMXE 0x2000
-#define CR4_SMXE 0x4000
+#define CR4_VMXE 0x2000 /* VMX enable */
+#define CR4_SMXE 0x4000 /* SMX enable */
+ /* 0x8000 reserved */
+#define CR4_FSGSBASE 0x10000 /* FSGSBASE enable */
#define CR4_PCIDE 0x20000 /* PCID enable */
#define CR4_OSXSAVE 0x40000 /* OS xsave/xrestore support */
#define CR4_SMEP 0x100000 /* NX for user pages in kernel */
#define CR4_SMAP 0x200000 /* kernel can't access user pages */
+#define CR4_PKE 0x400000 /* protection key enable */
#define FMT_CR4 \
- "\20\26smap\25smep\23osxsav\22pcide" \
- "\17smxe\16vmxe\13xmme\12fxsr\11pce\10pge" \
+ "\20\27pke\26smap\25smep\23osxsav" \
+ "\22pcide\20fsgsbase\17smxe\16vmxe" \
+ "\14umip\13xmme\12fxsr\11pce\10pge" \
"\7mce\6pae\5pse\4de\3tsd\2pvi\1vme"
/*
@@ -158,7 +162,9 @@ extern "C" {
#define MSR_AMD_EFER 0xc0000080 /* extended feature enable MSR */
+#define AMD_EFER_TCE 0x8000 /* translation cache extension */
#define AMD_EFER_FFXSR 0x4000 /* fast fxsave/fxrstor */
+#define AMD_EFER_LMSLE 0x2000 /* long mode segment limit enable */
#define AMD_EFER_SVME 0x1000 /* svm enable */
#define AMD_EFER_NXE 0x0800 /* no-execute enable */
#define AMD_EFER_LMA 0x0400 /* long mode active (read-only) */
@@ -166,7 +172,7 @@ extern "C" {
#define AMD_EFER_SCE 0x0001 /* system call extensions */
#define FMT_AMD_EFER \
- "\20\17ffxsr\15svme\14nxe\13lma\11lme\1sce"
+ "\20\20tce\17ffxsr\16lmsle\15svme\14nxe\13lma\11lme\1sce"
/* AMD's SYSCFG register */
diff --git a/usr/src/uts/intel/sys/debugreg.h b/usr/src/uts/intel/sys/debugreg.h
index b537076d26..8528a293ab 100644
--- a/usr/src/uts/intel/sys/debugreg.h
+++ b/usr/src/uts/intel/sys/debugreg.h
@@ -26,6 +26,9 @@
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _SYS_DEBUGREG_H
#define _SYS_DEBUGREG_H
@@ -57,6 +60,7 @@ extern "C" {
#define DR_ICEALSO 0x2000 /* Flag bit reserved for in-circuit-emulator */
#define DR_SINGLESTEP 0x4000 /* Trap resulting from the single-step flag */
#define DR_TASKSWITCH 0x8000 /* Trap resulting from a task-switch */
+#define DR_IN_RTM 0x10000 /* Trap inside an RTM region */
/*
* dr7 controls the rest of the debug registers.
@@ -73,6 +77,8 @@ extern "C" {
#define DR_CONTROL_RESERVED 0xFC00 /* Bits reserved by Intel */
#define DR_LOCAL_SLOWDOWN 0x100 /* Slow the pipeline for ldt addrs */
#define DR_GLOBAL_SLOWDOWN 0x200 /* Slow the pipeline for gdt addrs */
+#define DR_RTM 0x800 /* Restricted Transactional Memory */
+#define DR_GENERAL_DETECT 0x2000 /* General Detect Enable */
#define DR_LOCAL_ENABLE_SHIFT 0 /* Additional shift: local enable */
#define DR_GLOBAL_ENABLE_SHIFT 1 /* Additional shift: global enable */
@@ -95,6 +101,7 @@ extern "C" {
#define DR_LEN_1 0x0 /* Settings for data length */
#define DR_LEN_2 0x4
#define DR_LEN_4 0xC
+#define DR_LEN_8 0x8
#ifdef __cplusplus
}