summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2011-05-13 04:54:01 +0000
committergrehan <grehan@FreeBSD.org>2011-05-13 04:54:01 +0000
commitd45b7f14ae6fa78882fa9ec3be976733ca4767b4 (patch)
tree4af898a91c7d67e7068687610ebc68f1cbdf3b2e /lib
parent1430f46faf0f3eb24ffcd28a3248a565a48236ac (diff)
downloadFreeBSD-src-d45b7f14ae6fa78882fa9ec3be976733ca4767b4.zip
FreeBSD-src-d45b7f14ae6fa78882fa9ec3be976733ca4767b4.tar.gz
Import of bhyve hypervisor and utilities, part 1.
vmm.ko - kernel module for VT-x, VT-d and hypervisor control bhyve - user-space sequencer and i/o emulation vmmctl - dump of hypervisor register state libvmm - front-end to vmm.ko chardev interface bhyve was designed and implemented by Neel Natu. Thanks to the following folk from NetApp who helped to make this available: Joe CaraDonna Peter Snyder Jeff Heller Sandeep Mann Steve Miller Brian Pawlowski
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile2
-rw-r--r--lib/libvmmapi/Makefile9
-rw-r--r--lib/libvmmapi/mptable.c336
-rw-r--r--lib/libvmmapi/mptable.h171
-rw-r--r--lib/libvmmapi/vmmapi.c647
-rw-r--r--lib/libvmmapi/vmmapi.h98
-rw-r--r--lib/libvmmapi/vmmapi_freebsd.c187
7 files changed, 1450 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
index e9f4ec3..8f33206 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -102,6 +102,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libusbhid} \
${_libusb} \
${_libvgl} \
+ ${_libvmmapi} \
libwrap \
liby \
libz \
@@ -177,6 +178,7 @@ _libncp= libncp
.endif
_libsmb= libsmb
_libvgl= libvgl
+_libvmmapi= libvmmapi
.endif
.if ${MACHINE_ARCH} == "powerpc"
diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile
new file mode 100644
index 0000000..492391f
--- /dev/null
+++ b/lib/libvmmapi/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LIB= vmmapi
+SRCS= vmmapi.c vmmapi_freebsd.c mptable.c
+INCS= vmmapi.h
+
+CFLAGS+= -I${.CURDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libvmmapi/mptable.c b/lib/libvmmapi/mptable.c
new file mode 100644
index 0000000..1aea61a
--- /dev/null
+++ b/lib/libvmmapi/mptable.c
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 2011 NetApp, Inc.
+ * 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 NETAPP, INC ``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 NETAPP, INC 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+
+#include "vmmapi.h"
+#include "mptable.h"
+
+#define LAPIC_PADDR (0xFEE00000)
+#define LAPIC_VERSION (16)
+
+#define IOAPIC_PADDR (0xFEC00000)
+#define IOAPIC_VERSION (0x11)
+
+extern int errno;
+
+static uint8_t
+mp_compute_checksum(void *base, size_t len)
+{
+ uint8_t *bytes = base;
+ uint8_t sum = 0;
+ for(; len > 0; len--) {
+ sum += *bytes++;
+ }
+ return 256 - sum;
+}
+
+static void
+mp_build_mpfp(struct mp_floating_pointer *mpfp, vm_paddr_t mpfp_gpa)
+{
+ memset(mpfp, 0, sizeof(*mpfp));
+ memcpy(mpfp->signature, MPFP_SIGNATURE, MPFP_SIGNATURE_LEN);
+ mpfp->mptable_paddr = mpfp_gpa + sizeof(*mpfp);
+ mpfp->specrev = MP_SPECREV;
+ mpfp->feature2 = 0;
+ mpfp->checksum = mp_compute_checksum(mpfp, sizeof(*mpfp));
+}
+
+static void
+mp_build_mpch(struct mp_config_hdr *mpch)
+{
+ memset(mpch, 0, sizeof(*mpch));
+ mpch->specrev = MP_SPECREV;
+ memcpy(mpch->signature, MPCH_SIGNATURE, MPCH_SIGNATURE_LEN);
+ memcpy(mpch->oemid, MPCH_OEMID, MPCH_OEMID_LEN);
+ memcpy(mpch->prodid, MPCH_PRODID, MPCH_PRODID_LEN);
+ mpch->lapic_paddr = LAPIC_PADDR;
+
+
+}
+
+static void
+mp_build_proc_entries(struct mpe_proc *mpep, int num_proc)
+{
+ int i;
+
+ for (i = 0; i < num_proc; i++) {
+ memset(mpep, 0, sizeof(*mpep));
+ mpep->entry_type = MP_ENTRY_PROC;
+ mpep->lapic_id = i; // XXX
+ mpep->lapic_version = LAPIC_VERSION;
+ mpep->proc_flags = (i == 0)?MPEP_FLAGS_BSP:0;
+ mpep->proc_flags |= MPEP_FLAGS_EN;
+ mpep->proc_signature = MPEP_SIGNATURE;
+ mpep->feature_flags = MPEP_FEATURES;
+ mpep++;
+ }
+
+}
+
+static void
+mp_build_bus_entries(struct mpe_bus *mpeb)
+{
+ memset(mpeb, 0, sizeof(*mpeb));
+ mpeb->entry_type = MP_ENTRY_BUS;
+ mpeb->busid = MPE_BUSID_ISA;
+ memcpy(mpeb->busname, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);
+ mpeb++;
+
+ memset(mpeb, 0, sizeof(*mpeb));
+ mpeb->entry_type = MP_ENTRY_BUS;
+ mpeb->busid = MPE_BUSID_PCI;
+ memcpy(mpeb->busname, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN);
+
+}
+
+static void
+mp_build_ioapic_entries(struct mpe_ioapic *mpei)
+{
+ memset(mpei, 0, sizeof(*mpei));
+ mpei->entry_type = MP_ENTRY_IOAPIC;
+ mpei->ioapic_id = MPE_IOAPIC_ID;
+ mpei->ioapic_version = IOAPIC_VERSION;
+ mpei->ioapic_flags = MPE_IOAPIC_FLAG_EN;
+ mpei->ioapic_paddr = IOAPIC_PADDR;
+}
+
+static void
+mp_build_ioint_entries(struct mpe_ioint *mpeii, int num_pins)
+{
+ int pin;
+
+ /*
+ * The following config is taken from kernel mptable.c
+ * mptable_parse_default_config_ints(...), for now
+ * just use the default config, tweek later if needed.
+ */
+
+
+ /* Run through all 16 pins. */
+ for (pin = 0; pin < num_pins; pin++) {
+ memset(mpeii, 0, sizeof(*mpeii));
+ mpeii->entry_type = MP_ENTRY_IOINT;
+ mpeii->src_bus_id = MPE_BUSID_ISA;
+ mpeii->dst_apic_id = MPE_IOAPIC_ID;
+
+ /*
+ * All default configs route IRQs from bus 0 to the first 16 pins
+ * of the first I/O APIC with an APIC ID of 2.
+ */
+ mpeii->dst_apic_intin = pin;
+ switch (pin) {
+ case 0:
+ /* Pin 0 is an ExtINT pin. */
+ mpeii->intr_type = MPEII_INTR_EXTINT;
+ break;
+ case 2:
+ /* IRQ 0 is routed to pin 2. */
+ mpeii->intr_type = MPEII_INTR_INT;
+ mpeii->src_bus_irq = 0;
+ break;
+ case 5:
+ case 10:
+ case 11:
+ /*
+ * PCI Irqs set to level triggered.
+ */
+ mpeii->intr_flags = MPEII_FLAGS_TRIGMODE_LEVEL;
+ mpeii->src_bus_id = MPE_BUSID_PCI;
+ default:
+ /* All other pins are identity mapped. */
+ mpeii->intr_type = MPEII_INTR_INT;
+ mpeii->src_bus_irq = pin;
+ break;
+ }
+ mpeii++;
+ }
+
+}
+
+#define COPYSTR(dest, src, bytes) \
+ memcpy(dest, src, bytes); \
+ str[bytes] = 0;
+
+
+static void
+mptable_dump(struct mp_floating_pointer *mpfp, struct mp_config_hdr *mpch)
+{
+ static char str[16];
+ int i;
+ char *cur;
+
+ union mpe {
+ struct mpe_proc *proc;
+ struct mpe_bus *bus;
+ struct mpe_ioapic *ioapic;
+ struct mpe_ioint *ioint;
+ struct mpe_lint *lnit;
+ char *p;
+ };
+
+ union mpe mpe;
+
+ printf(" MP Floating Pointer :\n");
+ COPYSTR(str, mpfp->signature, 4);
+ printf(" signature: %s\n", str);
+ printf(" mpch paddr: %x\n", mpfp->mptable_paddr);
+ printf(" length: %x\n", mpfp->length);
+ printf(" specrec: %x\n", mpfp->specrev);
+ printf(" checksum: %x\n", mpfp->checksum);
+ printf(" feature1: %x\n", mpfp->feature1);
+ printf(" feature2: %x\n", mpfp->feature2);
+ printf(" feature3: %x\n", mpfp->feature3);
+ printf(" feature4: %x\n", mpfp->feature4);
+
+ printf(" MP Configuration Header :\n");
+ COPYSTR(str, mpch->signature, 4);
+ printf(" signature: %s\n", str);
+ printf(" length: %x\n", mpch->length);
+ printf(" specrec: %x\n", mpch->specrev);
+ printf(" checksum: %x\n", mpch->checksum);
+ COPYSTR(str, mpch->oemid, MPCH_OEMID_LEN);
+ printf(" oemid: %s\n", str);
+ COPYSTR(str, mpch->prodid, MPCH_PRODID_LEN);
+ printf(" prodid: %s\n", str);
+ printf(" oem_ptr: %x\n", mpch->oem_ptr);
+ printf(" oem_sz: %x\n", mpch->oem_sz);
+ printf(" nr_entries: %x\n", mpch->nr_entries);
+ printf(" apic paddr: %x\n", mpch->lapic_paddr);
+ printf(" ext_length: %x\n", mpch->ext_length);
+ printf(" ext_checksum: %x\n", mpch->ext_checksum);
+
+ cur = (char *)mpch + sizeof(*mpch);
+ for (i = 0; i < mpch->nr_entries; i++) {
+ mpe.p = cur;
+ switch(*mpe.p) {
+ case MP_ENTRY_PROC:
+ printf(" MP Processor Entry :\n");
+ printf(" lapic_id: %x\n", mpe.proc->lapic_id);
+ printf(" lapic_version: %x\n", mpe.proc->lapic_version);
+ printf(" proc_flags: %x\n", mpe.proc->proc_flags);
+ printf(" proc_signature: %x\n", mpe.proc->proc_signature);
+ printf(" feature_flags: %x\n", mpe.proc->feature_flags);
+ cur += sizeof(struct mpe_proc);
+ break;
+ case MP_ENTRY_BUS:
+ printf(" MP Bus Entry :\n");
+ printf(" busid: %x\n", mpe.bus->busid);
+ COPYSTR(str, mpe.bus->busname, MPE_BUSNAME_LEN);
+ printf(" busname: %s\n", str);
+ cur += sizeof(struct mpe_bus);
+ break;
+ case MP_ENTRY_IOAPIC:
+ printf(" MP IOAPIC Entry :\n");
+ printf(" ioapi_id: %x\n", mpe.ioapic->ioapic_id);
+ printf(" ioapi_version: %x\n", mpe.ioapic->ioapic_version);
+ printf(" ioapi_flags: %x\n", mpe.ioapic->ioapic_flags);
+ printf(" ioapi_paddr: %x\n", mpe.ioapic->ioapic_paddr);
+ cur += sizeof(struct mpe_ioapic);
+ break;
+ case MP_ENTRY_IOINT:
+ printf(" MP IO Interrupt Entry :\n");
+ printf(" intr_type: %x\n", mpe.ioint->intr_type);
+ printf(" intr_flags: %x\n", mpe.ioint->intr_flags);
+ printf(" src_bus_id: %x\n", mpe.ioint->src_bus_id);
+ printf(" src_bus_irq: %x\n", mpe.ioint->src_bus_irq);
+ printf(" dst_apic_id: %x\n", mpe.ioint->dst_apic_id);
+ printf(" dst_apic_intin: %x\n", mpe.ioint->dst_apic_intin);
+ cur += sizeof(struct mpe_ioint);
+ break;
+ case MP_ENTRY_LINT:
+ printf(" MP Local Interrupt Entry :\n");
+ cur += sizeof(struct mpe_lint);
+ break;
+ }
+
+ }
+}
+
+int
+vm_build_mptable(struct vmctx *ctx, vm_paddr_t gpa, int len, int ncpu,
+ void *oemp, int oemsz)
+{
+ struct mp_config_hdr *mpch;
+ char *mapaddr;
+ char *startaddr;
+ int error;
+
+ mapaddr = vm_map_memory(ctx, gpa, len);
+ if (mapaddr == MAP_FAILED) {
+ printf("%s\n", strerror(errno));
+ goto err;
+ }
+ startaddr = mapaddr;
+
+ mp_build_mpfp((struct mp_floating_pointer*) mapaddr, gpa);
+ mapaddr += sizeof(struct mp_floating_pointer);
+
+ mpch = (struct mp_config_hdr*)mapaddr;
+ mp_build_mpch(mpch);
+ mapaddr += sizeof(struct mp_config_hdr);
+
+ mp_build_proc_entries((struct mpe_proc*) mapaddr, ncpu);
+ mapaddr += (sizeof(struct mpe_proc)*ncpu);
+ mpch->nr_entries += ncpu;
+
+ mp_build_bus_entries((struct mpe_bus*)mapaddr);
+ mapaddr += (sizeof(struct mpe_bus)*MPE_NUM_BUSES);
+ mpch->nr_entries += MPE_NUM_BUSES;
+#if 0
+ mp_build_ioapic_entries((struct mpe_ioapic*)mapaddr);
+ mapaddr += sizeof(struct mpe_ioapic);
+ mpch->nr_entries++;
+
+ mp_build_ioint_entries((struct mpe_ioint*)mapaddr, MPEII_MAX_IRQ);
+ mapaddr += sizeof(struct mpe_ioint)*MPEII_MAX_IRQ;
+ mpch->nr_entries += MPEII_MAX_IRQ;
+
+#endif
+ if (oemp) {
+ mpch->oem_ptr = mapaddr - startaddr + gpa;
+ mpch->oem_sz = oemsz;
+ memcpy(mapaddr, oemp, oemsz);
+ }
+ mpch->length = (mapaddr) - ((char*) mpch);
+ mpch->checksum = mp_compute_checksum(mpch, sizeof(*mpch));
+
+
+ // mptable_dump((struct mp_floating_pointer*)startaddr, mpch);
+err:
+ return (error);
+}
diff --git a/lib/libvmmapi/mptable.h b/lib/libvmmapi/mptable.h
new file mode 100644
index 0000000..cad8834
--- /dev/null
+++ b/lib/libvmmapi/mptable.h
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2011 NetApp, Inc.
+ * 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 NETAPP, INC ``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 NETAPP, INC 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$
+ */
+
+#ifndef _MPTABLE_h_
+#define _MPTABLE_h_
+
+#define MP_SPECREV (4) // MP spec revision 1.1
+
+/*
+ * MP Floating Pointer Structure
+ */
+#define MPFP_SIGNATURE "_MP_"
+#define MPFP_SIGNATURE_LEN (4)
+#define MPFP_FEATURE2 (0x80) // IMCR is present
+struct mp_floating_pointer {
+ uint8_t signature[MPFP_SIGNATURE_LEN];
+ uint32_t mptable_paddr;
+ uint8_t length;
+ uint8_t specrev;
+ uint8_t checksum;
+ uint8_t feature1;
+ uint8_t feature2;
+ uint8_t feature3;
+ uint8_t feature4;
+ uint8_t feature5;
+};
+
+
+/*
+ * MP Configuration Table Header
+ */
+#define MPCH_SIGNATURE "PCMP"
+#define MPCH_SIGNATURE_LEN (4)
+
+#define MPCH_OEMID "NETAPP "
+#define MPCH_OEMID_LEN (8)
+#define MPCH_PRODID "vFiler "
+#define MPCH_PRODID_LEN (12)
+
+struct mp_config_hdr {
+ uint8_t signature[MPCH_SIGNATURE_LEN];
+ uint16_t length;
+ uint8_t specrev;
+ uint8_t checksum;
+ uint8_t oemid[MPCH_OEMID_LEN];
+ uint8_t prodid[MPCH_PRODID_LEN];
+ uint32_t oem_ptr;
+ uint16_t oem_sz;
+ uint16_t nr_entries;
+ uint32_t lapic_paddr;
+ uint16_t ext_length;
+ uint8_t ext_checksum;
+ uint8_t reserved;
+};
+
+#define MP_ENTRY_PROC (0)
+#define MP_ENTRY_BUS (1)
+#define MP_ENTRY_IOAPIC (2)
+#define MP_ENTRY_IOINT (3)
+#define MP_ENTRY_LINT (4)
+
+/*
+ * MP Processor Entry
+ */
+
+#define MPEP_FLAGS_EN (0x1)
+#define MPEP_FLAGS_BSP (0x2)
+
+#define MPEP_SIG_FAMILY (6)
+#define MPEP_SIG_MODEL (26)
+#define MPEP_SIG_STEPPING (5)
+#define MPEP_SIGNATURE ((MPEP_SIG_FAMILY << 8) | (MPEP_SIG_MODEL << 4) \
+ | (MPEP_SIG_STEPPING))
+
+#define MPEP_FEATURES (0xBFEBFBFF) // Value from Intel i7 CPUID
+
+struct mpe_proc {
+ uint8_t entry_type;
+ uint8_t lapic_id;
+ uint8_t lapic_version;
+ uint8_t proc_flags;
+ uint32_t proc_signature;
+ uint32_t feature_flags;
+ uint8_t reserved[8];
+};
+
+/*
+ * MP Bus Entry
+ */
+
+#define MPE_NUM_BUSES (2)
+#define MPE_BUSNAME_LEN (6)
+#define MPE_BUSID_ISA (0)
+#define MPE_BUSID_PCI (1)
+#define MPE_BUSNAME_ISA "ISA "
+#define MPE_BUSNAME_PCI "PCI "
+struct mpe_bus {
+ uint8_t entry_type;
+ uint8_t busid;
+ uint8_t busname[MPE_BUSNAME_LEN];
+};
+
+/*
+ * MP IO APIC Entry
+ */
+#define MPE_IOAPIC_ID (2)
+#define MPE_IOAPIC_FLAG_EN (1)
+struct mpe_ioapic {
+ uint8_t entry_type;
+ uint8_t ioapic_id;
+ uint8_t ioapic_version;
+ uint8_t ioapic_flags;
+ uint32_t ioapic_paddr;
+
+};
+
+/*
+ * MP IO Interrupt Assignment Entry
+ */
+#define MPEII_INTR_INT (0)
+#define MPEII_INTR_NMI (1)
+#define MPEII_INTR_SMI (2)
+#define MPEII_INTR_EXTINT (3)
+#define MPEII_PCI_IRQ_MASK (0x0c20U) /* IRQ 5,10,11 are PCI connected */
+#define MPEII_MAX_IRQ (16)
+#define MPEII_FLAGS_TRIGMODE_LEVEL (0x3)
+struct mpe_ioint {
+ uint8_t entry_type;
+ uint8_t intr_type;
+ uint16_t intr_flags;
+ uint8_t src_bus_id;
+ uint8_t src_bus_irq;
+ uint8_t dst_apic_id;
+ uint8_t dst_apic_intin;
+};
+
+/*
+ * MP Local Interrupt Assignment Entry
+ */
+struct mpe_lint {
+ uint8_t entry_type;
+};
+
+int vm_build_mptable(struct vmctx *ctxt, vm_paddr_t gpa, int len,
+ int ncpu, void *oemp, int oemsz);
+#endif /* _MPTABLE_h_ */
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
new file mode 100644
index 0000000..7f95fea
--- /dev/null
+++ b/lib/libvmmapi/vmmapi.c
@@ -0,0 +1,647 @@
+/*-
+ * Copyright (c) 2011 NetApp, Inc.
+ * 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 NETAPP, INC ``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 NETAPP, INC 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <machine/specialreg.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+
+#include "vmmapi.h"
+#include "mptable.h"
+
+#ifndef CR4_VMXE
+#define CR4_VMXE (1UL << 13)
+#endif
+
+#define BIOS_ROM_BASE (0xf0000)
+#define BIOS_ROM_SIZE (0x10000)
+
+struct vmctx {
+ int fd;
+ char *name;
+};
+
+#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
+#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
+
+static int
+vm_device_open(const char *name)
+{
+ int fd, len;
+ char *vmfile;
+
+ len = strlen("/dev/vmm/") + strlen(name) + 1;
+ vmfile = malloc(len);
+ assert(vmfile != NULL);
+ snprintf(vmfile, len, "/dev/vmm/%s", name);
+
+ /* Open the device file */
+ fd = open(vmfile, O_RDWR, 0);
+
+ free(vmfile);
+ return (fd);
+}
+
+int
+vm_create(const char *name)
+{
+
+ return (CREATE((char *)name));
+}
+
+struct vmctx *
+vm_open(const char *name)
+{
+ struct vmctx *vm;
+
+ vm = malloc(sizeof(struct vmctx) + strlen(name) + 1);
+ assert(vm != NULL);
+
+ vm->fd = -1;
+ vm->name = (char *)(vm + 1);
+ strcpy(vm->name, name);
+
+ if ((vm->fd = vm_device_open(vm->name)) < 0)
+ goto err;
+
+ return (vm);
+err:
+ vm_destroy(vm);
+ return (NULL);
+}
+
+void
+vm_destroy(struct vmctx *vm)
+{
+ assert(vm != NULL);
+
+ DESTROY(vm->name);
+ if (vm->fd >= 0)
+ close(vm->fd);
+ free(vm);
+}
+
+int
+vm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa,
+ vm_paddr_t *ret_hpa, size_t *ret_len)
+{
+ int error;
+ struct vm_memory_segment seg;
+
+ bzero(&seg, sizeof(seg));
+ seg.gpa = gpa;
+ error = ioctl(ctx->fd, VM_GET_MEMORY_SEG, &seg);
+ *ret_hpa = seg.hpa;
+ *ret_len = seg.len;
+ return (error);
+}
+
+int
+vm_setup_memory(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char **mapaddr)
+{
+ int error;
+ struct vm_memory_segment seg;
+
+ /*
+ * Create and optionally map 'len' bytes of memory at guest
+ * physical address 'gpa'
+ */
+ bzero(&seg, sizeof(seg));
+ seg.gpa = gpa;
+ seg.len = len;
+ error = ioctl(ctx->fd, VM_MAP_MEMORY, &seg);
+ if (error == 0 && mapaddr != NULL) {
+ *mapaddr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+ ctx->fd, gpa);
+ }
+ return (error);
+}
+
+char *
+vm_map_memory(struct vmctx *ctx, vm_paddr_t gpa, size_t len)
+{
+
+ /* Map 'len' bytes of memory at guest physical address 'gpa' */
+ return ((char *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+ ctx->fd, gpa));
+}
+
+int
+vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
+ uint64_t base, uint32_t limit, uint32_t access)
+{
+ int error;
+ struct vm_seg_desc vmsegdesc;
+
+ bzero(&vmsegdesc, sizeof(vmsegdesc));
+ vmsegdesc.cpuid = vcpu;
+ vmsegdesc.regnum = reg;
+ vmsegdesc.desc.base = base;
+ vmsegdesc.desc.limit = limit;
+ vmsegdesc.desc.access = access;
+
+ error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc);
+ return (error);
+}
+
+int
+vm_get_desc(struct vmctx *ctx, int vcpu, int reg,
+ uint64_t *base, uint32_t *limit, uint32_t *access)
+{
+ int error;
+ struct vm_seg_desc vmsegdesc;
+
+ bzero(&vmsegdesc, sizeof(vmsegdesc));
+ vmsegdesc.cpuid = vcpu;
+ vmsegdesc.regnum = reg;
+
+ error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc);
+ if (error == 0) {
+ *base = vmsegdesc.desc.base;
+ *limit = vmsegdesc.desc.limit;
+ *access = vmsegdesc.desc.access;
+ }
+ return (error);
+}
+
+int
+vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val)
+{
+ int error;
+ struct vm_register vmreg;
+
+ bzero(&vmreg, sizeof(vmreg));
+ vmreg.cpuid = vcpu;
+ vmreg.regnum = reg;
+ vmreg.regval = val;
+
+ error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg);
+ return (error);
+}
+
+int
+vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val)
+{
+ int error;
+ struct vm_register vmreg;
+
+ bzero(&vmreg, sizeof(vmreg));
+ vmreg.cpuid = vcpu;
+ vmreg.regnum = reg;
+
+ error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg);
+ *ret_val = vmreg.regval;
+ return (error);
+}
+
+int
+vm_get_pinning(struct vmctx *ctx, int vcpu, int *host_cpuid)
+{
+ int error;
+ struct vm_pin vmpin;
+
+ bzero(&vmpin, sizeof(vmpin));
+ vmpin.vm_cpuid = vcpu;
+
+ error = ioctl(ctx->fd, VM_GET_PINNING, &vmpin);
+ *host_cpuid = vmpin.host_cpuid;
+ return (error);
+}
+
+int
+vm_set_pinning(struct vmctx *ctx, int vcpu, int host_cpuid)
+{
+ int error;
+ struct vm_pin vmpin;
+
+ bzero(&vmpin, sizeof(vmpin));
+ vmpin.vm_cpuid = vcpu;
+ vmpin.host_cpuid = host_cpuid;
+
+ error = ioctl(ctx->fd, VM_SET_PINNING, &vmpin);
+ return (error);
+}
+
+int
+vm_run(struct vmctx *ctx, int vcpu, uint64_t rip, struct vm_exit *vmexit)
+{
+ int error;
+ struct vm_run vmrun;
+
+ bzero(&vmrun, sizeof(vmrun));
+ vmrun.cpuid = vcpu;
+ vmrun.rip = rip;
+
+ error = ioctl(ctx->fd, VM_RUN, &vmrun);
+ bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit));
+ return (error);
+}
+
+static int
+vm_inject_event_real(struct vmctx *ctx, int vcpu, enum vm_event_type type,
+ int vector, int error_code, int error_code_valid)
+{
+ struct vm_event ev;
+
+ bzero(&ev, sizeof(ev));
+ ev.cpuid = vcpu;
+ ev.type = type;
+ ev.vector = vector;
+ ev.error_code = error_code;
+ ev.error_code_valid = error_code_valid;
+
+ return (ioctl(ctx->fd, VM_INJECT_EVENT, &ev));
+}
+
+int
+vm_inject_event(struct vmctx *ctx, int vcpu, enum vm_event_type type,
+ int vector)
+{
+
+ return (vm_inject_event_real(ctx, vcpu, type, vector, 0, 0));
+}
+
+int
+vm_inject_event2(struct vmctx *ctx, int vcpu, enum vm_event_type type,
+ int vector, int error_code)
+{
+
+ return (vm_inject_event_real(ctx, vcpu, type, vector, error_code, 1));
+}
+
+int
+vm_build_tables(struct vmctx *ctxt, int ncpu, void *oemtbl, int oemtblsz)
+{
+
+ return (vm_build_mptable(ctxt, BIOS_ROM_BASE, BIOS_ROM_SIZE, ncpu,
+ oemtbl, oemtblsz));
+}
+
+int
+vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector)
+{
+ struct vm_lapic_irq vmirq;
+
+ bzero(&vmirq, sizeof(vmirq));
+ vmirq.cpuid = vcpu;
+ vmirq.vector = vector;
+
+ return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq));
+}
+
+int
+vm_inject_nmi(struct vmctx *ctx, int vcpu)
+{
+ struct vm_nmi vmnmi;
+
+ bzero(&vmnmi, sizeof(vmnmi));
+ vmnmi.cpuid = vcpu;
+
+ return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi));
+}
+
+int
+vm_capability_name2type(const char *capname)
+{
+ int i;
+
+ static struct {
+ const char *name;
+ int type;
+ } capstrmap[] = {
+ { "hlt_exit", VM_CAP_HALT_EXIT },
+ { "mtrap_exit", VM_CAP_MTRAP_EXIT },
+ { "pause_exit", VM_CAP_PAUSE_EXIT },
+ { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST },
+ { 0 }
+ };
+
+ for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) {
+ if (strcmp(capstrmap[i].name, capname) == 0)
+ return (capstrmap[i].type);
+ }
+
+ return (-1);
+}
+
+int
+vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap,
+ int *retval)
+{
+ int error;
+ struct vm_capability vmcap;
+
+ bzero(&vmcap, sizeof(vmcap));
+ vmcap.cpuid = vcpu;
+ vmcap.captype = cap;
+
+ error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap);
+ *retval = vmcap.capval;
+ return (error);
+}
+
+int
+vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val)
+{
+ struct vm_capability vmcap;
+
+ bzero(&vmcap, sizeof(vmcap));
+ vmcap.cpuid = vcpu;
+ vmcap.captype = cap;
+ vmcap.capval = val;
+
+ return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap));
+}
+
+int
+vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
+{
+ struct vm_pptdev pptdev;
+
+ bzero(&pptdev, sizeof(pptdev));
+ pptdev.bus = bus;
+ pptdev.slot = slot;
+ pptdev.func = func;
+
+ return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev));
+}
+
+int
+vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
+{
+ struct vm_pptdev pptdev;
+
+ bzero(&pptdev, sizeof(pptdev));
+ pptdev.bus = bus;
+ pptdev.slot = slot;
+ pptdev.func = func;
+
+ return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev));
+}
+
+int
+vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
+{
+ struct vm_pptdev_mmio pptmmio;
+
+ bzero(&pptmmio, sizeof(pptmmio));
+ pptmmio.bus = bus;
+ pptmmio.slot = slot;
+ pptmmio.func = func;
+ pptmmio.gpa = gpa;
+ pptmmio.len = len;
+ pptmmio.hpa = hpa;
+
+ return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio));
+}
+
+int
+vm_setup_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
+ int destcpu, int vector, int numvec)
+{
+ struct vm_pptdev_msi pptmsi;
+
+ bzero(&pptmsi, sizeof(pptmsi));
+ pptmsi.vcpu = vcpu;
+ pptmsi.bus = bus;
+ pptmsi.slot = slot;
+ pptmsi.func = func;
+ pptmsi.destcpu = destcpu;
+ pptmsi.vector = vector;
+ pptmsi.numvec = numvec;
+
+ return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi));
+}
+
+uint64_t *
+vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
+ int *ret_entries)
+{
+ int error;
+
+ static struct vm_stats vmstats;
+
+ vmstats.cpuid = vcpu;
+
+ error = ioctl(ctx->fd, VM_STATS, &vmstats);
+ if (error == 0) {
+ if (ret_entries)
+ *ret_entries = vmstats.num_entries;
+ if (ret_tv)
+ *ret_tv = vmstats.tv;
+ return (vmstats.statbuf);
+ } else
+ return (NULL);
+}
+
+const char *
+vm_get_stat_desc(struct vmctx *ctx, int index)
+{
+ int error;
+
+ static struct vm_stat_desc statdesc;
+
+ statdesc.index = index;
+ if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0)
+ return (statdesc.desc);
+ else
+ return (NULL);
+}
+
+/*
+ * From Intel Vol 3a:
+ * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT
+ */
+int
+vcpu_reset(struct vmctx *vmctx, int vcpu)
+{
+ int error;
+ uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx;
+ uint32_t desc_access, desc_limit;
+ uint16_t sel;
+
+ zero = 0;
+
+ rflags = 0x2;
+ error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
+ if (error)
+ goto done;
+
+ rip = 0xfff0;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
+ goto done;
+
+ cr0 = CR0_NE;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0)
+ goto done;
+
+ cr4 = CR4_VMXE;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
+ goto done;
+
+ /*
+ * CS: present, r/w, accessed, 16-bit, byte granularity, usable
+ */
+ desc_base = 0xffff0000;
+ desc_limit = 0xffff;
+ desc_access = 0x0093;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ sel = 0xf000;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0)
+ goto done;
+
+ /*
+ * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity
+ */
+ desc_base = 0;
+ desc_limit = 0xffff;
+ desc_access = 0x0093;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ sel = 0;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0)
+ goto done;
+
+ /* General purpose registers */
+ rdx = 0xf00;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0)
+ goto done;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0)
+ goto done;
+
+ /* GDTR, IDTR */
+ desc_base = 0;
+ desc_limit = 0xffff;
+ desc_access = 0;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
+ desc_base, desc_limit, desc_access);
+ if (error != 0)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR,
+ desc_base, desc_limit, desc_access);
+ if (error != 0)
+ goto done;
+
+ /* TR */
+ desc_base = 0;
+ desc_limit = 0xffff;
+ desc_access = 0x0000008b;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
+ if (error)
+ goto done;
+
+ sel = 0;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0)
+ goto done;
+
+ /* LDTR */
+ desc_base = 0;
+ desc_limit = 0xffff;
+ desc_access = 0x00000082;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base,
+ desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ sel = 0;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
+ goto done;
+
+ /* XXX cr2, debug registers */
+
+ error = 0;
+done:
+ return (error);
+}
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
new file mode 100644
index 0000000..38533a8
--- /dev/null
+++ b/lib/libvmmapi/vmmapi.h
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2011 NetApp, Inc.
+ * 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 NETAPP, INC ``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 NETAPP, INC 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$
+ */
+
+#ifndef _VMMAPI_H_
+#define _VMMAPI_H_
+
+struct vmctx;
+
+int vm_create(const char *name);
+struct vmctx *vm_open(const char *name);
+void vm_destroy(struct vmctx *ctx);
+int vm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa,
+ vm_paddr_t *ret_hpa, size_t *ret_len);
+/*
+ * Create a memory segment of 'len' bytes in the guest physical address space
+ * at offset 'gpa'.
+ *
+ * If 'mapaddr' is not NULL then this region is mmap'ed into the address
+ * space of the calling process. If there is an mmap error then *mapaddr
+ * will be set to MAP_FAILED.
+ */
+
+int vm_setup_memory(struct vmctx *ctx, vm_paddr_t gpa, size_t len,
+ char **mapaddr);
+char * vm_map_memory(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
+int vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
+ uint64_t base, uint32_t limit, uint32_t access);
+int vm_get_desc(struct vmctx *ctx, int vcpu, int reg,
+ uint64_t *base, uint32_t *limit, uint32_t *access);
+int vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val);
+int vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval);
+int vm_get_pinning(struct vmctx *ctx, int vcpu, int *host_cpuid);
+int vm_set_pinning(struct vmctx *ctx, int vcpu, int host_cpuid);
+int vm_run(struct vmctx *ctx, int vcpu, uint64_t rip,
+ struct vm_exit *ret_vmexit);
+int vm_build_tables(struct vmctx *ctxt, int ncpus, void *oemtbl,
+ int oemtblsz);
+int vm_inject_event(struct vmctx *ctx, int vcpu, enum vm_event_type type,
+ int vector);
+int vm_inject_event2(struct vmctx *ctx, int vcpu, enum vm_event_type type,
+ int vector, int error_code);
+int vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector);
+int vm_inject_nmi(struct vmctx *ctx, int vcpu);
+int vm_capability_name2type(const char *capname);
+int vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap,
+ int *retval);
+int vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap,
+ int val);
+int vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func);
+int vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func);
+int vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
+int vm_setup_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
+ int dest, int vector, int numvec);
+
+/*
+ * Return a pointer to the statistics buffer. Note that this is not MT-safe.
+ */
+uint64_t *vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
+ int *ret_entries);
+const char *vm_get_stat_desc(struct vmctx *ctx, int index);
+
+/* Reset vcpu register state */
+int vcpu_reset(struct vmctx *ctx, int vcpu);
+
+/*
+ * FreeBSD specific APIs
+ */
+int vm_setup_freebsd_registers(struct vmctx *ctx, int vcpu,
+ uint64_t rip, uint64_t cr3, uint64_t gdtbase,
+ uint64_t rsp);
+void vm_setup_freebsd_gdt(uint64_t *gdtr);
+#endif /* _VMMAPI_H_ */
diff --git a/lib/libvmmapi/vmmapi_freebsd.c b/lib/libvmmapi/vmmapi_freebsd.c
new file mode 100644
index 0000000..c4ad989
--- /dev/null
+++ b/lib/libvmmapi/vmmapi_freebsd.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2011 NetApp, Inc.
+ * 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 NETAPP, INC ``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 NETAPP, INC 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <machine/specialreg.h>
+#include <machine/segments.h>
+#include <machine/vmm.h>
+
+#include "vmmapi.h"
+
+#ifndef CR4_VMXE
+#define CR4_VMXE (1UL << 13)
+#endif
+
+#define DESC_UNUSABLE 0x00010000
+
+#define GUEST_NULL_SEL 0
+#define GUEST_CODE_SEL 1
+#define GUEST_DATA_SEL 2
+#define GUEST_GDTR_LIMIT (3 * 8 - 1)
+
+void
+vm_setup_freebsd_gdt(uint64_t *gdtr)
+{
+ gdtr[GUEST_NULL_SEL] = 0;
+ gdtr[GUEST_CODE_SEL] = 0x0020980000000000;
+ gdtr[GUEST_DATA_SEL] = 0x0000900000000000;
+}
+
+/*
+ * Setup the 'vcpu' register set such that it will begin execution at
+ * 'rip' in long mode.
+ */
+int
+vm_setup_freebsd_registers(struct vmctx *vmctx, int vcpu,
+ uint64_t rip, uint64_t cr3, uint64_t gdtbase,
+ uint64_t rsp)
+{
+ int error;
+ uint64_t cr0, cr4, efer, rflags, desc_base;
+ uint32_t desc_access, desc_limit;
+ uint16_t gsel;
+
+ cr0 = CR0_PE | CR0_PG | CR0_NE;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
+ goto done;
+
+ cr4 = CR4_PAE | CR4_VMXE;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
+ goto done;
+
+ efer = EFER_LME | EFER_LMA;
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_EFER, efer)))
+ goto done;
+
+ rflags = 0x2;
+ error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
+ if (error)
+ goto done;
+
+ desc_base = 0;
+ desc_limit = 0;
+ desc_access = 0x0000209B;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ desc_access = 0x00000093;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
+ desc_base, desc_limit, desc_access);
+ if (error)
+ goto done;
+
+ /*
+ * XXX TR is pointing to null selector even though we set the
+ * TSS segment to be usable with a base address and limit of 0.
+ */
+ desc_access = 0x0000008b;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
+ if (error)
+ goto done;
+
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, 0, 0,
+ DESC_UNUSABLE);
+ if (error)
+ goto done;
+
+ gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, gsel)) != 0)
+ goto done;
+
+ gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, gsel)) != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, gsel)) != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, gsel)) != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, gsel)) != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, gsel)) != 0)
+ goto done;
+
+ /* XXX TR is pointing to the null selector */
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, 0)) != 0)
+ goto done;
+
+ /* LDTR is pointing to the null selector */
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
+ goto done;
+
+ /* entry point */
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
+ goto done;
+
+ /* page table base */
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, cr3)) != 0)
+ goto done;
+
+ desc_base = gdtbase;
+ desc_limit = GUEST_GDTR_LIMIT;
+ error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
+ desc_base, desc_limit, 0);
+ if (error != 0)
+ goto done;
+
+ if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, rsp)) != 0)
+ goto done;
+
+ error = 0;
+done:
+ return (error);
+}
OpenPOWER on IntegriCloud