diff options
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 104 | ||||
-rw-r--r-- | sys/arch/amd64/include/vmmvar.h | 6 | ||||
-rw-r--r-- | sys/dev/pv/pvbus.c | 4 | ||||
-rw-r--r-- | sys/dev/pv/pvclock.c | 23 | ||||
-rw-r--r-- | sys/dev/pv/pvreg.h | 22 |
5 files changed, 115 insertions, 44 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index 66bd38c77f4..bdbecb9560b 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.243 2019/05/12 20:56:34 pd Exp $ */ +/* $OpenBSD: vmm.c,v 1.244 2019/05/13 15:40:34 pd Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -28,6 +28,7 @@ #include <sys/rwlock.h> #include <sys/pledge.h> #include <sys/memrange.h> +#include <sys/timetc.h> #include <uvm/uvm_extern.h> @@ -39,6 +40,7 @@ #include <machine/vmmvar.h> #include <dev/isa/isareg.h> +#include <dev/pv/pvreg.h> /* #define VMM_DEBUG */ @@ -199,6 +201,9 @@ void vmx_setmsrbrw(struct vcpu *, uint32_t); void svm_set_clean(struct vcpu *, uint32_t); void svm_set_dirty(struct vcpu *, uint32_t); +void vmm_init_pvclock(struct vcpu *, paddr_t); +int vmm_update_pvclock(struct vcpu *); + #ifdef VMM_DEBUG void dump_vcpu(struct vcpu *); void vmx_vcpu_dump_regs(struct vcpu *); @@ -3234,6 +3239,7 @@ vcpu_init(struct vcpu *vcpu) vcpu->vc_virt_mode = vmm_softc->mode; vcpu->vc_state = VCPU_STATE_STOPPED; vcpu->vc_vpid = 0; + vcpu->vc_pvclock_system_gpa = 0; if (vmm_softc->mode == VMM_MODE_VMX || vmm_softc->mode == VMM_MODE_EPT) ret = vcpu_init_vmx(vcpu); @@ -4190,6 +4196,7 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) } while (ret == 0) { + vmm_update_pvclock(vcpu); if (!resume) { /* * We are launching for the first time, or we are @@ -6065,26 +6072,30 @@ vmx_handle_wrmsr(struct vcpu *vcpu) rdx = &vcpu->vc_gueststate.vg_rdx; switch (*rcx) { - case MSR_MISC_ENABLE: - vmx_handle_misc_enable_msr(vcpu); - break; - case MSR_SMM_MONITOR_CTL: - /* - * 34.15.5 - Enabling dual monitor treatment - * - * Unsupported, so inject #GP and return without - * advancing %rip. - */ - ret = vmm_inject_gp(vcpu); - return (ret); + case MSR_MISC_ENABLE: + vmx_handle_misc_enable_msr(vcpu); + break; + case MSR_SMM_MONITOR_CTL: + /* + * 34.15.5 - Enabling dual monitor treatment + * + * Unsupported, so inject #GP and return without + * advancing %rip. + */ + ret = vmm_inject_gp(vcpu); + return (ret); + case KVM_MSR_SYSTEM_TIME: + vmm_init_pvclock(vcpu, + (*rax & 0xFFFFFFFFULL) | (*rdx << 32)); + break; #ifdef VMM_DEBUG - default: - /* - * Log the access, to be able to identify unknown MSRs - */ - DPRINTF("%s: wrmsr exit, msr=0x%llx, discarding data " - "written from guest=0x%llx:0x%llx\n", __func__, - *rcx, *rdx, *rax); + default: + /* + * Log the access, to be able to identify unknown MSRs + */ + DPRINTF("%s: wrmsr exit, msr=0x%llx, discarding data " + "written from guest=0x%llx:0x%llx\n", __func__, + *rcx, *rdx, *rax); #endif /* VMM_DEBUG */ } @@ -6122,6 +6133,9 @@ svm_handle_msr(struct vcpu *vcpu) if (vmcb->v_exitinfo1 == 1) { if (*rcx == MSR_EFER) { vmcb->v_efer = *rax | EFER_SVME; + } else if (*rcx == KVM_MSR_SYSTEM_TIME) { + vmm_init_pvclock(vcpu, + (*rax & 0xFFFFFFFFULL) | (*rdx << 32)); } else { #ifdef VMM_DEBUG /* Log the access, to be able to identify unknown MSRs */ @@ -6419,6 +6433,13 @@ vmm_handle_cpuid(struct vcpu *vcpu) *rcx = *((uint32_t *)&vmm_hv_signature[4]); *rdx = *((uint32_t *)&vmm_hv_signature[8]); break; + case 0x40000001: /* KVM hypervisor features */ + *rax = (1 << KVM_FEATURE_CLOCKSOURCE2) | + (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); + *rbx = 0; + *rcx = 0; + *rdx = 0; + break; case 0x80000000: /* Extended function level */ *rax = 0x80000008; /* curcpu()->ci_pnfeatset */ *rbx = 0; @@ -6537,6 +6558,7 @@ vcpu_run_svm(struct vcpu *vcpu, struct vm_run_params *vrp) } while (ret == 0) { + vmm_update_pvclock(vcpu); if (!resume) { /* * We are launching for the first time, or we are @@ -6773,6 +6795,48 @@ vmm_free_vpid(uint16_t vpid) rw_exit_write(&vmm_softc->vpid_lock); } +void +vmm_init_pvclock(struct vcpu *vcpu, paddr_t gpa) +{ + vcpu->vc_pvclock_system_gpa = gpa; + vcpu->vc_pvclock_system_tsc_mul = + (int) ((1000000000L << 20) / tc_getfrequency()); + vmm_update_pvclock(vcpu); +} + +int +vmm_update_pvclock(struct vcpu *vcpu) +{ + struct pvclock_time_info *pvclock_ti; + struct timespec tv; + struct vm *vm = vcpu->vc_parent; + paddr_t pvclock_hpa, pvclock_gpa; + + if (vcpu->vc_pvclock_system_gpa & PVCLOCK_SYSTEM_TIME_ENABLE) { + pvclock_gpa = vcpu->vc_pvclock_system_gpa & 0xFFFFFFFFFFFFFFF0; + if (!pmap_extract(vm->vm_map->pmap, pvclock_gpa, &pvclock_hpa)) + return (EINVAL); + pvclock_ti = (void*) PMAP_DIRECT_MAP(pvclock_hpa); + + /* START next cycle (must be odd) */ + pvclock_ti->ti_version = + (++vcpu->vc_pvclock_version << 1) | 0x1; + + pvclock_ti->ti_tsc_timestamp = rdtsc(); + nanotime(&tv); + pvclock_ti->ti_system_time = + tv.tv_sec * 1000000000L + tv.tv_nsec; + pvclock_ti->ti_tsc_shift = -20; + pvclock_ti->ti_tsc_to_system_mul = + vcpu->vc_pvclock_system_tsc_mul; + pvclock_ti->ti_flags = PVCLOCK_FLAG_TSC_STABLE; + + /* END (must be even) */ + pvclock_ti->ti_version &= ~0x1; + } + return (0); +} + /* * vmx_exit_reason_decode * diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h index 5bbc099740f..a6dfab50d00 100644 --- a/sys/arch/amd64/include/vmmvar.h +++ b/sys/arch/amd64/include/vmmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmmvar.h,v 1.64 2019/05/12 20:56:34 pd Exp $ */ +/* $OpenBSD: vmmvar.h,v 1.65 2019/05/13 15:40:34 pd Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -890,6 +890,10 @@ struct vcpu { uint8_t vc_event; + uint32_t vc_pvclock_version; + paddr_t vc_pvclock_system_gpa; + uint32_t vc_pvclock_system_tsc_mul; + /* VMX only */ uint64_t vc_vmx_basic; uint64_t vc_vmx_entry_ctls; diff --git a/sys/dev/pv/pvbus.c b/sys/dev/pv/pvbus.c index 885cf702c20..6c7b0be643f 100644 --- a/sys/dev/pv/pvbus.c +++ b/sys/dev/pv/pvbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pvbus.c,v 1.18 2018/01/18 11:43:20 mikeb Exp $ */ +/* $OpenBSD: pvbus.c,v 1.19 2019/05/13 15:40:34 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -90,7 +90,7 @@ struct pvbus_type { { "VMwareVMware", "VMware" }, { "XenVMMXenVMM", "Xen", pvbus_xen, pvbus_xen_print }, { "bhyve bhyve ", "bhyve" }, - { VMM_HV_SIGNATURE, "OpenBSD" }, + { VMM_HV_SIGNATURE, "OpenBSD", pvbus_kvm }, }; struct bus_dma_tag pvbus_dma_tag = { diff --git a/sys/dev/pv/pvclock.c b/sys/dev/pv/pvclock.c index 05eebf783c2..1325f89887b 100644 --- a/sys/dev/pv/pvclock.c +++ b/sys/dev/pv/pvclock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pvclock.c,v 1.3 2018/12/05 18:02:51 reyk Exp $ */ +/* $OpenBSD: pvclock.c,v 1.4 2019/05/13 15:40:34 pd Exp $ */ /* * Copyright (c) 2018 Reyk Floeter <reyk@openbsd.org> @@ -41,25 +41,6 @@ struct pvclock_softc { struct timecounter *sc_tc; }; -struct pvclock_wall_clock { - uint32_t wc_version; - uint32_t wc_sec; - uint32_t wc_nsec; -} __packed; - -struct pvclock_time_info { - uint32_t ti_version; - uint32_t ti_pad0; - uint64_t ti_tsc_timestamp; - uint64_t ti_system_time; - uint32_t ti_tsc_to_system_mul; - int8_t ti_tsc_shift; - uint8_t ti_flags; - uint8_t ti_pad[2]; -} __packed; - -#define PVCLOCK_FLAG_TSC_STABLE 0x01 -#define PVCLOCK_SYSTEM_TIME_ENABLE 0x01 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) int pvclock_match(struct device *, void *, void *); @@ -104,6 +85,8 @@ pvclock_match(struct device *parent, void *match, void *aux) * only support the "kvmclock". */ hv = &pva->pva_hv[PVBUS_KVM]; + if (hv->hv_base == 0) + hv = &pva->pva_hv[PVBUS_OPENBSD]; if (hv->hv_base != 0) { /* * We only implement support for the 2nd version of pvclock. diff --git a/sys/dev/pv/pvreg.h b/sys/dev/pv/pvreg.h index df83489d0cf..c5c60ce0e8f 100644 --- a/sys/dev/pv/pvreg.h +++ b/sys/dev/pv/pvreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pvreg.h,v 1.5 2018/11/23 12:37:40 reyk Exp $ */ +/* $OpenBSD: pvreg.h,v 1.6 2019/05/13 15:40:34 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -46,6 +46,26 @@ #define KVM_MSR_WALL_CLOCK 0x4b564d00 #define KVM_MSR_SYSTEM_TIME 0x4b564d01 +struct pvclock_wall_clock { + uint32_t wc_version; + uint32_t wc_sec; + uint32_t wc_nsec; +} __packed; + +struct pvclock_time_info { + uint32_t ti_version; + uint32_t ti_pad0; + uint64_t ti_tsc_timestamp; + uint64_t ti_system_time; + uint32_t ti_tsc_to_system_mul; + int8_t ti_tsc_shift; + uint8_t ti_flags; + uint8_t ti_pad[2]; +} __packed; + +#define PVCLOCK_FLAG_TSC_STABLE 0x01 +#define PVCLOCK_SYSTEM_TIME_ENABLE 0x01 + /* * Hyper-V */ |