summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-10-26 04:44:28 +0000
committerneel <neel@FreeBSD.org>2014-10-26 04:44:28 +0000
commiteb58530f9bb9d086a7a00af1e840a2c1d49f56ca (patch)
treeb8049f7eda99ce6b0c7d3a4c2b78de5a46539072 /sys/amd64/vmm
parenta76d8ee4e9b6e0f73c4210907a7f9773ca25c154 (diff)
downloadFreeBSD-src-eb58530f9bb9d086a7a00af1e840a2c1d49f56ca.zip
FreeBSD-src-eb58530f9bb9d086a7a00af1e840a2c1d49f56ca.tar.gz
Move the ACPI PM timer emulation into vmm.ko.
This reduces variability during timer calibration by keeping the emulation "close" to the guest. Additionally having all timer emulations in the kernel will ease the transition to a per-VM clock source (as opposed to using the host's uptime keep track of time). Discussed with: grehan
Diffstat (limited to 'sys/amd64/vmm')
-rw-r--r--sys/amd64/vmm/io/vpmtmr.c104
-rw-r--r--sys/amd64/vmm/io/vpmtmr.h42
-rw-r--r--sys/amd64/vmm/vmm.c11
-rw-r--r--sys/amd64/vmm/vmm_ioport.c2
4 files changed, 159 insertions, 0 deletions
diff --git a/sys/amd64/vmm/io/vpmtmr.c b/sys/amd64/vmm/io/vpmtmr.c
new file mode 100644
index 0000000..4f56542
--- /dev/null
+++ b/sys/amd64/vmm/io/vpmtmr.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2014, Neel Natu (neel@freebsd.org)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/cpuset.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <machine/vmm.h>
+
+#include "vpmtmr.h"
+
+/*
+ * The ACPI Power Management timer is a free-running 24- or 32-bit
+ * timer with a frequency of 3.579545MHz
+ *
+ * This implementation will be 32-bits
+ */
+
+#define PMTMR_FREQ 3579545 /* 3.579545MHz */
+
+struct vpmtmr {
+ sbintime_t freq_sbt;
+ sbintime_t baseuptime;
+ uint32_t baseval;
+};
+
+static MALLOC_DEFINE(M_VPMTMR, "vpmtmr", "bhyve virtual acpi timer");
+
+struct vpmtmr *
+vpmtmr_init(struct vm *vm)
+{
+ struct vpmtmr *vpmtmr;
+ struct bintime bt;
+
+ vpmtmr = malloc(sizeof(struct vpmtmr), M_VPMTMR, M_WAITOK | M_ZERO);
+ vpmtmr->baseuptime = sbinuptime();
+ vpmtmr->baseval = 0;
+
+ FREQ2BT(PMTMR_FREQ, &bt);
+ vpmtmr->freq_sbt = bttosbt(bt);
+
+ return (vpmtmr);
+}
+
+void
+vpmtmr_cleanup(struct vpmtmr *vpmtmr)
+{
+
+ free(vpmtmr, M_VPMTMR);
+}
+
+int
+vpmtmr_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *val)
+{
+ struct vpmtmr *vpmtmr;
+ sbintime_t now, delta;
+
+ if (!in || bytes != 4)
+ return (-1);
+
+ vpmtmr = vm_pmtmr(vm);
+
+ /*
+ * No locking needed because 'baseuptime' and 'baseval' are
+ * written only during initialization.
+ */
+ now = sbinuptime();
+ delta = now - vpmtmr->baseuptime;
+ KASSERT(delta >= 0, ("vpmtmr_handler: uptime went backwards: "
+ "%#lx to %#lx", vpmtmr->baseuptime, now));
+ *val = vpmtmr->baseval + delta / vpmtmr->freq_sbt;
+
+ return (0);
+}
diff --git a/sys/amd64/vmm/io/vpmtmr.h b/sys/amd64/vmm/io/vpmtmr.h
new file mode 100644
index 0000000..e68a18f
--- /dev/null
+++ b/sys/amd64/vmm/io/vpmtmr.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2014 Neel Natu (neel@freebsd.org)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VPMTMR_H_
+#define _VPMTMR_H_
+
+#define IO_PMTMR 0x408
+
+struct vpmtmr;
+
+struct vpmtmr *vpmtmr_init(struct vm *vm);
+void vpmtmr_cleanup(struct vpmtmr *pmtmr);
+
+int vpmtmr_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *val);
+
+#endif
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 7d06749..aaa9d23 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -74,6 +74,7 @@ __FBSDID("$FreeBSD$");
#include "vhpet.h"
#include "vioapic.h"
#include "vlapic.h"
+#include "vpmtmr.h"
#include "vmm_ipi.h"
#include "vmm_stat.h"
#include "vmm_lapic.h"
@@ -134,6 +135,7 @@ struct vm {
struct vioapic *vioapic; /* (i) virtual ioapic */
struct vatpic *vatpic; /* (i) virtual atpic */
struct vatpit *vatpit; /* (i) virtual atpit */
+ struct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */
volatile cpuset_t active_cpus; /* (i) active vcpus */
int suspend; /* (i) stop VM execution */
volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */
@@ -360,6 +362,7 @@ vm_init(struct vm *vm, bool create)
vm->vhpet = vhpet_init(vm);
vm->vatpic = vatpic_init(vm);
vm->vatpit = vatpit_init(vm);
+ vm->vpmtmr = vpmtmr_init(vm);
CPU_ZERO(&vm->active_cpus);
@@ -422,6 +425,7 @@ vm_cleanup(struct vm *vm, bool destroy)
if (vm->iommu != NULL)
iommu_destroy_domain(vm->iommu);
+ vpmtmr_cleanup(vm->vpmtmr);
vatpit_cleanup(vm->vatpit);
vhpet_cleanup(vm->vhpet);
vatpic_cleanup(vm->vatpic);
@@ -2199,6 +2203,13 @@ vm_atpit(struct vm *vm)
return (vm->vatpit);
}
+struct vpmtmr *
+vm_pmtmr(struct vm *vm)
+{
+
+ return (vm->vpmtmr);
+}
+
enum vm_reg_name
vm_segment_name(int seg)
{
diff --git a/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c
index 564ca74..e553599 100644
--- a/sys/amd64/vmm/vmm_ioport.c
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include "vatpic.h"
#include "vatpit.h"
+#include "vpmtmr.h"
#include "vmm_ioport.h"
#include "vmm_ktr.h"
@@ -58,6 +59,7 @@ ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {
[IO_ICU2 + ICU_IMR_OFFSET] = vatpic_slave_handler,
[IO_ELCR1] = vatpic_elc_handler,
[IO_ELCR2] = vatpic_elc_handler,
+ [IO_PMTMR] = vpmtmr_handler,
};
#ifdef KTR
OpenPOWER on IntegriCloud