diff options
author | neel <neel@FreeBSD.org> | 2015-06-27 22:48:22 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2015-06-27 22:48:22 +0000 |
commit | 115742fae3f7a7c52d6d5f4894f37e68dff4fd5c (patch) | |
tree | cb845c4cb2d3a3b67b3e1134742c3c5b250ae954 /usr.sbin | |
parent | 02efaba1d135756ed65855bdc99e7d83f46cc4a2 (diff) | |
download | FreeBSD-src-115742fae3f7a7c52d6d5f4894f37e68dff4fd5c.zip FreeBSD-src-115742fae3f7a7c52d6d5f4894f37e68dff4fd5c.tar.gz |
MFC r276428:
Replace bhyve's minimal RTC emulation with a fully featured one in vmm.ko.
MFC r276432:
Initialize all fields of 'struct vm_exception exception' before passing it
to vm_inject_exception().
MFC r276763:
Clear blocking due to STI or MOV SS in the hypervisor when an instruction is
emulated or when the vcpu incurs an exception.
MFC r277149:
Clean up usage of 'struct vm_exception' to only to communicate information
from userspace to vmm.ko when injecting an exception.
MFC r277168:
Fix typo (missing comma).
MFC r277309:
Make the error message explicit instead of just printing the usage if the
virtual machine name is not specified.
MFC r277310:
Simplify instruction restart logic in bhyve.
MFC r277359:
Fix a bug in libvmmapi 'vm_copy_setup()' where it would return success even
if the 'gpa' was in the guest MMIO region.
MFC r277360:
MOVS instruction emulation.
MFC r277626:
Add macro to identify AVIC capability (advanced virtual interrupt controller)
in AMD processors.
MFC r279220:
Don't close a block context if it couldn't be opened avoiding a null deref.
MFC r279225:
Add "-u" option to bhyve(8) to indicate that the RTC should maintain UTC time.
MFC r279227:
Emulate MSR 0xC0011024 when running on AMD processors.
MFC r279228:
Always emulate MSR_PAT on Intel processors and don't rely on PAT save/restore
capability of VT-x. This lets bhyve run nested in older VMware versions that
don't support the PAT save/restore capability.
MFC r279540:
Fix warnings/errors when building vmm.ko with gcc.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bhyve/bhyve.8 | 4 | ||||
-rw-r--r-- | usr.sbin/bhyve/bhyverun.c | 57 | ||||
-rw-r--r-- | usr.sbin/bhyve/bhyverun.h | 5 | ||||
-rw-r--r-- | usr.sbin/bhyve/inout.c | 20 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_ahci.c | 3 | ||||
-rw-r--r-- | usr.sbin/bhyve/rtc.c | 303 | ||||
-rw-r--r-- | usr.sbin/bhyve/rtc.h | 2 | ||||
-rw-r--r-- | usr.sbin/bhyve/task_switch.c | 16 | ||||
-rw-r--r-- | usr.sbin/bhyve/xmsr.c | 9 | ||||
-rw-r--r-- | usr.sbin/bhyvectl/bhyvectl.c | 89 |
10 files changed, 169 insertions, 339 deletions
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 8de0989..e15f9ac 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -32,7 +32,7 @@ .Nd "run a guest operating system inside a virtual machine" .Sh SYNOPSIS .Nm -.Op Fl abehwxACHPWY +.Op Fl abehuwxACHPWY .Op Fl c Ar numcpus .Op Fl g Ar gdbport .Op Fl l Ar lpcdev Ns Op , Ns Ar conf @@ -239,6 +239,8 @@ The host device must have been reserved at boot-time using the loader variable as described in .Xr vmm 4 . .El +.It Fl u +RTC keeps UTC time. .It Fl U Ar uuid Set the universally unique identifier .Pq UUID diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 5971993..97ed046 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -122,7 +122,7 @@ usage(int code) { fprintf(stderr, - "Usage: %s [-abehwxACHPWY] [-c vcpus] [-g <gdb port>] [-l <lpc>]\n" + "Usage: %s [-abehuwxACHPWY] [-c vcpus] [-g <gdb port>] [-l <lpc>]\n" " %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n" " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create ACPI tables\n" @@ -137,6 +137,7 @@ usage(int code) " -p: pin 'vcpu' to 'hostcpu'\n" " -P: vmexit from the guest on pause\n" " -s: <slot,driver,configinfo> PCI slot config\n" + " -u: RTC keeps UTC time\n" " -U: uuid\n" " -w: ignore unimplemented MSRs\n" " -W: force virtio to use single-vector MSI\n" @@ -185,20 +186,14 @@ vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid, int errcode) { struct vmctx *ctx; - int error; + int error, restart_instruction; ctx = arg; - if (errcode_valid) - error = vm_inject_exception2(ctx, vcpu, vector, errcode); - else - error = vm_inject_exception(ctx, vcpu, vector); - assert(error == 0); + restart_instruction = 1; - /* - * Set the instruction length to 0 to ensure that the instruction is - * restarted when the fault handler returns. - */ - vmexit[vcpu].inst_length = 0; + error = vm_inject_exception(ctx, vcpu, vector, errcode_valid, errcode, + restart_instruction); + assert(error == 0); } void * @@ -329,12 +324,6 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) } error = emulate_inout(ctx, vcpu, vme, strictio); - if (!error && in && !string) { - error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, - vme->u.inout.eax); - assert(error == 0); - } - if (error) { fprintf(stderr, "Unhandled %s%c 0x%04x\n", in ? "in" : "out", bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port); @@ -358,7 +347,7 @@ vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) vme->u.msr.code, *pvcpu); if (strictmsr) { vm_inject_gp(ctx, *pvcpu); - return (VMEXIT_RESTART); + return (VMEXIT_CONTINUE); } } @@ -384,7 +373,7 @@ vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) vme->u.msr.code, vme->u.msr.wval, *pvcpu); if (strictmsr) { vm_inject_gp(ctx, *pvcpu); - return (VMEXIT_RESTART); + return (VMEXIT_CONTINUE); } } return (VMEXIT_CONTINUE); @@ -462,9 +451,11 @@ static int vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { + assert(vmexit->inst_length == 0); + stats.vmexit_bogus++; - return (VMEXIT_RESTART); + return (VMEXIT_CONTINUE); } static int @@ -494,9 +485,11 @@ static int vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { + assert(vmexit->inst_length == 0); + stats.vmexit_mtrap++; - return (VMEXIT_RESTART); + return (VMEXIT_CONTINUE); } static int @@ -581,7 +574,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = { }; static void -vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) +vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip) { int error, rc, prevcpu; enum vm_exitcode exitcode; @@ -596,8 +589,11 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) error = vm_active_cpus(ctx, &active_cpus); assert(CPU_ISSET(vcpu, &active_cpus)); + error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RIP, startrip); + assert(error == 0); + while (1) { - error = vm_run(ctx, vcpu, rip, &vmexit[vcpu]); + error = vm_run(ctx, vcpu, &vmexit[vcpu]); if (error != 0) break; @@ -614,10 +610,6 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) switch (rc) { case VMEXIT_CONTINUE: - rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length; - break; - case VMEXIT_RESTART: - rip = vmexit[vcpu].rip; break; case VMEXIT_ABORT: abort(); @@ -694,6 +686,7 @@ main(int argc, char *argv[]) { int c, error, gdb_port, err, bvmcons; int dump_guest_memory, max_vcpus, mptgen; + int rtc_localtime; struct vmctx *ctx; uint64_t rip; size_t memsize; @@ -705,8 +698,9 @@ main(int argc, char *argv[]) guest_ncpus = 1; memsize = 256 * MB; mptgen = 1; + rtc_localtime = 1; - while ((c = getopt(argc, argv, "abehwxACHIPWYp:g:c:s:m:l:U:")) != -1) { + while ((c = getopt(argc, argv, "abehuwxACHIPWYp:g:c:s:m:l:U:")) != -1) { switch (c) { case 'a': x2apic_mode = 0; @@ -766,6 +760,9 @@ main(int argc, char *argv[]) case 'e': strictio = 1; break; + case 'u': + rtc_localtime = 0; + break; case 'U': guest_uuid_str = optarg; break; @@ -829,7 +826,7 @@ main(int argc, char *argv[]) pci_irq_init(ctx); ioapic_init(ctx); - rtc_init(ctx); + rtc_init(ctx, rtc_localtime); sci_init(ctx); /* diff --git a/usr.sbin/bhyve/bhyverun.h b/usr.sbin/bhyve/bhyverun.h index 87824ef..c51bf48 100644 --- a/usr.sbin/bhyve/bhyverun.h +++ b/usr.sbin/bhyve/bhyverun.h @@ -35,9 +35,8 @@ #define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] #endif -#define VMEXIT_CONTINUE 1 /* continue from next instruction */ -#define VMEXIT_RESTART 2 /* restart current instruction */ -#define VMEXIT_ABORT 3 /* abort the vm run loop */ +#define VMEXIT_CONTINUE (0) +#define VMEXIT_ABORT (-1) struct vmctx; extern int guest_ncpus; diff --git a/usr.sbin/bhyve/inout.c b/usr.sbin/bhyve/inout.c index 1041a59..402b953 100644 --- a/usr.sbin/bhyve/inout.c +++ b/usr.sbin/bhyve/inout.c @@ -104,7 +104,7 @@ int emulate_inout(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit, int strict) { int addrsize, bytes, flags, in, port, prot, rep; - uint32_t val; + uint32_t eax, val; inout_func_t handler; void *arg; int error, retval; @@ -214,16 +214,20 @@ emulate_inout(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit, int strict) } /* Restart the instruction if more iterations remain */ - if (retval == 0 && count != 0) - vmexit->inst_length = 0; - } else { - if (!in) { - val = vmexit->u.inout.eax & vie_size2mask(bytes); + if (retval == 0 && count != 0) { + error = vm_restart_instruction(ctx, vcpu); + assert(error == 0); } + } else { + eax = vmexit->u.inout.eax; + val = eax & vie_size2mask(bytes); retval = handler(ctx, vcpu, in, port, bytes, &val, arg); if (retval == 0 && in) { - vmexit->u.inout.eax &= ~vie_size2mask(bytes); - vmexit->u.inout.eax |= val & vie_size2mask(bytes); + eax &= ~vie_size2mask(bytes); + eax |= val & vie_size2mask(bytes); + error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, + eax); + assert(error == 0); } } return (retval); diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 9dbabcd..31e02f8 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -2299,7 +2299,8 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) open_fail: if (ret) { - blockif_close(sc->port[0].bctx); + if (sc->port[0].bctx != NULL) + blockif_close(sc->port[0].bctx); free(sc); } diff --git a/usr.sbin/bhyve/rtc.c b/usr.sbin/bhyve/rtc.c index 459c900..5c70154 100644 --- a/usr.sbin/bhyve/rtc.c +++ b/usr.sbin/bhyve/rtc.c @@ -30,10 +30,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> -#include <sys/time.h> -#include <stdio.h> -#include <string.h> #include <time.h> #include <assert.h> @@ -41,47 +38,11 @@ __FBSDID("$FreeBSD$"); #include <vmmapi.h> #include "acpi.h" -#include "inout.h" #include "pci_lpc.h" #include "rtc.h" -#define IO_RTC 0x70 +#define IO_RTC 0x70 -#define RTC_SEC 0x00 /* seconds */ -#define RTC_SEC_ALARM 0x01 -#define RTC_MIN 0x02 -#define RTC_MIN_ALARM 0x03 -#define RTC_HRS 0x04 -#define RTC_HRS_ALARM 0x05 -#define RTC_WDAY 0x06 -#define RTC_DAY 0x07 -#define RTC_MONTH 0x08 -#define RTC_YEAR 0x09 -#define RTC_CENTURY 0x32 /* current century */ - -#define RTC_STATUSA 0xA -#define RTCSA_TUP 0x80 /* time update, don't look now */ - -#define RTC_STATUSB 0xB -#define RTCSB_DST 0x01 -#define RTCSB_24HR 0x02 -#define RTCSB_BIN 0x04 /* 0 = BCD, 1 = Binary */ -#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */ -#define RTCSB_HALT 0x80 /* stop clock updates */ - -#define RTC_INTR 0x0c /* status register C (R) interrupt source */ - -#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */ -#define RTCSD_PWR 0x80 /* clock power OK */ - -#define RTC_NVRAM_START 0x0e -#define RTC_NVRAM_END 0x7f -#define RTC_NVRAM_SZ (128 - RTC_NVRAM_START) -#define nvoff(x) ((x) - RTC_NVRAM_START) - -#define RTC_DIAG 0x0e -#define RTC_RSTCODE 0x0f -#define RTC_EQUIPMENT 0x14 #define RTC_LMEM_LSB 0x34 #define RTC_LMEM_MSB 0x35 #define RTC_HMEM_LSB 0x5b @@ -92,249 +53,30 @@ __FBSDID("$FreeBSD$"); #define m_16MB (16*1024*1024) #define m_4GB (4ULL*1024*1024*1024) -static int addr; - -static uint8_t rtc_nvram[RTC_NVRAM_SZ]; - -/* XXX initialize these to default values as they would be from BIOS */ -static uint8_t status_a, status_b; - -static struct { - uint8_t hours; - uint8_t mins; - uint8_t secs; -} rtc_alarm; - -static u_char const bin2bcd_data[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 -}; -#define bin2bcd(bin) (bin2bcd_data[bin]) - -#define rtcout(val) ((status_b & RTCSB_BIN) ? (val) : bin2bcd((val))) - -static void -timevalfix(struct timeval *t1) -{ - - if (t1->tv_usec < 0) { - t1->tv_sec--; - t1->tv_usec += 1000000; - } - if (t1->tv_usec >= 1000000) { - t1->tv_sec++; - t1->tv_usec -= 1000000; - } -} - -static void -timevalsub(struct timeval *t1, const struct timeval *t2) -{ - - t1->tv_sec -= t2->tv_sec; - t1->tv_usec -= t2->tv_usec; - timevalfix(t1); -} - -static int -rtc_addr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, - uint32_t *eax, void *arg) -{ - if (bytes != 1) - return (-1); - - if (in) { - /* straight read of this register will return 0xFF */ - *eax = 0xff; - return (0); - } - - switch (*eax & 0x7f) { - case RTC_SEC: - case RTC_SEC_ALARM: - case RTC_MIN: - case RTC_MIN_ALARM: - case RTC_HRS: - case RTC_HRS_ALARM: - case RTC_WDAY: - case RTC_DAY: - case RTC_MONTH: - case RTC_YEAR: - case RTC_STATUSA: - case RTC_STATUSB: - case RTC_INTR: - case RTC_STATUSD: - case RTC_NVRAM_START ... RTC_NVRAM_END: - break; - default: - return (-1); - } - - addr = *eax & 0x7f; - return (0); -} - -static int -rtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, - uint32_t *eax, void *arg) +/* + * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970 + */ +static time_t +rtc_time(struct vmctx *ctx, int use_localtime) { - int hour; + struct tm tm; time_t t; - struct timeval cur, delta; - - static struct timeval last; - static struct tm tm; - - if (bytes != 1) - return (-1); - - gettimeofday(&cur, NULL); - /* - * Increment the cached time only once per second so we can guarantee - * that the guest has at least one second to read the hour:min:sec - * separately and still get a coherent view of the time. - */ - delta = cur; - timevalsub(&delta, &last); - if (delta.tv_sec >= 1 && (status_b & RTCSB_HALT) == 0) { - t = cur.tv_sec; + time(&t); + if (use_localtime) { localtime_r(&t, &tm); - last = cur; + t = timegm(&tm); } - - if (in) { - switch (addr) { - case RTC_SEC_ALARM: - *eax = rtc_alarm.secs; - break; - case RTC_MIN_ALARM: - *eax = rtc_alarm.mins; - break; - case RTC_HRS_ALARM: - *eax = rtc_alarm.hours; - break; - case RTC_SEC: - *eax = rtcout(tm.tm_sec); - return (0); - case RTC_MIN: - *eax = rtcout(tm.tm_min); - return (0); - case RTC_HRS: - if (status_b & RTCSB_24HR) - hour = tm.tm_hour; - else - hour = (tm.tm_hour % 12) + 1; - - *eax = rtcout(hour); - - /* - * If we are representing time in the 12-hour format - * then set the MSB to indicate PM. - */ - if ((status_b & RTCSB_24HR) == 0 && tm.tm_hour >= 12) - *eax |= 0x80; - - return (0); - case RTC_WDAY: - *eax = rtcout(tm.tm_wday + 1); - return (0); - case RTC_DAY: - *eax = rtcout(tm.tm_mday); - return (0); - case RTC_MONTH: - *eax = rtcout(tm.tm_mon + 1); - return (0); - case RTC_YEAR: - *eax = rtcout(tm.tm_year % 100); - return (0); - case RTC_STATUSA: - *eax = status_a; - return (0); - case RTC_STATUSB: - *eax = status_b; - return (0); - case RTC_INTR: - *eax = 0; - return (0); - case RTC_STATUSD: - *eax = RTCSD_PWR; - return (0); - case RTC_NVRAM_START ... RTC_NVRAM_END: - *eax = rtc_nvram[addr - RTC_NVRAM_START]; - return (0); - default: - return (-1); - } - } - - switch (addr) { - case RTC_STATUSA: - status_a = *eax & ~RTCSA_TUP; - break; - case RTC_STATUSB: - /* XXX not implemented yet XXX */ - if (*eax & RTCSB_PINTR) - return (-1); - status_b = *eax; - break; - case RTC_STATUSD: - /* ignore write */ - break; - case RTC_SEC_ALARM: - rtc_alarm.secs = *eax; - break; - case RTC_MIN_ALARM: - rtc_alarm.mins = *eax; - break; - case RTC_HRS_ALARM: - rtc_alarm.hours = *eax; - break; - case RTC_SEC: - case RTC_MIN: - case RTC_HRS: - case RTC_WDAY: - case RTC_DAY: - case RTC_MONTH: - case RTC_YEAR: - /* - * Ignore writes to the time of day registers - */ - break; - case RTC_NVRAM_START ... RTC_NVRAM_END: - rtc_nvram[addr - RTC_NVRAM_START] = *eax; - break; - default: - return (-1); - } - return (0); + return (t); } void -rtc_init(struct vmctx *ctx) +rtc_init(struct vmctx *ctx, int use_localtime) { - struct timeval cur; - struct tm tm; size_t himem; size_t lomem; int err; - err = gettimeofday(&cur, NULL); - assert(err == 0); - (void) localtime_r(&cur.tv_sec, &tm); - - memset(rtc_nvram, 0, sizeof(rtc_nvram)); - - rtc_nvram[nvoff(RTC_CENTURY)] = bin2bcd((tm.tm_year + 1900) / 100); - /* XXX init diag/reset code/equipment/checksum ? */ /* @@ -344,17 +86,22 @@ rtc_init(struct vmctx *ctx) * 0x5b/0x5c/0x5d - 64KB chunks above 4GB */ lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB; - rtc_nvram[nvoff(RTC_LMEM_LSB)] = lomem; - rtc_nvram[nvoff(RTC_LMEM_MSB)] = lomem >> 8; + err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem); + assert(err == 0); + err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8); + assert(err == 0); himem = vm_get_highmem_size(ctx) / m_64KB; - rtc_nvram[nvoff(RTC_HMEM_LSB)] = himem; - rtc_nvram[nvoff(RTC_HMEM_SB)] = himem >> 8; - rtc_nvram[nvoff(RTC_HMEM_MSB)] = himem >> 16; -} + err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem); + assert(err == 0); + err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8); + assert(err == 0); + err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16); + assert(err == 0); -INOUT_PORT(rtc, IO_RTC, IOPORT_F_INOUT, rtc_addr_handler); -INOUT_PORT(rtc, IO_RTC + 1, IOPORT_F_INOUT, rtc_data_handler); + err = vm_rtc_settime(ctx, rtc_time(ctx, use_localtime)); + assert(err == 0); +} static void rtc_dsdt(void) diff --git a/usr.sbin/bhyve/rtc.h b/usr.sbin/bhyve/rtc.h index 72cffb3..5b08ca3 100644 --- a/usr.sbin/bhyve/rtc.h +++ b/usr.sbin/bhyve/rtc.h @@ -29,6 +29,6 @@ #ifndef _RTC_H_ #define _RTC_H_ -void rtc_init(struct vmctx *ctx); +void rtc_init(struct vmctx *ctx, int use_localtime); #endif /* _RTC_H_ */ diff --git a/usr.sbin/bhyve/task_switch.c b/usr.sbin/bhyve/task_switch.c index b939c1a..ba6a9d2 100644 --- a/usr.sbin/bhyve/task_switch.c +++ b/usr.sbin/bhyve/task_switch.c @@ -725,21 +725,11 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) assert(paging->cpu_mode == CPU_MODE_PROTECTED); /* - * Calculate the %eip to store in the old TSS before modifying the - * 'inst_length'. + * Calculate the instruction pointer to store in the old TSS. */ eip = vmexit->rip + vmexit->inst_length; /* - * Set the 'inst_length' to '0'. - * - * If an exception is triggered during emulation of the task switch - * then the exception handler should return to the instruction that - * caused the task switch as opposed to the subsequent instruction. - */ - vmexit->inst_length = 0; - - /* * Section 4.6, "Access Rights" in Intel SDM Vol 3. * The following page table accesses are implicitly supervisor mode: * - accesses to GDT or LDT to load segment descriptors @@ -883,8 +873,8 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) * after this point will be handled in the context of the new task and * the saved instruction pointer will belong to the new task. */ - vmexit->rip = newtss.tss_eip; - assert(vmexit->inst_length == 0); + error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RIP, newtss.tss_eip); + assert(error == 0); /* Load processor state from new TSS */ error = tss32_restore(ctx, vcpu, task_switch, ot_sel, &newtss, nt_iov); diff --git a/usr.sbin/bhyve/xmsr.c b/usr.sbin/bhyve/xmsr.c index d50a939..5b7bfbb 100644 --- a/usr.sbin/bhyve/xmsr.c +++ b/usr.sbin/bhyve/xmsr.c @@ -185,6 +185,15 @@ emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t *val) *val = 0; break; + /* + * OpenBSD guests test bit 0 of this MSR to detect if the + * workaround for erratum 721 is already applied. + * http://support.amd.com/TechDocs/41322_10h_Rev_Gd.pdf + */ + case 0xC0011029: + *val = 1; + break; + default: error = -1; break; diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c index 0c4457e..e2b514d 100644 --- a/usr.sbin/bhyvectl/bhyvectl.c +++ b/usr.sbin/bhyvectl/bhyvectl.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <fcntl.h> #include <string.h> #include <getopt.h> +#include <time.h> #include <assert.h> #include <machine/cpufunc.h> @@ -157,6 +158,11 @@ usage(bool cpu_intel) " [--inject-nmi]\n" " [--force-reset]\n" " [--force-poweroff]\n" + " [--get-rtc-time]\n" + " [--set-rtc-time=<secs>]\n" + " [--get-rtc-nvram]\n" + " [--set-rtc-nvram=<val>]\n" + " [--rtc-nvram-offset=<offset>]\n" " [--get-active-cpus]\n" " [--get-suspended-cpus]\n" " [--get-intinfo]\n" @@ -220,6 +226,12 @@ usage(bool cpu_intel) exit(1); } +static int get_rtc_time, set_rtc_time; +static int get_rtc_nvram, set_rtc_nvram; +static int rtc_nvram_offset; +static uint8_t rtc_nvram_value; +static time_t rtc_secs; + static int get_stats, getcap, setcap, capval, get_gpa_pmap; static int inject_nmi, assert_lapic_lvt; static int force_reset, force_poweroff; @@ -545,6 +557,9 @@ enum { UNASSIGN_PPTDEV, GET_GPA_PMAP, ASSERT_LAPIC_LVT, + SET_RTC_TIME, + SET_RTC_NVRAM, + RTC_NVRAM_OFFSET, }; static void @@ -1269,6 +1284,11 @@ setup_options(bool cpu_intel) { "setcap", REQ_ARG, 0, SET_CAP }, { "get-gpa-pmap", REQ_ARG, 0, GET_GPA_PMAP }, { "assert-lapic-lvt", REQ_ARG, 0, ASSERT_LAPIC_LVT }, + { "get-rtc-time", NO_ARG, &get_rtc_time, 1 }, + { "set-rtc-time", REQ_ARG, 0, SET_RTC_TIME }, + { "rtc-nvram-offset", REQ_ARG, 0, RTC_NVRAM_OFFSET }, + { "get-rtc-nvram", NO_ARG, &get_rtc_nvram, 1 }, + { "set-rtc-nvram", REQ_ARG, 0, SET_RTC_NVRAM }, { "getcap", NO_ARG, &getcap, 1 }, { "get-stats", NO_ARG, &get_stats, 1 }, { "get-desc-ds",NO_ARG, &get_desc_ds, 1 }, @@ -1462,6 +1482,33 @@ setup_options(bool cpu_intel) return (all_opts); } +static const char * +wday_str(int idx) +{ + static const char *weekdays[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + + if (idx >= 0 && idx < 7) + return (weekdays[idx]); + else + return ("UNK"); +} + +static const char * +mon_str(int idx) +{ + static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + if (idx >= 0 && idx < 12) + return (months[idx]); + else + return ("UNK"); +} + int main(int argc, char *argv[]) { @@ -1477,6 +1524,7 @@ main(int argc, char *argv[]) cpuset_t cpus; bool cpu_intel; uint64_t cs, ds, es, fs, gs, ss, tr, ldtr; + struct tm tm; struct option *opts; cpu_intel = cpu_vendor_intel(); @@ -1594,6 +1642,17 @@ main(int argc, char *argv[]) capval = strtoul(optarg, NULL, 0); setcap = 1; break; + case SET_RTC_TIME: + rtc_secs = strtoul(optarg, NULL, 0); + set_rtc_time = 1; + break; + case SET_RTC_NVRAM: + rtc_nvram_value = (uint8_t)strtoul(optarg, NULL, 0); + set_rtc_nvram = 1; + break; + case RTC_NVRAM_OFFSET: + rtc_nvram_offset = strtoul(optarg, NULL, 0); + break; case GET_GPA_PMAP: gpa_pmap = strtoul(optarg, NULL, 0); get_gpa_pmap = 1; @@ -1971,6 +2030,31 @@ main(int argc, char *argv[]) } } + if (!error && set_rtc_nvram) + error = vm_rtc_write(ctx, rtc_nvram_offset, rtc_nvram_value); + + if (!error && (get_rtc_nvram || get_all)) { + error = vm_rtc_read(ctx, rtc_nvram_offset, &rtc_nvram_value); + if (error == 0) { + printf("rtc nvram[%03d]: 0x%02x\n", rtc_nvram_offset, + rtc_nvram_value); + } + } + + if (!error && set_rtc_time) + error = vm_rtc_settime(ctx, rtc_secs); + + if (!error && (get_rtc_time || get_all)) { + error = vm_rtc_gettime(ctx, &rtc_secs); + if (error == 0) { + gmtime_r(&rtc_secs, &tm); + printf("rtc time %#lx: %s %s %02d %02d:%02d:%02d %d\n", + rtc_secs, wday_str(tm.tm_wday), mon_str(tm.tm_mon), + tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, + 1900 + tm.tm_year); + } + } + if (!error && (getcap || get_all)) { int captype, val, getcaptype; @@ -2034,10 +2118,7 @@ main(int argc, char *argv[]) } if (!error && run) { - error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RIP, &rip); - assert(error == 0); - - error = vm_run(ctx, vcpu, rip, &vmexit); + error = vm_run(ctx, vcpu, &vmexit); if (error == 0) dump_vm_run_exitcode(&vmexit, vcpu); else |