aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-12-22 06:25:20 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-12-22 06:25:20 +0000
commitffac39deae0a2e50aa8d1197d15b8d0bb7e778fd (patch)
tree7cc54cf998fe4ddc1699fa454d51d5f3316dcad5 /sys
parente87e283ce36f0c12b442244e4e5f679c17d8bb50 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/vmgenc/vmgenc_acpi.c240
-rw-r--r--sys/dev/vmgenc/vmgenc_acpi.h47
3 files changed, 288 insertions, 0 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 86a03cb36c208..bb1614fca784b 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3398,6 +3398,7 @@ dev/virtio/scsi/virtio_scsi.c optional virtio_scsi
dev/virtio/random/virtio_random.c optional virtio_random
dev/virtio/console/virtio_console.c optional virtio_console
dev/vkbd/vkbd.c optional vkbd
+dev/vmgenc/vmgenc_acpi.c optional acpi
dev/vr/if_vr.c optional vr pci
dev/vt/colors/vt_termcolors.c optional vt
dev/vt/font/vt_font_default.c optional vt
diff --git a/sys/dev/vmgenc/vmgenc_acpi.c b/sys/dev/vmgenc/vmgenc_acpi.c
new file mode 100644
index 0000000000000..dc86bff59ba53
--- /dev/null
+++ b/sys/dev/vmgenc/vmgenc_acpi.c
@@ -0,0 +1,240 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Conrad Meyer <cem@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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+/*
+ * VM Generation Counter driver
+ *
+ * See, e.g., the "Virtual Machine Generation ID" white paper:
+ * https://go.microsoft.com/fwlink/p/?LinkID=260709 , and perhaps also:
+ * https://docs.microsoft.com/en-us/windows/win32/hyperv_v2/virtual-machine-generation-identifier ,
+ * https://azure.microsoft.com/en-us/blog/accessing-and-using-azure-vm-unique-id/
+ *
+ * Microsoft introduced the concept in 2013 or so and seems to have
+ * successfully driven it to a consensus standard among hypervisors, not just
+ * HyperV/Azure:
+ * - QEMU: https://bugzilla.redhat.com/show_bug.cgi?id=1118834
+ * - VMware/ESXi: https://kb.vmware.com/s/article/2032586
+ * - Xen: https://github.com/xenserver/xen-4.5/blob/master/tools/firmware/hvmloader/acpi/dsdt.asl#L456
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+
+#include <dev/acpica/acpivar.h>
+#include <dev/vmgenc/vmgenc_acpi.h>
+
+#ifndef ACPI_NOTIFY_STATUS_CHANGED
+#define ACPI_NOTIFY_STATUS_CHANGED 0x80
+#endif
+
+#define GUID_BYTES 16
+
+static const char *vmgenc_ids[] = {
+ "VM_GEN_COUNTER",
+ NULL
+};
+#if 0
+MODULE_PNP_INFO("Z:_CID", acpi, vmgenc, vmgenc_ids, nitems(vmgenc_ids) - 1);
+#endif
+
+struct vmgenc_softc {
+ volatile void *vmg_pguid;
+ uint8_t vmg_cache_guid[GUID_BYTES];
+};
+
+static void
+vmgenc_status_changed(void *context)
+{
+ uint8_t guid[GUID_BYTES];
+ struct vmgenc_softc *sc;
+ device_t dev;
+
+ dev = context;
+ sc = device_get_softc(dev);
+
+ /* Check for spurious notify events. */
+ memcpy(guid, __DEVOLATILE(void *, sc->vmg_pguid), sizeof(guid));
+ if (memcmp(guid, sc->vmg_cache_guid, GUID_BYTES) == 0)
+ return; /* No change. */
+
+ /* Update cache. */
+ memcpy(sc->vmg_cache_guid, guid, GUID_BYTES);
+
+ EVENTHANDLER_INVOKE(acpi_vmgenc_event);
+ acpi_UserNotify("VMGenerationCounter", acpi_get_handle(dev), 0);
+}
+
+static void
+vmgenc_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+ device_t dev;
+
+ dev = context;
+ switch (notify) {
+ case ACPI_NOTIFY_STATUS_CHANGED:
+ /*
+ * We're possibly in GPE / interrupt context, kick the event up
+ * to a taskqueue.
+ */
+ AcpiOsExecute(OSL_NOTIFY_HANDLER, vmgenc_status_changed, dev);
+ break;
+ default:
+ device_printf(dev, "unknown notify %#x\n", notify);
+ break;
+ }
+}
+
+static int
+vmgenc_probe(device_t dev)
+{
+ int rv;
+
+ if (acpi_disabled("vmgenc"))
+ return (ENXIO);
+ rv = ACPI_ID_PROBE(device_get_parent(dev), dev,
+ __DECONST(char **, vmgenc_ids), NULL);
+ if (rv <= 0)
+ device_set_desc(dev, "VM Generation Counter");
+ return (rv);
+}
+
+static const char *
+vmgenc_acpi_getname(ACPI_HANDLE handle, char data[static 256])
+{
+ ACPI_BUFFER buf;
+
+ buf.Length = 256;
+ buf.Pointer = data;
+
+ if (ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf)))
+ return (data);
+ return ("(unknown)");
+}
+
+static int
+acpi_GetPackedUINT64(device_t dev, ACPI_HANDLE handle, char *path,
+ uint64_t *out)
+{
+ char hpath[256];
+ ACPI_STATUS status;
+ ACPI_BUFFER buf;
+ ACPI_OBJECT param[3];
+
+ buf.Pointer = param;
+ buf.Length = sizeof(param);
+ status = AcpiEvaluateObject(handle, path, NULL, &buf);
+ if (!ACPI_SUCCESS(status)) {
+ device_printf(dev, "%s(%s::%s()): %s\n", __func__,
+ vmgenc_acpi_getname(handle, hpath), path,
+ AcpiFormatException(status));
+ return (ENXIO);
+ }
+ if (param[0].Type != ACPI_TYPE_PACKAGE) {
+ device_printf(dev, "%s(%s::%s()): Wrong type %#x\n", __func__,
+ vmgenc_acpi_getname(handle, hpath), path,
+ param[0].Type);
+ return (ENXIO);
+ }
+ if (param[0].Package.Count != 2) {
+ device_printf(dev, "%s(%s::%s()): Wrong number of results %u\n",
+ __func__, vmgenc_acpi_getname(handle, hpath), path,
+ param[0].Package.Count);
+ return (ENXIO);
+ }
+ if (param[0].Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
+ param[0].Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
+ device_printf(dev, "%s(%s::%s()): Wrong type results %#x, %#x\n",
+ __func__, vmgenc_acpi_getname(handle, hpath), path,
+ param[0].Package.Elements[0].Type,
+ param[0].Package.Elements[1].Type);
+ return (ENXIO);
+ }
+
+ *out = (param[0].Package.Elements[0].Integer.Value & UINT32_MAX) |
+ ((uint64_t)param[0].Package.Elements[1].Integer.Value << 32);
+ if (*out == 0)
+ return (ENXIO);
+ return (0);
+
+}
+
+static int
+vmgenc_attach(device_t dev)
+{
+ struct vmgenc_softc *sc;
+ uint64_t guid_physaddr;
+ ACPI_HANDLE h;
+ int error;
+
+ h = acpi_get_handle(dev);
+ sc = device_get_softc(dev);
+
+ error = acpi_GetPackedUINT64(dev, h, "ADDR", &guid_physaddr);
+ if (error != 0)
+ return (error);
+
+ SYSCTL_ADD_OPAQUE(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "guid",
+ CTLFLAG_RD, sc->vmg_cache_guid, GUID_BYTES, "",
+ "latest cached VM generation counter (128-bit UUID)");
+
+ sc->vmg_pguid = AcpiOsMapMemory(guid_physaddr, GUID_BYTES);
+ memcpy(sc->vmg_cache_guid, __DEVOLATILE(void *, sc->vmg_pguid),
+ sizeof(sc->vmg_cache_guid));
+
+ AcpiInstallNotifyHandler(h, ACPI_DEVICE_NOTIFY, vmgenc_notify, dev);
+ return (0);
+}
+
+static device_method_t vmgenc_methods[] = {
+ DEVMETHOD(device_probe, vmgenc_probe),
+ DEVMETHOD(device_attach, vmgenc_attach),
+ DEVMETHOD_END
+};
+
+static driver_t vmgenc_driver = {
+ "vmgenc",
+ vmgenc_methods,
+ sizeof(struct vmgenc_softc),
+};
+
+static devclass_t vmgenc_devclass;
+DRIVER_MODULE(vmgenc, acpi, vmgenc_driver, vmgenc_devclass, NULL, NULL);
+MODULE_DEPEND(vmgenc, acpi, 1, 1, 1);
diff --git a/sys/dev/vmgenc/vmgenc_acpi.h b/sys/dev/vmgenc/vmgenc_acpi.h
new file mode 100644
index 0000000000000..8ad750baabe03
--- /dev/null
+++ b/sys/dev/vmgenc/vmgenc_acpi.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Conrad Meyer <cem@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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+#include <sys/_eventhandler.h>
+
+/*
+ * VM Generation Counter driver
+ *
+ * This driver has two functions: first, it provides a system event (both in
+ * the kernel EVENTHANDLER framework as well as a userspace devctl event)
+ * whenever a VM has been (HyperV doc, for example):
+ * - Snapped and the snapshot is executing
+ * - Recovered from backup
+ * - Failed over in a HA setup
+ * - Imported, copied, or cloned
+ * - And unspecified if VM configuration changes might cause a changed
+ * generation counter
+ *
+ * Second, it can read the current VM generation counter, a 128-bit GUID.
+ */
+typedef void (*vmgenc_handler)(void *);
+EVENTHANDLER_DECLARE(acpi_vmgenc_event, vmgenc_handler);