aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorNeel Natu <neel@FreeBSD.org>2014-07-19 20:59:08 +0000
committerNeel Natu <neel@FreeBSD.org>2014-07-19 20:59:08 +0000
commit091d453222c352732e496226ffceb33c0b165f56 (patch)
tree5276627274ad6c55ba76fce7b924b9a9eef00e3d /usr.sbin
parentec5622ad86451436339a2dc2c15213956d73adc8 (diff)
downloadsrc-091d453222c352732e496226ffceb33c0b165f56.tar.gz
src-091d453222c352732e496226ffceb33c0b165f56.zip
Handle nested exceptions in bhyve.
A nested exception condition arises when a second exception is triggered while delivering the first exception. Most nested exceptions can be handled serially but some are converted into a double fault. If an exception is generated during delivery of a double fault then the virtual machine shuts down as a result of a triple fault. vm_exit_intinfo() is used to record that a VM-exit happened while an event was being delivered through the IDT. If an exception is triggered while handling the VM-exit it will be treated like a nested exception. vm_entry_intinfo() is used by processor-specific code to get the event to be injected into the guest on the next VM-entry. This function is responsible for deciding the disposition of nested exceptions.
Notes
Notes: svn path=/head/; revision=268889
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bhyve/bhyverun.c2
-rw-r--r--usr.sbin/bhyve/task_switch.c10
-rw-r--r--usr.sbin/bhyvectl/bhyvectl.c46
3 files changed, 53 insertions, 5 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 457ec513a0d4..2b95d9cf880a 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -534,6 +534,8 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
exit(1);
case VM_SUSPEND_HALT:
exit(2);
+ case VM_SUSPEND_TRIPLEFAULT:
+ exit(3);
default:
fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
exit(100);
diff --git a/usr.sbin/bhyve/task_switch.c b/usr.sbin/bhyve/task_switch.c
index b2f5bedb862f..e946807aa8e5 100644
--- a/usr.sbin/bhyve/task_switch.c
+++ b/usr.sbin/bhyve/task_switch.c
@@ -904,10 +904,14 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
*/
/*
- * XXX is the original task switch was triggered by a hardware
- * exception then do we generate a double-fault if we encounter
- * an exception during the task switch?
+ * If the task switch was triggered by an event delivered through
+ * the IDT then extinguish the pending event from the vcpu's
+ * exitintinfo.
*/
+ if (task_switch->reason == TSR_IDT_GATE) {
+ error = vm_set_intinfo(ctx, vcpu, 0);
+ assert(error == 0);
+ }
/*
* XXX should inject debug exception if 'T' bit is 1
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index e77f0d77df6f..b6006b72a767 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -195,7 +195,8 @@ usage(void)
" [--force-reset]\n"
" [--force-poweroff]\n"
" [--get-active-cpus]\n"
- " [--get-suspended-cpus]\n",
+ " [--get-suspended-cpus]\n"
+ " [--get-intinfo]\n",
progname);
exit(1);
}
@@ -205,6 +206,7 @@ static int inject_nmi, assert_lapic_lvt;
static int force_reset, force_poweroff;
static const char *capname;
static int create, destroy, get_lowmem, get_highmem;
+static int get_intinfo;
static int get_active_cpus, get_suspended_cpus;
static uint64_t memsize;
static int set_cr0, get_cr0, set_cr3, get_cr3, set_cr4, get_cr4;
@@ -412,6 +414,37 @@ print_cpus(const char *banner, const cpuset_t *cpus)
printf("\n");
}
+static void
+print_intinfo(const char *banner, uint64_t info)
+{
+ int type;
+
+ printf("%s:\t", banner);
+ if (info & VM_INTINFO_VALID) {
+ type = info & VM_INTINFO_TYPE;
+ switch (type) {
+ case VM_INTINFO_HWINTR:
+ printf("extint");
+ break;
+ case VM_INTINFO_NMI:
+ printf("nmi");
+ break;
+ case VM_INTINFO_SWINTR:
+ printf("swint");
+ break;
+ default:
+ printf("exception");
+ break;
+ }
+ printf(" vector %d", (int)VM_INTINFO_VECTOR(info));
+ if (info & VM_INTINFO_DEL_ERRCODE)
+ printf(" errcode %#x", (u_int)(info >> 32));
+ } else {
+ printf("n/a");
+ }
+ printf("\n");
+}
+
int
main(int argc, char *argv[])
{
@@ -420,7 +453,7 @@ main(int argc, char *argv[])
vm_paddr_t gpa, gpa_pmap;
size_t len;
struct vm_exit vmexit;
- uint64_t ctl, eptp, bm, addr, u64, pteval[4], *pte;
+ uint64_t ctl, eptp, bm, addr, u64, pteval[4], *pte, info[2];
struct vmctx *ctx;
int wired;
cpuset_t cpus;
@@ -595,6 +628,7 @@ main(int argc, char *argv[])
{ "force-poweroff", NO_ARG, &force_poweroff, 1 },
{ "get-active-cpus", NO_ARG, &get_active_cpus, 1 },
{ "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 },
+ { "get-intinfo", NO_ARG, &get_intinfo, 1 },
{ NULL, 0, NULL, 0 }
};
@@ -1566,6 +1600,14 @@ main(int argc, char *argv[])
print_cpus("suspended cpus", &cpus);
}
+ if (!error && (get_intinfo || get_all)) {
+ error = vm_get_intinfo(ctx, vcpu, &info[0], &info[1]);
+ if (!error) {
+ print_intinfo("pending", info[0]);
+ print_intinfo("current", info[1]);
+ }
+ }
+
if (!error && run) {
error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RIP, &rip);
assert(error == 0);