[Midnightbsd-cvs] src [9895] trunk/sys/x86: sync with freebsd 10-stable

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu May 24 18:26:03 EDT 2018


Revision: 9895
          http://svnweb.midnightbsd.org/src/?rev=9895
Author:   laffer1
Date:     2018-05-24 18:26:03 -0400 (Thu, 24 May 2018)
Log Message:
-----------
sync with freebsd 10-stable

Modified Paths:
--------------
    trunk/sys/x86/acpica/OsdEnvironment.c
    trunk/sys/x86/acpica/acpi_apm.c
    trunk/sys/x86/acpica/madt.c
    trunk/sys/x86/acpica/srat.c
    trunk/sys/x86/bios/smbios.c
    trunk/sys/x86/bios/vpd.c
    trunk/sys/x86/cpufreq/est.c
    trunk/sys/x86/cpufreq/hwpstate.c
    trunk/sys/x86/cpufreq/p4tcc.c
    trunk/sys/x86/cpufreq/powernow.c
    trunk/sys/x86/cpufreq/smist.c
    trunk/sys/x86/include/_align.h
    trunk/sys/x86/include/_inttypes.h
    trunk/sys/x86/include/apicreg.h
    trunk/sys/x86/include/apm_bios.h
    trunk/sys/x86/include/bus.h
    trunk/sys/x86/include/mca.h
    trunk/sys/x86/include/mptable.h
    trunk/sys/x86/include/pci_cfgreg.h
    trunk/sys/x86/include/vdso.h
    trunk/sys/x86/isa/atpic.c
    trunk/sys/x86/isa/atrtc.c
    trunk/sys/x86/isa/clock.c
    trunk/sys/x86/isa/elcr.c
    trunk/sys/x86/isa/icu.h
    trunk/sys/x86/isa/isa.c
    trunk/sys/x86/isa/isa.h
    trunk/sys/x86/isa/isa_dma.c
    trunk/sys/x86/isa/nmi.c
    trunk/sys/x86/isa/orm.c
    trunk/sys/x86/pci/pci_bus.c
    trunk/sys/x86/pci/qpi.c
    trunk/sys/x86/x86/busdma_machdep.c
    trunk/sys/x86/x86/dump_machdep.c
    trunk/sys/x86/x86/intr_machdep.c
    trunk/sys/x86/x86/io_apic.c
    trunk/sys/x86/x86/local_apic.c
    trunk/sys/x86/x86/mca.c
    trunk/sys/x86/x86/mptable.c
    trunk/sys/x86/x86/mptable_pci.c
    trunk/sys/x86/x86/msi.c
    trunk/sys/x86/x86/nexus.c
    trunk/sys/x86/x86/tsc.c

Added Paths:
-----------
    trunk/sys/x86/include/_limits.h
    trunk/sys/x86/include/_stdint.h
    trunk/sys/x86/include/_types.h
    trunk/sys/x86/include/acpica_machdep.h
    trunk/sys/x86/include/busdma_impl.h
    trunk/sys/x86/include/elf.h
    trunk/sys/x86/include/endian.h
    trunk/sys/x86/include/fdt.h
    trunk/sys/x86/include/float.h
    trunk/sys/x86/include/fpu.h
    trunk/sys/x86/include/frame.h
    trunk/sys/x86/include/legacyvar.h
    trunk/sys/x86/include/metadata.h
    trunk/sys/x86/include/ofw_machdep.h
    trunk/sys/x86/include/psl.h
    trunk/sys/x86/include/ptrace.h
    trunk/sys/x86/include/reg.h
    trunk/sys/x86/include/segments.h
    trunk/sys/x86/include/setjmp.h
    trunk/sys/x86/include/sigframe.h
    trunk/sys/x86/include/signal.h
    trunk/sys/x86/include/specialreg.h
    trunk/sys/x86/include/stdarg.h
    trunk/sys/x86/include/sysarch.h
    trunk/sys/x86/include/trap.h
    trunk/sys/x86/include/ucontext.h
    trunk/sys/x86/include/vmware.h
    trunk/sys/x86/iommu/
    trunk/sys/x86/iommu/busdma_dmar.c
    trunk/sys/x86/iommu/busdma_dmar.h
    trunk/sys/x86/iommu/intel_ctx.c
    trunk/sys/x86/iommu/intel_dmar.h
    trunk/sys/x86/iommu/intel_drv.c
    trunk/sys/x86/iommu/intel_fault.c
    trunk/sys/x86/iommu/intel_gas.c
    trunk/sys/x86/iommu/intel_idpgtbl.c
    trunk/sys/x86/iommu/intel_qi.c
    trunk/sys/x86/iommu/intel_quirks.c
    trunk/sys/x86/iommu/intel_reg.h
    trunk/sys/x86/iommu/intel_utils.c
    trunk/sys/x86/x86/bus_machdep.c
    trunk/sys/x86/x86/busdma_bounce.c
    trunk/sys/x86/x86/fdt_machdep.c
    trunk/sys/x86/x86/identcpu.c
    trunk/sys/x86/x86/legacy.c
    trunk/sys/x86/xen/
    trunk/sys/x86/xen/hvm.c
    trunk/sys/x86/xen/xen_intr.c

Modified: trunk/sys/x86/acpica/OsdEnvironment.c
===================================================================
--- trunk/sys/x86/acpica/OsdEnvironment.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/acpica/OsdEnvironment.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000,2001 Michael Smith
  * Copyright (c) 2000 BSDi
@@ -26,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/acpica/OsdEnvironment.c 281687 2015-04-18 08:01:12Z jkim $");
 
 #include <sys/types.h>
 #include <sys/bus.h>
@@ -68,7 +69,7 @@
 static u_long
 acpi_get_root_from_memory(void)
 {
-	ACPI_SIZE acpi_root;
+	ACPI_PHYSICAL_ADDRESS acpi_root;
 
 	if (ACPI_SUCCESS(AcpiFindRootPointer(&acpi_root)))
 		return (acpi_root);

Modified: trunk/sys/x86/acpica/acpi_apm.c
===================================================================
--- trunk/sys/x86/acpica/acpi_apm.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/acpica/acpi_apm.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2001 Mitsuru IWASAKI
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/acpica/acpi_apm.c 228283 2011-12-05 16:08:18Z ed $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -51,12 +52,10 @@
 #define	APM_UNKNOWN	0xff
 
 static int apm_active;
-static struct clonedevs *apm_clones;
 
 static MALLOC_DEFINE(M_APMDEV, "apmdev", "APM device emulation");
 
 static d_open_t		apmopen;
-static d_close_t	apmclose;
 static d_write_t	apmwrite;
 static d_ioctl_t	apmioctl;
 static d_poll_t		apmpoll;
@@ -71,9 +70,7 @@
 
 static struct cdevsw apm_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_TRACKCLOSE | D_NEEDMINOR,
 	.d_open =	apmopen,
-	.d_close =	apmclose,
 	.d_write =	apmwrite,
 	.d_ioctl =	apmioctl,
 	.d_poll =	apmpoll,
@@ -202,39 +199,6 @@
 	return (0);
 }
 
-/* Create single-use devices for /dev/apm and /dev/apmctl. */
-static void
-apm_clone(void *arg, struct ucred *cred, char *name, int namelen,
-    struct cdev **dev)
-{
-	int ctl_dev, unit;
-
-	if (*dev != NULL)
-		return;
-	if (strcmp(name, "apmctl") == 0)
-		ctl_dev = TRUE;
-	else if (strcmp(name, "apm") == 0)
-		ctl_dev = FALSE;
-	else
-		return;
-
-	/* Always create a new device and unit number. */
-	unit = -1;
-	if (clone_create(&apm_clones, &apm_cdevsw, &unit, dev, 0)) {
-		if (ctl_dev) {
-			*dev = make_dev(&apm_cdevsw, unit,
-			    UID_ROOT, GID_OPERATOR, 0660, "apmctl%d", unit);
-		} else {
-			*dev = make_dev(&apm_cdevsw, unit,
-			    UID_ROOT, GID_OPERATOR, 0664, "apm%d", unit);
-		}
-		if (*dev != NULL) {
-			dev_ref(*dev);
-			(*dev)->si_flags |= SI_CHEAPCLONE;
-		}
-	}
-}
-
 /* Create a struct for tracking per-device suspend notification. */
 static struct apm_clone_data *
 apm_create_clone(struct cdev *dev, struct acpi_softc *acpi_sc)
@@ -263,30 +227,13 @@
 	return (clone);
 }
 
-static int
-apmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
+static void
+apmdtor(void *data)
 {
-	struct	acpi_softc *acpi_sc;
-	struct 	apm_clone_data *clone;
-
-	acpi_sc = devclass_get_softc(devclass_find("acpi"), 0);
-	clone = apm_create_clone(dev, acpi_sc);
-	dev->si_drv1 = clone;
-
-	/* If the device is opened for write, record that. */
-	if ((flag & FWRITE) != 0)
-		clone->flags |= ACPI_EVF_WRITE;
-
-	return (0);
-}
-
-static int
-apmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
-{
 	struct	apm_clone_data *clone;
 	struct	acpi_softc *acpi_sc;
 
-	clone = dev->si_drv1;
+	clone = data;
 	acpi_sc = clone->acpi_sc;
 
 	/* We are about to lose a reference so check if suspend should occur */
@@ -301,7 +248,22 @@
 	knlist_destroy(&clone->sel_read.si_note);
 	ACPI_UNLOCK(acpi);
 	free(clone, M_APMDEV);
-	destroy_dev_sched(dev);
+}
+
+static int
+apmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
+	struct	acpi_softc *acpi_sc;
+	struct 	apm_clone_data *clone;
+
+	acpi_sc = devclass_get_softc(devclass_find("acpi"), 0);
+	clone = apm_create_clone(dev, acpi_sc);
+	devfs_set_cdevpriv(clone, apmdtor);
+
+	/* If the device is opened for write, record that. */
+	if ((flag & FWRITE) != 0)
+		clone->flags |= ACPI_EVF_WRITE;
+
 	return (0);
 }
 
@@ -316,7 +278,7 @@
 	apm_info_old_t aiop;
 
 	error = 0;
-	clone = dev->si_drv1;
+	devfs_get_cdevpriv((void **)&clone);
 	acpi_sc = clone->acpi_sc;
 
 	switch (cmd) {
@@ -430,8 +392,8 @@
 	int revents;
 
 	revents = 0;
+	devfs_get_cdevpriv((void **)&clone);
 	ACPI_LOCK(acpi);
-	clone = dev->si_drv1;
 	if (clone->acpi_sc->acpi_next_sstate)
 		revents |= events & (POLLIN | POLLRDNORM);
 	else
@@ -445,8 +407,8 @@
 {
 	struct	apm_clone_data *clone;
 
+	devfs_get_cdevpriv((void **)&clone);
 	ACPI_LOCK(acpi);
-	clone = dev->si_drv1;
 	kn->kn_hook = clone;
 	kn->kn_fop = &apm_readfiltops;
 	knlist_add(&clone->sel_read.si_note, kn, 0);
@@ -485,6 +447,7 @@
 	/* Create a clone for /dev/acpi also. */
 	STAILQ_INIT(&sc->apm_cdevs);
 	sc->acpi_clone = apm_create_clone(sc->acpi_dev_t, sc);
-	clone_setup(&apm_clones);
-	EVENTHANDLER_REGISTER(dev_clone, apm_clone, 0, 1000);
+
+	make_dev(&apm_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0660, "apmctl");
+	make_dev(&apm_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0664, "apm");
 }

Modified: trunk/sys/x86/acpica/madt.c
===================================================================
--- trunk/sys/x86/acpica/madt.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/acpica/madt.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -28,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/acpica/madt.c 288461 2015-10-01 20:54:19Z jhb $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -56,8 +54,8 @@
 } *ioapics;
 
 static struct lapic_info {
-	u_int la_enabled:1;
-	u_int la_acpi_id:8;
+	u_int la_enabled;
+	u_int la_acpi_id;
 } lapics[MAX_APIC_ID + 1];
 
 static int madt_found_sci_override;
@@ -223,35 +221,49 @@
 }
 
 static void
+madt_add_cpu(u_int acpi_id, u_int apic_id, u_int flags)
+{
+	struct lapic_info *la;
+
+	/*
+	 * The MADT does not include a BSP flag, so we have to let the
+	 * MP code figure out which CPU is the BSP on its own.
+	 */
+	if (bootverbose)
+		printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
+		    apic_id, acpi_id, flags & ACPI_MADT_ENABLED ?
+		    "enabled" : "disabled");
+	if (!(flags & ACPI_MADT_ENABLED))
+		return;
+	if (apic_id > MAX_APIC_ID) {
+		printf("MADT: Ignoring local APIC ID %u (too high)\n",
+		    apic_id);
+		return;
+	}
+
+	la = &lapics[apic_id];
+	KASSERT(la->la_enabled == 0, ("Duplicate local APIC ID %u", apic_id));
+	la->la_enabled = 1;
+	la->la_acpi_id = acpi_id;
+	lapic_create(apic_id, 0);
+}
+
+static void
 madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
 {
 	ACPI_MADT_LOCAL_APIC *proc;
-	struct lapic_info *la;
+	ACPI_MADT_LOCAL_X2APIC *x2apic;
 
 	switch (entry->Type) {
 	case ACPI_MADT_TYPE_LOCAL_APIC:
-		/*
-		 * The MADT does not include a BSP flag, so we have to
-		 * let the MP code figure out which CPU is the BSP on
-		 * its own.
-		 */
 		proc = (ACPI_MADT_LOCAL_APIC *)entry;
-		if (bootverbose)
-			printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
-			    proc->Id, proc->ProcessorId,
-			    (proc->LapicFlags & ACPI_MADT_ENABLED) ?
-			    "enabled" : "disabled");
-		if (!(proc->LapicFlags & ACPI_MADT_ENABLED))
-			break;
-		if (proc->Id > MAX_APIC_ID)
-			panic("%s: CPU ID %u too high", __func__, proc->Id);
-		la = &lapics[proc->Id];
-		KASSERT(la->la_enabled == 0,
-		    ("Duplicate local APIC ID %u", proc->Id));
-		la->la_enabled = 1;
-		la->la_acpi_id = proc->ProcessorId;
-		lapic_create(proc->Id, 0);
+		madt_add_cpu(proc->ProcessorId, proc->Id, proc->LapicFlags);
 		break;
+	case ACPI_MADT_TYPE_LOCAL_X2APIC:
+		x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
+		madt_add_cpu(x2apic->Uid, x2apic->LocalApicId,
+		    x2apic->LapicFlags);
+		break;
 	}
 }
 
@@ -301,6 +313,9 @@
 {
 
 	switch (IntiFlags & ACPI_MADT_POLARITY_MASK) {
+	default:
+		printf("WARNING: Bogus Interrupt Polarity. Assume CONFORMS\n");
+		/* FALLTHROUGH*/
 	case ACPI_MADT_POLARITY_CONFORMS:
 		if (Source == AcpiGbl_FADT.SciInterrupt)
 			return (INTR_POLARITY_LOW);
@@ -310,8 +325,6 @@
 		return (INTR_POLARITY_HIGH);
 	case ACPI_MADT_POLARITY_ACTIVE_LOW:
 		return (INTR_POLARITY_LOW);
-	default:
-		panic("Bogus Interrupt Polarity");
 	}
 }
 
@@ -320,6 +333,9 @@
 {
 
 	switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) {
+	default:
+		printf("WARNING: Bogus Interrupt Trigger Mode. Assume CONFORMS.\n");
+		/*FALLTHROUGH*/
 	case ACPI_MADT_TRIGGER_CONFORMS:
 		if (Source == AcpiGbl_FADT.SciInterrupt)
 			return (INTR_TRIGGER_LEVEL);
@@ -329,8 +345,6 @@
 		return (INTR_TRIGGER_EDGE);
 	case ACPI_MADT_TRIGGER_LEVEL:
 		return (INTR_TRIGGER_LEVEL);
-	default:
-		panic("Bogus Interrupt Trigger Mode");
 	}
 }
 
@@ -504,31 +518,46 @@
  * Parse an entry for an NMI routed to a local APIC LVT pin.
  */
 static void
-madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
+madt_handle_local_nmi(u_int acpi_id, UINT8 Lint, UINT16 IntiFlags)
 {
 	u_int apic_id, pin;
 
-	if (nmi->ProcessorId == 0xff)
+	if (acpi_id == 0xffffffff)
 		apic_id = APIC_ID_ALL;
-	else if (madt_find_cpu(nmi->ProcessorId, &apic_id) != 0) {
+	else if (madt_find_cpu(acpi_id, &apic_id) != 0) {
 		if (bootverbose)
 			printf("MADT: Ignoring local NMI routed to "
-			    "ACPI CPU %u\n", nmi->ProcessorId);
+			    "ACPI CPU %u\n", acpi_id);
 		return;
 	}
-	if (nmi->Lint == 0)
-		pin = LVT_LINT0;
+	if (Lint == 0)
+		pin = APIC_LVT_LINT0;
 	else
-		pin = LVT_LINT1;
+		pin = APIC_LVT_LINT1;
 	lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
-	if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
+	if (!(IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
 		lapic_set_lvt_triggermode(apic_id, pin,
-		    interrupt_trigger(nmi->IntiFlags, 0));
-	if (!(nmi->IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
+		    interrupt_trigger(IntiFlags, 0));
+	if (!(IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
 		lapic_set_lvt_polarity(apic_id, pin,
-		    interrupt_polarity(nmi->IntiFlags, 0));
+		    interrupt_polarity(IntiFlags, 0));
 }
 
+static void
+madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
+{
+
+	madt_handle_local_nmi(nmi->ProcessorId == 0xff ? 0xffffffff :
+	    nmi->ProcessorId, nmi->Lint, nmi->IntiFlags);
+}
+
+static void
+madt_parse_local_x2apic_nmi(ACPI_MADT_LOCAL_X2APIC_NMI *nmi)
+{
+
+	madt_handle_local_nmi(nmi->Uid, nmi->Lint, nmi->IntiFlags);
+}
+
 /*
  * Parse interrupt entries.
  */
@@ -547,6 +576,10 @@
 	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
 		madt_parse_local_nmi((ACPI_MADT_LOCAL_APIC_NMI *)entry);
 		break;
+	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
+		madt_parse_local_x2apic_nmi(
+		    (ACPI_MADT_LOCAL_X2APIC_NMI *)entry);
+		break;
 	}
 }
 
@@ -575,4 +608,4 @@
 			    la->la_acpi_id);
 	}
 }
-SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL);
+SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_MIDDLE, madt_set_ids, NULL);

Modified: trunk/sys/x86/acpica/srat.c
===================================================================
--- trunk/sys/x86/acpica/srat.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/acpica/srat.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2010 Advanced Computing Technologies LLC
+ * Copyright (c) 2010 Hudson River Trading LLC
  * Written by: John H. Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
  *
@@ -26,17 +27,19 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/acpica/srat.c 299485 2016-05-11 22:06:28Z vangyzen $");
 
-#include "opt_vm.h"
-
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/smp.h>
+#include <sys/vmmeter.h>
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_param.h>
+#include <vm/vm_page.h>
 #include <vm/vm_phys.h>
 
 #include <contrib/dev/acpica/include/acpi.h>
@@ -47,7 +50,7 @@
 
 #include <dev/acpica/acpivar.h>
 
-#if VM_NDOMAIN > 1
+#if MAXMEMDOM > 1
 struct cpu_info {
 	int enabled:1;
 	int has_memory:1;
@@ -60,6 +63,8 @@
 static ACPI_TABLE_SRAT *srat;
 static vm_paddr_t srat_physaddr;
 
+static int vm_domains[VM_PHYSSEG_MAX];
+
 static void	srat_walk_table(acpi_subtable_handler *handler, void *arg);
 
 /*
@@ -104,8 +109,12 @@
 			    "enabled" : "disabled");
 		if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
 			break;
-		KASSERT(!cpus[cpu->ApicId].enabled,
-		    ("Duplicate local APIC ID %u", cpu->ApicId));
+		if (cpus[cpu->ApicId].enabled) {
+			printf("SRAT: Duplicate local APIC ID %u\n",
+			    cpu->ApicId);
+			*(int *)arg = ENXIO;
+			break;
+		}
 		cpus[cpu->ApicId].domain = domain;
 		cpus[cpu->ApicId].enabled = 1;
 		break;
@@ -245,27 +254,27 @@
 static int
 renumber_domains(void)
 {
-	int domains[VM_PHYSSEG_MAX];
-	int ndomain, i, j, slot;
+	int i, j, slot;
 
 	/* Enumerate all the domains. */
-	ndomain = 0;
+	vm_ndomains = 0;
 	for (i = 0; i < num_mem; i++) {
 		/* See if this domain is already known. */
-		for (j = 0; j < ndomain; j++) {
-			if (domains[j] >= mem_info[i].domain)
+		for (j = 0; j < vm_ndomains; j++) {
+			if (vm_domains[j] >= mem_info[i].domain)
 				break;
 		}
-		if (j < ndomain && domains[j] == mem_info[i].domain)
+		if (j < vm_ndomains && vm_domains[j] == mem_info[i].domain)
 			continue;
 
 		/* Insert the new domain at slot 'j'. */
 		slot = j;
-		for (j = ndomain; j > slot; j--)
-			domains[j] = domains[j - 1];
-		domains[slot] = mem_info[i].domain;
-		ndomain++;
-		if (ndomain > VM_NDOMAIN) {
+		for (j = vm_ndomains; j > slot; j--)
+			vm_domains[j] = vm_domains[j - 1];
+		vm_domains[slot] = mem_info[i].domain;
+		vm_ndomains++;
+		if (vm_ndomains > MAXMEMDOM) {
+			vm_ndomains = 1;
 			printf("SRAT: Too many memory domains\n");
 			return (EFBIG);
 		}
@@ -272,22 +281,25 @@
 	}
 
 	/* Renumber each domain to its index in the sorted 'domains' list. */
-	for (i = 0; i < ndomain; i++) {
+	for (i = 0; i < vm_ndomains; i++) {
 		/*
 		 * If the domain is already the right value, no need
 		 * to renumber.
 		 */
-		if (domains[i] == i)
+		if (vm_domains[i] == i)
 			continue;
 
 		/* Walk the cpu[] and mem_info[] arrays to renumber. */
 		for (j = 0; j < num_mem; j++)
-			if (mem_info[j].domain == domains[i])
+			if (mem_info[j].domain == vm_domains[i])
 				mem_info[j].domain = i;
 		for (j = 0; j <= MAX_APIC_ID; j++)
-			if (cpus[j].enabled && cpus[j].domain == domains[i])
+			if (cpus[j].enabled && cpus[j].domain == vm_domains[i])
 				cpus[j].domain = i;
 	}
+	KASSERT(vm_ndomains > 0,
+	    ("renumber_domains: invalid final vm_ndomains setup"));
+
 	return (0);
 }
 
@@ -362,4 +374,23 @@
 	}
 }
 SYSINIT(srat_set_cpus, SI_SUB_CPU, SI_ORDER_ANY, srat_set_cpus, NULL);
-#endif /* VM_NDOMAIN > 1 */
+
+/*
+ * Map a _PXM value to a VM domain ID.
+ *
+ * Returns the domain ID, or -1 if no domain ID was found.
+ */
+int
+acpi_map_pxm_to_vm_domainid(int pxm)
+{
+	int i;
+
+	for (i = 0; i < vm_ndomains; i++) {
+		if (vm_domains[i] == pxm)
+			return (i);
+	}
+
+	return (-1);
+}
+
+#endif /* MAXMEMDOM > 1 */

Modified: trunk/sys/x86/bios/smbios.c
===================================================================
--- trunk/sys/x86/bios/smbios.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/bios/smbios.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 Matthew N. Dodd <winter at jurai.net>
  * All rights reserved.
@@ -25,11 +26,12 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/bios/smbios.c 241073 2012-09-30 15:42:20Z kevlo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
 #include <sys/socket.h>
 
 #include <sys/module.h>
@@ -204,6 +206,7 @@
 		for (i = 0; i < count; i++) {
 			device_delete_child(device_get_parent(devs[i]), devs[i]);
 		}
+		free(devs, M_TEMP);
 		break;
 	default:
 		break;

Modified: trunk/sys/x86/bios/vpd.c
===================================================================
--- trunk/sys/x86/bios/vpd.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/bios/vpd.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 Matthew N. Dodd <winter at jurai.net>
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/bios/vpd.c 227309 2011-11-07 15:43:11Z ed $");
 
 /*
  * VPD decoder for IBM systems (Thinkpads)

Modified: trunk/sys/x86/cpufreq/est.c
===================================================================
--- trunk/sys/x86/cpufreq/est.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/cpufreq/est.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2004 Colin Percival
  * Copyright (c) 2005 Nate Lawson
@@ -26,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/cpufreq/est.c 260473 2014-01-09 10:44:27Z mav $");
 
 #include <sys/param.h>
 #include <sys/bus.h>

Modified: trunk/sys/x86/cpufreq/hwpstate.c
===================================================================
--- trunk/sys/x86/cpufreq/hwpstate.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/cpufreq/hwpstate.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 Nate Lawson
  * Copyright (c) 2004 Colin Percival
@@ -44,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/cpufreq/hwpstate.c 326638 2017-12-06 21:40:24Z jkim $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -83,11 +84,15 @@
 #define	AMD_10H_11H_CUR_DID(msr)		(((msr) >> 6) & 0x07)
 #define	AMD_10H_11H_CUR_FID(msr)		((msr) & 0x3F)
 
+#define	AMD_17H_CUR_VID(msr)			(((msr) >> 14) & 0xFF)
+#define	AMD_17H_CUR_DID(msr)			(((msr) >> 8) & 0x3F)
+#define	AMD_17H_CUR_FID(msr)			((msr) & 0xFF)
+
 #define	HWPSTATE_DEBUG(dev, msg...)			\
-	do{						\
-		if(hwpstate_verbose)			\
+	do {						\
+		if (hwpstate_verbose)			\
 			device_printf(dev, msg);	\
-	}while(0)
+	} while (0)
 
 struct hwpstate_setting {
 	int	freq;		/* CPU clock in Mhz or 100ths of a percent. */
@@ -117,11 +122,14 @@
 static int	hwpstate_get_info_from_msr(device_t dev);
 static int	hwpstate_goto_pstate(device_t dev, int pstate_id);
 
-static int	hwpstate_verbose = 0;
-SYSCTL_INT(_debug, OID_AUTO, hwpstate_verbose, CTLFLAG_RW | CTLFLAG_TUN,
-       &hwpstate_verbose, 0, "Debug hwpstate");
-TUNABLE_INT("debug.hwpstate_verbose", &hwpstate_verbose);
+static int	hwpstate_verbose;
+SYSCTL_INT(_debug, OID_AUTO, hwpstate_verbose, CTLFLAG_RWTUN,
+    &hwpstate_verbose, 0, "Debug hwpstate");
 
+static int	hwpstate_verify;
+SYSCTL_INT(_debug, OID_AUTO, hwpstate_verify, CTLFLAG_RWTUN,
+    &hwpstate_verify, 0, "Verify P-state after setting");
+
 static device_method_t hwpstate_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_identify,	hwpstate_identify),
@@ -155,61 +163,69 @@
  * Go to Px-state on all cpus considering the limit.
  */
 static int
-hwpstate_goto_pstate(device_t dev, int pstate)
+hwpstate_goto_pstate(device_t dev, int id)
 {
-	int i;
+	sbintime_t sbt;
 	uint64_t msr;
-	int j;
-	int limit;
-	int id = pstate;
-	int error;
-	
+	int cpu, i, j, limit;
+
 	/* get the current pstate limit */
 	msr = rdmsr(MSR_AMD_10H_11H_LIMIT);
 	limit = AMD_10H_11H_GET_PSTATE_LIMIT(msr);
-	if(limit > id)
+	if (limit > id)
 		id = limit;
 
+	cpu = curcpu;
+	HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n", id, cpu);
+	/* Go To Px-state */
+	wrmsr(MSR_AMD_10H_11H_CONTROL, id);
+
 	/*
 	 * We are going to the same Px-state on all cpus.
 	 * Probably should take _PSD into account.
 	 */
-	error = 0;
 	CPU_FOREACH(i) {
+		if (i == cpu)
+			continue;
+
 		/* Bind to each cpu. */
 		thread_lock(curthread);
 		sched_bind(curthread, i);
 		thread_unlock(curthread);
-		HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n",
-			id, PCPU_GET(cpuid));
+		HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n", id, i);
 		/* Go To Px-state */
 		wrmsr(MSR_AMD_10H_11H_CONTROL, id);
 	}
-	CPU_FOREACH(i) {
-		/* Bind to each cpu. */
-		thread_lock(curthread);
-		sched_bind(curthread, i);
-		thread_unlock(curthread);
-		/* wait loop (100*100 usec is enough ?) */
-		for(j = 0; j < 100; j++){
-			/* get the result. not assure msr=id */
-			msr = rdmsr(MSR_AMD_10H_11H_STATUS);
-			if(msr == id){
-				break;
+
+	/*
+	 * Verify whether each core is in the requested P-state.
+	 */
+	if (hwpstate_verify) {
+		CPU_FOREACH(i) {
+			thread_lock(curthread);
+			sched_bind(curthread, i);
+			thread_unlock(curthread);
+			/* wait loop (100*100 usec is enough ?) */
+			for (j = 0; j < 100; j++) {
+				/* get the result. not assure msr=id */
+				msr = rdmsr(MSR_AMD_10H_11H_STATUS);
+				if (msr == id)
+					break;
+				sbt = SBT_1MS / 10;
+				tsleep_sbt(dev, PZERO, "pstate_goto", sbt,
+				    sbt >> tc_precexp, 0);
 			}
-			DELAY(100);
+			HWPSTATE_DEBUG(dev, "result: P%d-state on cpu%d\n",
+			    (int)msr, i);
+			if (msr != id) {
+				HWPSTATE_DEBUG(dev,
+				    "error: loop is not enough.\n");
+				return (ENXIO);
+			}
 		}
-		HWPSTATE_DEBUG(dev, "result  P%d-state on cpu%d\n",
-		    (int)msr, PCPU_GET(cpuid));
-		if (msr != id) {
-			HWPSTATE_DEBUG(dev, "error: loop is not enough.\n");
-			error = ENXIO;
-		}
 	}
-	thread_lock(curthread);
-	sched_unbind(curthread);
-	thread_unlock(curthread);
-	return (error);
+
+	return (0);
 }
 
 static int
@@ -243,7 +259,7 @@
 	if (cf == NULL)
 		return (EINVAL);
 	msr = rdmsr(MSR_AMD_10H_11H_STATUS);
-	if(msr >= sc->cfnum)
+	if (msr >= sc->cfnum)
 		return (EINVAL);
 	set = sc->hwpstate_settings[msr];
 
@@ -368,7 +384,8 @@
 		 */
 		msr = rdmsr(MSR_AMD_10H_11H_LIMIT);
 		if (sc->cfnum != 1 + AMD_10H_11H_GET_PSTATE_MAX_VAL(msr)) {
-			HWPSTATE_DEBUG(dev, "msr and acpi _PSS count mismatch.\n");
+			HWPSTATE_DEBUG(dev, "MSR (%jd) and ACPI _PSS (%d)"
+			    " count mismatch\n", (intmax_t)msr, sc->cfnum);
 			error = TRUE;
 		}
 	}
@@ -409,25 +426,37 @@
 	hwpstate_set = sc->hwpstate_settings;
 	for (i = 0; i < sc->cfnum; i++) {
 		msr = rdmsr(MSR_AMD_10H_11H_CONFIG + i);
-		if ((msr & ((uint64_t)1 << 63)) != ((uint64_t)1 << 63)) {
+		if ((msr & ((uint64_t)1 << 63)) == 0) {
 			HWPSTATE_DEBUG(dev, "msr is not valid.\n");
 			return (ENXIO);
 		}
 		did = AMD_10H_11H_CUR_DID(msr);
 		fid = AMD_10H_11H_CUR_FID(msr);
-		switch(family) {
+
+		/* Convert fid/did to frequency. */
+		switch (family) {
 		case 0x11:
-			/* fid/did to frequency */
-			hwpstate_set[i].freq = 100 * (fid + 0x08) / (1 << did);
+			hwpstate_set[i].freq = (100 * (fid + 0x08)) >> did;
 			break;
 		case 0x10:
-			/* fid/did to frequency */
-			hwpstate_set[i].freq = 100 * (fid + 0x10) / (1 << did);
+		case 0x12:
+		case 0x15:
+		case 0x16:
+			hwpstate_set[i].freq = (100 * (fid + 0x10)) >> did;
 			break;
+		case 0x17:
+			did = AMD_17H_CUR_DID(msr);
+			if (did == 0) {
+				HWPSTATE_DEBUG(dev, "unexpected did: 0\n");
+				did = 1;
+			}
+			fid = AMD_17H_CUR_FID(msr);
+			hwpstate_set[i].freq = (200 * fid) / did;
+			break;
 		default:
-			HWPSTATE_DEBUG(dev, "get_info_from_msr: AMD family %d CPU's are not implemented yet. sorry.\n", family);
+			HWPSTATE_DEBUG(dev, "get_info_from_msr: AMD family"
+			    " 0x%02x CPUs are not supported yet\n", family);
 			return (ENXIO);
-			break;
 		}
 		hwpstate_set[i].pstate_id = i;
 		/* There was volts calculation, but deleted it. */

Modified: trunk/sys/x86/cpufreq/p4tcc.c
===================================================================
--- trunk/sys/x86/cpufreq/p4tcc.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/cpufreq/p4tcc.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 Nate Lawson
  * All rights reserved.
@@ -37,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/cpufreq/p4tcc.c 250487 2013-05-10 22:43:27Z hiren $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -297,8 +298,8 @@
 	 */
 	if (msr & TCC_ENABLE_ONDEMAND)
 		sc->auto_mode = FALSE;
- 	else
- 		sc->auto_mode = TRUE;
+	else
+		sc->auto_mode = TRUE;
 
 	return (0);
 }

Modified: trunk/sys/x86/cpufreq/powernow.c
===================================================================
--- trunk/sys/x86/cpufreq/powernow.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/cpufreq/powernow.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2004-2005 Bruno Ducrot
  * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda at spa.is.uec.ac.jp>
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/cpufreq/powernow.c 305615 2016-09-08 15:06:28Z pfg $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -700,9 +701,9 @@
 			if (sc->pn_type != PN8_TYPE)
 				return (EINVAL);
 			sc->vst = psb->settlingtime;
-			sc->rvo = PN8_PSB_TO_RVO(psb->res1),
-			sc->irt = PN8_PSB_TO_IRT(psb->res1),
-			sc->mvs = PN8_PSB_TO_MVS(psb->res1),
+			sc->rvo = PN8_PSB_TO_RVO(psb->res1);
+			sc->irt = PN8_PSB_TO_IRT(psb->res1);
+			sc->mvs = PN8_PSB_TO_MVS(psb->res1);
 			sc->low = PN8_PSB_TO_BATT(psb->res1);
 			if (bootverbose) {
 				device_printf(dev, "PSB: VST: %d\n",

Modified: trunk/sys/x86/cpufreq/smist.c
===================================================================
--- trunk/sys/x86/cpufreq/smist.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/cpufreq/smist.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 Bruno Ducrot
  *
@@ -36,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/cpufreq/smist.c 187597 2009-01-22 20:29:07Z jkim $");
 
 #include <sys/param.h>
 #include <sys/bus.h>

Modified: trunk/sys/x86/include/_align.h
===================================================================
--- trunk/sys/x86/include/_align.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/_align.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2001 David E. O'Brien
  * Copyright (c) 1990 The Regents of the University of California.
@@ -35,7 +36,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)param.h	5.8 (Berkeley) 6/28/91
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/x86/include/_align.h 215856 2010-11-26 10:59:20Z tijl $
  */
 
 #ifndef _X86_INCLUDE__ALIGN_H_

Modified: trunk/sys/x86/include/_inttypes.h
===================================================================
--- trunk/sys/x86/include/_inttypes.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/_inttypes.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -27,7 +28,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  *	From: $NetBSD: int_fmtio.h,v 1.2 2001/04/26 16:25:21 kleink Exp $
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/include/_inttypes.h 217157 2011-01-08 18:09:48Z tijl $
  */
 
 #ifndef _MACHINE_INTTYPES_H_

Added: trunk/sys/x86/include/_limits.h
===================================================================
--- trunk/sys/x86/include/_limits.h	                        (rev 0)
+++ trunk/sys/x86/include/_limits.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,102 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)limits.h	8.3 (Berkeley) 1/4/94
+ * $FreeBSD: stable/10/sys/x86/include/_limits.h 235939 2012-05-24 21:44:46Z obrien $
+ */
+
+#ifndef	_MACHINE__LIMITS_H_
+#define	_MACHINE__LIMITS_H_
+
+/*
+ * According to ANSI (section 2.2.4.2), the values below must be usable by
+ * #if preprocessing directives.  Additionally, the expression must have the
+ * same type as would an expression that is an object of the corresponding
+ * type converted according to the integral promotions.  The subtraction for
+ * INT_MIN, etc., is so the value is not unsigned; e.g., 0x80000000 is an
+ * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2).
+ */
+
+#define	__CHAR_BIT	8		/* number of bits in a char */
+
+#define	__SCHAR_MAX	0x7f		/* max value for a signed char */
+#define	__SCHAR_MIN	(-0x7f - 1)	/* min value for a signed char */
+
+#define	__UCHAR_MAX	0xff		/* max value for an unsigned char */
+
+#define	__USHRT_MAX	0xffff		/* max value for an unsigned short */
+#define	__SHRT_MAX	0x7fff		/* max value for a short */
+#define	__SHRT_MIN	(-0x7fff - 1)	/* min value for a short */
+
+#define	__UINT_MAX	0xffffffff	/* max value for an unsigned int */
+#define	__INT_MAX	0x7fffffff	/* max value for an int */
+#define	__INT_MIN	(-0x7fffffff - 1)	/* min value for an int */
+
+#ifdef	__LP64__
+#define	__ULONG_MAX	0xffffffffffffffff	/* max for an unsigned long */
+#define	__LONG_MAX	0x7fffffffffffffff	/* max for a long */
+#define	__LONG_MIN	(-0x7fffffffffffffff - 1) /* min for a long */
+#else
+#define	__ULONG_MAX	0xffffffffUL
+#define	__LONG_MAX	0x7fffffffL
+#define	__LONG_MIN	(-0x7fffffffL - 1)
+#endif
+
+			/* max value for an unsigned long long */
+#define	__ULLONG_MAX	0xffffffffffffffffULL
+#define	__LLONG_MAX	0x7fffffffffffffffLL	/* max value for a long long */
+#define	__LLONG_MIN	(-0x7fffffffffffffffLL - 1)  /* min for a long long */
+
+#ifdef	__LP64__
+#define	__SSIZE_MAX	__LONG_MAX	/* max value for a ssize_t */
+#define	__SIZE_T_MAX	__ULONG_MAX	/* max value for a size_t */
+#define	__OFF_MAX	__LONG_MAX	/* max value for an off_t */
+#define	__OFF_MIN	__LONG_MIN	/* min value for an off_t */
+/* Quads and longs are the same on the amd64.  Ensure they stay in sync. */
+#define	__UQUAD_MAX	__ULONG_MAX	/* max value for a uquad_t */
+#define	__QUAD_MAX	__LONG_MAX	/* max value for a quad_t */
+#define	__QUAD_MIN	__LONG_MIN	/* min value for a quad_t */
+#define	__LONG_BIT	64
+#else
+#define	__SSIZE_MAX	__INT_MAX
+#define	__SIZE_T_MAX	__UINT_MAX
+#define	__OFF_MAX	__LLONG_MAX
+#define	__OFF_MIN	__LLONG_MIN
+#define	__UQUAD_MAX	__ULLONG_MAX
+#define	__QUAD_MAX	__LLONG_MAX
+#define	__QUAD_MIN	__LLONG_MIN
+#define	__LONG_BIT	32
+#endif
+
+#define	__WORD_BIT	32
+
+/* Minimum signal stack size. */
+#define	__MINSIGSTKSZ	(512 * 4)
+
+#endif /* !_MACHINE__LIMITS_H_ */


Property changes on: trunk/sys/x86/include/_limits.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/_stdint.h
===================================================================
--- trunk/sys/x86/include/_stdint.h	                        (rev 0)
+++ trunk/sys/x86/include/_stdint.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,190 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2001, 2002 Mike Barcroft <mike at FreeBSD.org>
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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: stable/10/sys/x86/include/_stdint.h 237517 2012-06-24 04:15:58Z andrew $
+ */
+
+#ifndef _MACHINE__STDINT_H_
+#define	_MACHINE__STDINT_H_
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+#define	INT8_C(c)		(c)
+#define	INT16_C(c)		(c)
+#define	INT32_C(c)		(c)
+
+#define	UINT8_C(c)		(c)
+#define	UINT16_C(c)		(c)
+#define	UINT32_C(c)		(c ## U)
+
+#ifdef	__LP64__
+#define	INT64_C(c)		(c ## L)
+#define	UINT64_C(c)		(c ## UL)
+#else
+#define	INT64_C(c)		(c ## LL)
+#define	UINT64_C(c)		(c ## ULL)
+#endif
+
+#define	INTMAX_C(c)		INT64_C(c)
+#define	UINTMAX_C(c)		UINT64_C(c)
+
+#endif /* !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) */
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.2.1 Limits of exact-width integer types
+ */
+#define	INT8_MIN	(-0x7f-1)
+#define	INT16_MIN	(-0x7fff-1)
+#define	INT32_MIN	(-0x7fffffff-1)
+
+#define	INT8_MAX	0x7f
+#define	INT16_MAX	0x7fff
+#define	INT32_MAX	0x7fffffff
+
+#define	UINT8_MAX	0xff
+#define	UINT16_MAX	0xffff
+#define	UINT32_MAX	0xffffffffU
+
+#ifdef __LP64__
+#define	INT64_MIN	(-0x7fffffffffffffff-1)
+#define	INT64_MAX	0x7fffffffffffffff
+#define	UINT64_MAX	0xffffffffffffffff
+#else
+#define	INT64_MIN	(-0x7fffffffffffffffLL-1)
+#define	INT64_MAX	0x7fffffffffffffffLL
+#define	UINT64_MAX	0xffffffffffffffffULL
+#endif
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.2.2  Limits of minimum-width integer types
+ */
+/* Minimum values of minimum-width signed integer types. */
+#define	INT_LEAST8_MIN	INT8_MIN
+#define	INT_LEAST16_MIN	INT16_MIN
+#define	INT_LEAST32_MIN	INT32_MIN
+#define	INT_LEAST64_MIN	INT64_MIN
+
+/* Maximum values of minimum-width signed integer types. */
+#define	INT_LEAST8_MAX	INT8_MAX
+#define	INT_LEAST16_MAX	INT16_MAX
+#define	INT_LEAST32_MAX	INT32_MAX
+#define	INT_LEAST64_MAX	INT64_MAX
+
+/* Maximum values of minimum-width unsigned integer types. */
+#define	UINT_LEAST8_MAX	 UINT8_MAX
+#define	UINT_LEAST16_MAX UINT16_MAX
+#define	UINT_LEAST32_MAX UINT32_MAX
+#define	UINT_LEAST64_MAX UINT64_MAX
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.2.3  Limits of fastest minimum-width integer types
+ */
+/* Minimum values of fastest minimum-width signed integer types. */
+#define	INT_FAST8_MIN	INT32_MIN
+#define	INT_FAST16_MIN	INT32_MIN
+#define	INT_FAST32_MIN	INT32_MIN
+#define	INT_FAST64_MIN	INT64_MIN
+
+/* Maximum values of fastest minimum-width signed integer types. */
+#define	INT_FAST8_MAX	INT32_MAX
+#define	INT_FAST16_MAX	INT32_MAX
+#define	INT_FAST32_MAX	INT32_MAX
+#define	INT_FAST64_MAX	INT64_MAX
+
+/* Maximum values of fastest minimum-width unsigned integer types. */
+#define	UINT_FAST8_MAX	UINT32_MAX
+#define	UINT_FAST16_MAX	UINT32_MAX
+#define	UINT_FAST32_MAX	UINT32_MAX
+#define	UINT_FAST64_MAX	UINT64_MAX
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.2.4  Limits of integer types capable of holding object pointers
+ */
+#ifdef	__LP64__
+#define	INTPTR_MIN	INT64_MIN
+#define	INTPTR_MAX	INT64_MAX
+#define	UINTPTR_MAX	UINT64_MAX
+#else
+#define	INTPTR_MIN	INT32_MIN
+#define	INTPTR_MAX	INT32_MAX
+#define	UINTPTR_MAX	UINT32_MAX
+#endif
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.2.5  Limits of greatest-width integer types
+ */
+#define	INTMAX_MIN	INT64_MIN
+#define	INTMAX_MAX	INT64_MAX
+#define	UINTMAX_MAX	UINT64_MAX
+
+/*
+ * ISO/IEC 9899:1999
+ * 7.18.3  Limits of other integer types
+ */
+#ifdef	__LP64__
+/* Limits of ptrdiff_t. */
+#define	PTRDIFF_MIN	INT64_MIN	
+#define	PTRDIFF_MAX	INT64_MAX
+
+/* Limits of sig_atomic_t. */
+#define	SIG_ATOMIC_MIN	LONG_MIN
+#define	SIG_ATOMIC_MAX	LONG_MAX
+
+/* Limit of size_t. */
+#define	SIZE_MAX	UINT64_MAX
+#else
+#define	PTRDIFF_MIN	INT32_MIN
+#define	PTRDIFF_MAX	INT32_MAX
+#define	SIG_ATOMIC_MIN	INT32_MIN
+#define	SIG_ATOMIC_MAX	INT32_MAX
+#define	SIZE_MAX	UINT32_MAX
+#endif
+
+/* Limits of wint_t. */
+#define	WINT_MIN	INT32_MIN
+#define	WINT_MAX	INT32_MAX
+
+#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */
+
+#endif /* !_MACHINE__STDINT_H_ */


Property changes on: trunk/sys/x86/include/_stdint.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/_types.h
===================================================================
--- trunk/sys/x86/include/_types.h	                        (rev 0)
+++ trunk/sys/x86/include/_types.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,173 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2002 Mike Barcroft <mike at FreeBSD.org>
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	From: @(#)ansi.h	8.2 (Berkeley) 1/4/94
+ *	From: @(#)types.h	8.3 (Berkeley) 1/5/94
+ * $FreeBSD: stable/10/sys/x86/include/_types.h 287139 2015-08-25 19:18:38Z jkim $
+ */
+
+#ifndef _MACHINE__TYPES_H_
+#define	_MACHINE__TYPES_H_
+
+#ifndef _SYS_CDEFS_H_
+#error this file needs sys/cdefs.h as a prerequisite
+#endif
+
+#define __NO_STRICT_ALIGNMENT
+
+/*
+ * Basic types upon which most other types are built.
+ */
+typedef	signed char		__int8_t;
+typedef	unsigned char		__uint8_t;
+typedef	short			__int16_t;
+typedef	unsigned short		__uint16_t;
+typedef	int			__int32_t;
+typedef	unsigned int		__uint32_t;
+#ifdef	__LP64__
+typedef	long			__int64_t;
+typedef	unsigned long		__uint64_t;
+#else
+#ifndef lint
+__extension__
+#endif
+/* LONGLONG */
+typedef	long long		__int64_t;
+#ifndef lint
+__extension__
+#endif
+/* LONGLONG */
+typedef	unsigned long long	__uint64_t;
+#endif
+
+/*
+ * Standard type definitions.
+ */
+#ifdef	__LP64__
+typedef	__int32_t	__clock_t;		/* clock()... */
+typedef	__int64_t	__critical_t;
+typedef	double		__double_t;
+typedef	float		__float_t;
+typedef	__int64_t	__intfptr_t;
+typedef	__int64_t	__intptr_t;
+#else
+typedef	unsigned long	__clock_t;
+typedef	__int32_t	__critical_t;
+typedef	long double	__double_t;
+typedef	long double	__float_t;
+typedef	__int32_t	__intfptr_t;
+typedef	__int32_t	__intptr_t;
+#endif
+typedef	__int64_t	__intmax_t;
+typedef	__int32_t	__int_fast8_t;
+typedef	__int32_t	__int_fast16_t;
+typedef	__int32_t	__int_fast32_t;
+typedef	__int64_t	__int_fast64_t;
+typedef	__int8_t	__int_least8_t;
+typedef	__int16_t	__int_least16_t;
+typedef	__int32_t	__int_least32_t;
+typedef	__int64_t	__int_least64_t;
+#ifdef	__LP64__
+typedef	__int64_t	__ptrdiff_t;		/* ptr1 - ptr2 */
+typedef	__int64_t	__register_t;
+typedef	__int64_t	__segsz_t;		/* segment size (in pages) */
+typedef	__uint64_t	__size_t;		/* sizeof() */
+typedef	__int64_t	__ssize_t;		/* byte count or error */
+typedef	__int64_t	__time_t;		/* time()... */
+typedef	__uint64_t	__uintfptr_t;
+typedef	__uint64_t	__uintptr_t;
+#else
+typedef	__int32_t	__ptrdiff_t;
+typedef	__int32_t	__register_t;
+typedef	__int32_t	__segsz_t;
+typedef	__uint32_t	__size_t;
+typedef	__int32_t	__ssize_t;
+typedef	__int32_t	__time_t;
+typedef	__uint32_t	__uintfptr_t;
+typedef	__uint32_t	__uintptr_t;
+#endif
+typedef	__uint64_t	__uintmax_t;
+typedef	__uint32_t	__uint_fast8_t;
+typedef	__uint32_t	__uint_fast16_t;
+typedef	__uint32_t	__uint_fast32_t;
+typedef	__uint64_t	__uint_fast64_t;
+typedef	__uint8_t	__uint_least8_t;
+typedef	__uint16_t	__uint_least16_t;
+typedef	__uint32_t	__uint_least32_t;
+typedef	__uint64_t	__uint_least64_t;
+#ifdef	__LP64__
+typedef	__uint64_t	__u_register_t;
+typedef	__uint64_t	__vm_offset_t;
+typedef	__uint64_t	__vm_paddr_t;
+typedef	__uint64_t	__vm_size_t;
+#else
+typedef	__uint32_t	__u_register_t;
+typedef	__uint32_t	__vm_offset_t;
+#ifdef PAE
+typedef	__uint64_t	__vm_paddr_t;
+#else
+typedef	__uint32_t	__vm_paddr_t;
+#endif
+typedef	__uint32_t	__vm_size_t;
+#endif
+typedef	__int64_t	__vm_ooffset_t;
+typedef	__uint64_t	__vm_pindex_t;
+typedef	int		___wchar_t;
+
+#define	__WCHAR_MIN	__INT_MIN	/* min value for a wchar_t */
+#define	__WCHAR_MAX	__INT_MAX	/* max value for a wchar_t */
+
+/*
+ * Unusual type definitions.
+ */
+#ifdef __GNUCLIKE_BUILTIN_VARARGS
+typedef	__builtin_va_list	__va_list;	/* internally known to gcc */
+#else
+#ifdef __LP64__
+struct __s_va_list {
+	__uint32_t	_pad1[2];	/* gp_offset, fp_offset */
+	__uint64_t	_pad2[2];	/* overflow_arg_area, reg_save_area */
+};
+typedef	struct __s_va_list	__va_list;
+#else
+typedef	char *			__va_list;
+#endif
+#endif
+#if defined(__GNUC_VA_LIST_COMPATIBILITY) && !defined(__GNUC_VA_LIST) \
+    && !defined(__NO_GNUC_VA_LIST)
+#define __GNUC_VA_LIST
+typedef __va_list		__gnuc_va_list;	/* compatibility w/GNU headers*/
+#endif
+
+#endif /* !_MACHINE__TYPES_H_ */


Property changes on: trunk/sys/x86/include/_types.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/acpica_machdep.h
===================================================================
--- trunk/sys/x86/include/acpica_machdep.h	                        (rev 0)
+++ trunk/sys/x86/include/acpica_machdep.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,81 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2002 Mitsuru IWASAKI
+ * 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: stable/10/sys/x86/include/acpica_machdep.h 259073 2013-12-07 18:23:29Z peter $
+ */
+
+/******************************************************************************
+ *
+ * Name: acpica_machdep.h - arch-specific defines, etc.
+ *       $Revision$
+ *
+ *****************************************************************************/
+
+#ifndef __ACPICA_MACHDEP_H__
+#define	__ACPICA_MACHDEP_H__
+
+#ifdef _KERNEL
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define	ACPI_SYSTEM_XFACE
+#define	ACPI_EXTERNAL_XFACE
+#define	ACPI_INTERNAL_XFACE
+#define	ACPI_INTERNAL_VAR_XFACE
+
+/* Asm macros */
+
+#define	ACPI_ASM_MACROS
+#define	BREAKPOINT3
+#define	ACPI_DISABLE_IRQS() disable_intr()
+#define	ACPI_ENABLE_IRQS()  enable_intr()
+
+#define	ACPI_FLUSH_CPU_CACHE()	wbinvd()
+
+/* Section 5.2.10.1: global lock acquire/release functions */
+int	acpi_acquire_global_lock(volatile uint32_t *);
+int	acpi_release_global_lock(volatile uint32_t *);
+#define	ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq)	do {			\
+	(Acq) = acpi_acquire_global_lock(&((GLptr)->GlobalLock));	\
+} while (0)
+#define	ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq)	do {			\
+	(Acq) = acpi_release_global_lock(&((GLptr)->GlobalLock));	\
+} while (0)
+ 
+void	acpi_SetDefaultIntrModel(int model);
+void	acpi_cpu_c1(void);
+void	*acpi_map_table(vm_paddr_t pa, const char *sig);
+void	acpi_unmap_table(void *table);
+vm_paddr_t acpi_find_table(const char *sig);
+
+#endif /* _KERNEL */
+
+#endif /* __ACPICA_MACHDEP_H__ */


Property changes on: trunk/sys/x86/include/acpica_machdep.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/include/apicreg.h
===================================================================
--- trunk/sys/x86/include/apicreg.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/apicreg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1996, by Peter Wemm and Steve Passe
  * All rights reserved.
@@ -22,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/include/apicreg.h 262141 2014-02-18 01:15:32Z jhb $
  */
 
 #ifndef _X86_APICREG_H_
@@ -357,6 +358,16 @@
 #define APIC_TDCR_128		0x0a
 #define APIC_TDCR_1		0x0b
 
+/* LVT table indices */
+#define	APIC_LVT_LINT0		0
+#define	APIC_LVT_LINT1		1
+#define	APIC_LVT_TIMER		2
+#define	APIC_LVT_ERROR		3
+#define	APIC_LVT_PMC		4
+#define	APIC_LVT_THERMAL	5
+#define	APIC_LVT_CMCI		6
+#define	APIC_LVT_MAX		APIC_LVT_CMCI
+
 /******************************************************************************
  * I/O APIC defines
  */

Modified: trunk/sys/x86/include/apm_bios.h
===================================================================
--- trunk/sys/x86/include/apm_bios.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/apm_bios.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * APM (Advanced Power Management) BIOS Device Driver
  *
@@ -12,7 +13,7 @@
  *
  * Aug, 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/include/apm_bios.h 215140 2010-11-11 19:36:21Z jkim $
  */
 
 #ifndef _X86_APM_BIOS_H_

Modified: trunk/sys/x86/include/bus.h
===================================================================
--- trunk/sys/x86/include/bus.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/bus.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) KATO Takenori, 1999.
  *
@@ -28,7 +29,7 @@
  * (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$
+ * $FreeBSD: stable/10/sys/x86/include/bus.h 287126 2015-08-25 14:39:40Z marcel $
  */
 
 /*	$NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $	*/
@@ -49,13 +50,6 @@
  * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the NetBSD
- *	Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -130,6 +124,7 @@
 #define BUS_SPACE_MAXADDR	0xFFFFFFFF
 #endif
 
+#define BUS_SPACE_INVALID_DATA	(~0)
 #define BUS_SPACE_UNRESTRICTED	(~0)
 
 /*
@@ -136,33 +131,16 @@
  * Map a region of device bus space into CPU virtual address space.
  */
 
-static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
-				  bus_size_t size, int flags,
-				  bus_space_handle_t *bshp);
+int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size,
+    int flags, bus_space_handle_t *bshp);
 
-static __inline int
-bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr,
-	      bus_size_t size __unused, int flags __unused,
-	      bus_space_handle_t *bshp)
-{
-
-	*bshp = addr;
-	return (0);
-}
-
 /*
  * Unmap a region of device bus space.
  */
 
-static __inline void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
-				     bus_size_t size);
+void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh,
+    bus_size_t size);
 
-static __inline void
-bus_space_unmap(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
-		bus_size_t size __unused)
-{
-}
-
 /*
  * Get a new handle for a subregion of an already-mapped area of bus space.
  */
@@ -221,6 +199,12 @@
 					   bus_space_handle_t handle,
 					   bus_size_t offset);
 
+#ifdef __amd64__
+static __inline uint64_t bus_space_read_8(bus_space_tag_t tag,
+					  bus_space_handle_t handle,
+					  bus_size_t offset);
+#endif
+
 static __inline u_int8_t
 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle,
 		 bus_size_t offset)
@@ -251,8 +235,16 @@
 	return (*(volatile u_int32_t *)(handle + offset));
 }
 
-#if 0	/* Cause a link error for bus_space_read_8 */
-#define	bus_space_read_8(t, h, o)	!!! bus_space_read_8 unimplemented !!!
+#ifdef __amd64__
+static __inline uint64_t
+bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle,
+		 bus_size_t offset)
+{
+
+	if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */
+		return (BUS_SPACE_INVALID_DATA);
+	return (*(volatile uint64_t *)(handle + offset));
+}
 #endif
 
 /*
@@ -479,6 +471,12 @@
 				       bus_space_handle_t bsh,
 				       bus_size_t offset, u_int32_t value);
 
+#ifdef __amd64__
+static __inline void bus_space_write_8(bus_space_tag_t tag,
+				       bus_space_handle_t bsh,
+				       bus_size_t offset, uint64_t value);
+#endif
+
 static __inline void
 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
 		       bus_size_t offset, u_int8_t value)
@@ -512,8 +510,17 @@
 		*(volatile u_int32_t *)(bsh + offset) = value;
 }
 
-#if 0	/* Cause a link error for bus_space_write_8 */
-#define	bus_space_write_8	!!! bus_space_write_8 not implemented !!!
+#ifdef __amd64__
+static __inline void
+bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh,
+		  bus_size_t offset, uint64_t value)
+{
+
+	if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */
+		return;
+	else
+		*(volatile uint64_t *)(bsh + offset) = value;
+}
 #endif
 
 /*
@@ -1014,7 +1021,7 @@
 		__asm __volatile("lock; addl $0,0(%%esp)" : : : "memory");
 #endif
 	else
-		__asm __volatile("" : : : "memory");
+		__compiler_membar();
 #endif
 }
 

Added: trunk/sys/x86/include/busdma_impl.h
===================================================================
--- trunk/sys/x86/include/busdma_impl.h	                        (rev 0)
+++ trunk/sys/x86/include/busdma_impl.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,97 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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: stable/10/sys/x86/include/busdma_impl.h 259512 2013-12-17 13:49:35Z kib $
+ */
+
+#ifndef	__X86_BUSDMA_IMPL_H
+#define	__X86_BUSDMA_IMPL_H
+
+struct bus_dma_tag_common {
+	struct bus_dma_impl *impl;
+	struct bus_dma_tag_common *parent;
+	bus_size_t	  alignment;
+	bus_addr_t	  boundary;
+	bus_addr_t	  lowaddr;
+	bus_addr_t	  highaddr;
+	bus_dma_filter_t *filter;
+	void		 *filterarg;
+	bus_size_t	  maxsize;
+	u_int		  nsegments;
+	bus_size_t	  maxsegsz;
+	int		  flags;
+	bus_dma_lock_t	 *lockfunc;
+	void		 *lockfuncarg;
+	int		  ref_count;
+};
+
+struct bus_dma_impl {
+	int (*tag_create)(bus_dma_tag_t parent,
+	    bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr,
+	    bus_addr_t highaddr, bus_dma_filter_t *filter,
+	    void *filterarg, bus_size_t maxsize, int nsegments,
+	    bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+	    void *lockfuncarg, bus_dma_tag_t *dmat);
+	int (*tag_destroy)(bus_dma_tag_t dmat);
+	int (*map_create)(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp);
+	int (*map_destroy)(bus_dma_tag_t dmat, bus_dmamap_t map);
+	int (*mem_alloc)(bus_dma_tag_t dmat, void** vaddr, int flags,
+	    bus_dmamap_t *mapp);
+	void (*mem_free)(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);
+	int (*load_ma)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
+	    bus_dma_segment_t *segs, int *segp);
+	int (*load_phys)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    vm_paddr_t buf, bus_size_t buflen, int flags,
+	    bus_dma_segment_t *segs, int *segp);
+	int (*load_buffer)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    void *buf, bus_size_t buflen, pmap_t pmap, int flags,
+	    bus_dma_segment_t *segs, int *segp);
+	void (*map_waitok)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    struct memdesc *mem, bus_dmamap_callback_t *callback,
+	    void *callback_arg);
+	bus_dma_segment_t *(*map_complete)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    bus_dma_segment_t *segs, int nsegs, int error);
+	void (*map_unload)(bus_dma_tag_t dmat, bus_dmamap_t map);
+	void (*map_sync)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    bus_dmasync_op_t op);
+};
+
+void bus_dma_dflt_lock(void *arg, bus_dma_lock_op_t op);
+int bus_dma_run_filter(struct bus_dma_tag_common *dmat, bus_addr_t paddr);
+int common_bus_dma_tag_create(struct bus_dma_tag_common *parent,
+    bus_size_t alignment,
+    bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
+    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
+    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+    void *lockfuncarg, size_t sz, void **dmat);
+
+extern struct bus_dma_impl bus_dma_bounce_impl;
+
+#endif


Property changes on: trunk/sys/x86/include/busdma_impl.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/elf.h
===================================================================
--- trunk/sys/x86/include/elf.h	                        (rev 0)
+++ trunk/sys/x86/include/elf.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,216 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * 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: stable/10/sys/x86/include/elf.h 247047 2013-02-20 17:39:52Z kib $
+ */
+
+#ifndef _MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_ 1
+
+#if defined(__i386__) || defined(_MACHINE_ELF_WANT_32BIT)
+
+/*
+ * ELF definitions for the i386 architecture.
+ */
+
+#include <sys/elf32.h>	/* Definitions common to all 32 bit architectures. */
+#if defined(__ELF_WORD_SIZE) && __ELF_WORD_SIZE == 64
+#include <sys/elf64.h>	/* Definitions common to all 64 bit architectures. */
+#endif
+
+#ifndef __ELF_WORD_SIZE
+#define	__ELF_WORD_SIZE	32	/* Used by <sys/elf_generic.h> */
+#endif
+
+#include <sys/elf_generic.h>
+
+#define	ELF_ARCH	EM_386
+
+#define	ELF_MACHINE_OK(x) ((x) == EM_386 || (x) == EM_486)
+
+/*
+ * Auxiliary vector entries for passing information to the interpreter.
+ *
+ * The i386 supplement to the SVR4 ABI specification names this "auxv_t",
+ * but POSIX lays claim to all symbols ending with "_t".
+ */
+
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	int	a_type;			/* Entry type. */
+	union {
+		long	a_val;		/* Integer value. */
+		void	*a_ptr;		/* Address. */
+		void	(*a_fcn)(void);	/* Function pointer (not used). */
+	} a_un;
+} Elf32_Auxinfo;
+
+#if __ELF_WORD_SIZE == 64
+/* Fake for amd64 loader support */
+typedef struct {
+	int fake;
+} Elf64_Auxinfo;
+#endif
+
+__ElfType(Auxinfo);
+
+/* Values for a_type. */
+#define	AT_NULL		0	/* Terminates the vector. */
+#define	AT_IGNORE	1	/* Ignored entry. */
+#define	AT_EXECFD	2	/* File descriptor of program to load. */
+#define	AT_PHDR		3	/* Program header of program already loaded. */
+#define	AT_PHENT	4	/* Size of each program header entry. */
+#define	AT_PHNUM	5	/* Number of program header entries. */
+#define	AT_PAGESZ	6	/* Page size in bytes. */
+#define	AT_BASE		7	/* Interpreter's base address. */
+#define	AT_FLAGS	8	/* Flags (unused for i386). */
+#define	AT_ENTRY	9	/* Where interpreter should transfer control. */
+#define	AT_NOTELF	10	/* Program is not ELF ?? */
+#define	AT_UID		11	/* Real uid. */
+#define	AT_EUID		12	/* Effective uid. */
+#define	AT_GID		13	/* Real gid. */
+#define	AT_EGID		14	/* Effective gid. */
+#define	AT_EXECPATH	15	/* Path to the executable. */
+#define	AT_CANARY	16	/* Canary for SSP. */
+#define	AT_CANARYLEN	17	/* Length of the canary. */
+#define	AT_OSRELDATE	18	/* OSRELDATE. */
+#define	AT_NCPUS	19	/* Number of CPUs. */
+#define	AT_PAGESIZES	20	/* Pagesizes. */
+#define	AT_PAGESIZESLEN	21	/* Number of pagesizes. */
+#define	AT_TIMEKEEP	22	/* Pointer to timehands. */
+#define	AT_STACKPROT	23	/* Initial stack protection. */
+
+#define	AT_COUNT	24	/* Count of defined aux entry types. */
+
+/*
+ * Relocation types.
+ */
+
+#define	R_386_COUNT	38	/* Count of defined relocation types. */
+
+/* Define "machine" characteristics */
+#define	ELF_TARG_CLASS	ELFCLASS32
+#define	ELF_TARG_DATA	ELFDATA2LSB
+#define	ELF_TARG_MACH	EM_386
+#define	ELF_TARG_VER	1
+
+#define	ET_DYN_LOAD_ADDR 0x01001000
+
+#elif defined(__amd64__)
+
+/*
+ * ELF definitions for the AMD64 architecture.
+ */
+
+#ifndef __ELF_WORD_SIZE
+#define	__ELF_WORD_SIZE	64	/* Used by <sys/elf_generic.h> */
+#endif
+#include <sys/elf32.h>	/* Definitions common to all 32 bit architectures. */
+#include <sys/elf64.h>	/* Definitions common to all 64 bit architectures. */
+#include <sys/elf_generic.h>
+
+#define	ELF_ARCH	EM_X86_64
+#define	ELF_ARCH32	EM_386
+
+#define	ELF_MACHINE_OK(x) ((x) == EM_X86_64)
+
+/*
+ * Auxiliary vector entries for passing information to the interpreter.
+ *
+ * The i386 supplement to the SVR4 ABI specification names this "auxv_t",
+ * but POSIX lays claim to all symbols ending with "_t".
+ */
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	int	a_type;			/* Entry type. */
+	union {
+		int	a_val;		/* Integer value. */
+	} a_un;
+} Elf32_Auxinfo;
+
+
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	long	a_type;			/* Entry type. */
+	union {
+		long	a_val;		/* Integer value. */
+		void	*a_ptr;		/* Address. */
+		void	(*a_fcn)(void);	/* Function pointer (not used). */
+	} a_un;
+} Elf64_Auxinfo;
+
+__ElfType(Auxinfo);
+
+/* Values for a_type. */
+#define	AT_NULL		0	/* Terminates the vector. */
+#define	AT_IGNORE	1	/* Ignored entry. */
+#define	AT_EXECFD	2	/* File descriptor of program to load. */
+#define	AT_PHDR		3	/* Program header of program already loaded. */
+#define	AT_PHENT	4	/* Size of each program header entry. */
+#define	AT_PHNUM	5	/* Number of program header entries. */
+#define	AT_PAGESZ	6	/* Page size in bytes. */
+#define	AT_BASE		7	/* Interpreter's base address. */
+#define	AT_FLAGS	8	/* Flags (unused for i386). */
+#define	AT_ENTRY	9	/* Where interpreter should transfer control. */
+#define	AT_NOTELF	10	/* Program is not ELF ?? */
+#define	AT_UID		11	/* Real uid. */
+#define	AT_EUID		12	/* Effective uid. */
+#define	AT_GID		13	/* Real gid. */
+#define	AT_EGID		14	/* Effective gid. */
+#define	AT_EXECPATH	15	/* Path to the executable. */
+#define	AT_CANARY	16	/* Canary for SSP */
+#define	AT_CANARYLEN	17	/* Length of the canary. */
+#define	AT_OSRELDATE	18	/* OSRELDATE. */
+#define	AT_NCPUS	19	/* Number of CPUs. */
+#define	AT_PAGESIZES	20	/* Pagesizes. */
+#define	AT_PAGESIZESLEN	21	/* Number of pagesizes. */
+#define	AT_TIMEKEEP	22	/* Pointer to timehands. */
+#define	AT_STACKPROT	23	/* Initial stack protection. */
+
+#define	AT_COUNT	24	/* Count of defined aux entry types. */
+
+/*
+ * Relocation types.
+ */
+
+#define	R_X86_64_COUNT	24	/* Count of defined relocation types. */
+
+/* Define "machine" characteristics */
+#if __ELF_WORD_SIZE == 32
+#define ELF_TARG_CLASS  ELFCLASS32
+#else
+#define ELF_TARG_CLASS  ELFCLASS64
+#endif
+#define	ELF_TARG_DATA	ELFDATA2LSB
+#define	ELF_TARG_MACH	EM_X86_64
+#define	ELF_TARG_VER	1
+
+#if __ELF_WORD_SIZE == 32
+#define	ET_DYN_LOAD_ADDR 0x01001000
+#else
+#define	ET_DYN_LOAD_ADDR 0x01021000
+#endif
+
+#endif /* __i386__, __amd64__ */
+
+#endif /* !_MACHINE_ELF_H_ */


Property changes on: trunk/sys/x86/include/elf.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/endian.h
===================================================================
--- trunk/sys/x86/include/endian.h	                        (rev 0)
+++ trunk/sys/x86/include/endian.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,132 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1987, 1991 Regents of the University of California.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)endian.h	7.8 (Berkeley) 4/3/91
+ * $FreeBSD: stable/10/sys/x86/include/endian.h 233684 2012-03-29 23:31:48Z dim $
+ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define	_MACHINE_ENDIAN_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+/*
+ * Define the order of 32-bit words in 64-bit words.
+ */
+#define	_QUAD_HIGHWORD 1
+#define	_QUAD_LOWWORD 0
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define	_LITTLE_ENDIAN	1234	/* LSB first: i386, vax */
+#define	_BIG_ENDIAN	4321	/* MSB first: 68000, ibm, net */
+#define	_PDP_ENDIAN	3412	/* LSB first in word, MSW first in long */
+
+#define	_BYTE_ORDER	_LITTLE_ENDIAN
+
+/*
+ * Deprecated variants that don't have enough underscores to be useful in more
+ * strict namespaces.
+ */
+#if __BSD_VISIBLE
+#define	LITTLE_ENDIAN	_LITTLE_ENDIAN
+#define	BIG_ENDIAN	_BIG_ENDIAN
+#define	PDP_ENDIAN	_PDP_ENDIAN
+#define	BYTE_ORDER	_BYTE_ORDER
+#endif
+
+#define	__bswap16_gen(x)	(__uint16_t)((x) << 8 | (x) >> 8)
+#define	__bswap32_gen(x)		\
+	(((__uint32_t)__bswap16((x) & 0xffff) << 16) | __bswap16((x) >> 16))
+#define	__bswap64_gen(x)		\
+	(((__uint64_t)__bswap32((x) & 0xffffffff) << 32) | __bswap32((x) >> 32))
+
+#ifdef __GNUCLIKE_BUILTIN_CONSTANT_P
+#define	__bswap16(x)				\
+	((__uint16_t)(__builtin_constant_p(x) ?	\
+	    __bswap16_gen((__uint16_t)(x)) : __bswap16_var(x)))
+#define	__bswap32(x)			\
+	(__builtin_constant_p(x) ?	\
+	    __bswap32_gen((__uint32_t)(x)) : __bswap32_var(x))
+#define	__bswap64(x)			\
+	(__builtin_constant_p(x) ?	\
+	    __bswap64_gen((__uint64_t)(x)) : __bswap64_var(x))
+#else
+/* XXX these are broken for use in static initializers. */
+#define	__bswap16(x)	__bswap16_var(x)
+#define	__bswap32(x)	__bswap32_var(x)
+#define	__bswap64(x)	__bswap64_var(x)
+#endif
+
+/* These are defined as functions to avoid multiple evaluation of x. */
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t _x)
+{
+
+	return (__bswap16_gen(_x));
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t _x)
+{
+
+#ifdef __GNUCLIKE_ASM
+	__asm("bswap %0" : "+r" (_x));
+	return (_x);
+#else
+	return (__bswap32_gen(_x));
+#endif
+}
+
+static __inline __uint64_t
+__bswap64_var(__uint64_t _x)
+{
+
+#if defined(__amd64__) && defined(__GNUCLIKE_ASM)
+	__asm("bswap %0" : "+r" (_x));
+	return (_x);
+#else
+	/*
+	 * It is important for the optimizations that the following is not
+	 * really generic, but expands to 2 __bswap32_var()'s.
+	 */
+	return (__bswap64_gen(_x));
+#endif
+}
+
+#define	__htonl(x)	__bswap32(x)
+#define	__htons(x)	__bswap16(x)
+#define	__ntohl(x)	__bswap32(x)
+#define	__ntohs(x)	__bswap16(x)
+
+#endif /* !_MACHINE_ENDIAN_H_ */


Property changes on: trunk/sys/x86/include/endian.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/fdt.h
===================================================================
--- trunk/sys/x86/include/fdt.h	                        (rev 0)
+++ trunk/sys/x86/include/fdt.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,37 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Juniper Networks, 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 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: stable/10/sys/x86/include/fdt.h 266084 2014-05-14 19:18:58Z ian $
+ */
+
+#ifndef _MACHINE_FDT_H_
+#define _MACHINE_FDT_H_
+
+__BEGIN_DECLS
+int x86_init_fdt(void);
+__END_DECLS
+
+#endif /* _MACHINE_FDT_H_ */


Property changes on: trunk/sys/x86/include/fdt.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/float.h
===================================================================
--- trunk/sys/x86/include/float.h	                        (rev 0)
+++ trunk/sys/x86/include/float.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,99 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1989 Regents of the University of California.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)float.h	7.1 (Berkeley) 5/8/90
+ * $FreeBSD: stable/10/sys/x86/include/float.h 235939 2012-05-24 21:44:46Z obrien $
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_ 1
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int __flt_rounds(void);
+__END_DECLS
+
+#define FLT_RADIX	2		/* b */
+#define FLT_ROUNDS	__flt_rounds()
+#if __ISO_C_VISIBLE >= 1999
+#ifdef __LP64__
+#define	FLT_EVAL_METHOD	0		/* no promotions */
+#else
+#define	FLT_EVAL_METHOD	(-1)		/* i387 semantics are...interesting */
+#endif
+#define	DECIMAL_DIG	21		/* max precision in decimal digits */
+#endif
+
+#define FLT_MANT_DIG	24		/* p */
+#define FLT_EPSILON	1.19209290E-07F	/* b**(1-p) */
+#define FLT_DIG		6		/* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP	(-125)		/* emin */
+#define FLT_MIN		1.17549435E-38F	/* b**(emin-1) */
+#define FLT_MIN_10_EXP	(-37)		/* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP	128		/* emax */
+#define FLT_MAX		3.40282347E+38F	/* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP	38		/* floor(log10((1-b**(-p))*b**emax)) */
+#if __ISO_C_VISIBLE >= 2011
+#define	FLT_TRUE_MIN	1.40129846E-45F	/* b**(emin-p) */
+#define	FLT_DECIMAL_DIG	9		/* ceil(1+p*log10(b)) */
+#define	FLT_HAS_SUBNORM	1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define DBL_MANT_DIG	53
+#define DBL_EPSILON	2.2204460492503131E-16
+#define DBL_DIG		15
+#define DBL_MIN_EXP	(-1021)
+#define DBL_MIN		2.2250738585072014E-308
+#define DBL_MIN_10_EXP	(-307)
+#define DBL_MAX_EXP	1024
+#define DBL_MAX		1.7976931348623157E+308
+#define DBL_MAX_10_EXP	308
+#if __ISO_C_VISIBLE >= 2011
+#define	DBL_TRUE_MIN	4.9406564584124654E-324
+#define	DBL_DECIMAL_DIG	17
+#define	DBL_HAS_SUBNORM	1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define LDBL_MANT_DIG	64
+#define LDBL_EPSILON	1.0842021724855044340E-19L
+#define LDBL_DIG	18
+#define LDBL_MIN_EXP	(-16381)
+#define LDBL_MIN	3.3621031431120935063E-4932L
+#define LDBL_MIN_10_EXP	(-4931)
+#define LDBL_MAX_EXP	16384
+#define LDBL_MAX	1.1897314953572317650E+4932L
+#define LDBL_MAX_10_EXP	4932
+#if __ISO_C_VISIBLE >= 2011
+#define	LDBL_TRUE_MIN	3.6451995318824746025E-4951L
+#define	LDBL_DECIMAL_DIG 21
+#define	LDBL_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#endif /* _MACHINE_FLOAT_H_ */


Property changes on: trunk/sys/x86/include/float.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/fpu.h
===================================================================
--- trunk/sys/x86/include/fpu.h	                        (rev 0)
+++ trunk/sys/x86/include/fpu.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,218 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)npx.h	5.3 (Berkeley) 1/18/91
+ * $FreeBSD: stable/10/sys/x86/include/fpu.h 279211 2015-02-23 18:38:41Z jhb $
+ */
+
+/*
+ * Floating Point Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef _X86_FPU_H_
+#define	_X86_FPU_H_
+
+/* Environment information of floating point unit. */
+struct env87 {
+	int32_t		en_cw;		/* control word (16bits) */
+	int32_t		en_sw;		/* status word (16bits) */
+	int32_t		en_tw;		/* tag word (16bits) */
+	int32_t		en_fip;		/* fp instruction pointer */
+	uint16_t	en_fcs;		/* fp code segment selector */
+	uint16_t	en_opcode;	/* opcode last executed (11 bits) */
+	int32_t		en_foo;		/* fp operand offset */
+	int32_t		en_fos;		/* fp operand segment selector */
+};
+
+/* Contents of each x87 floating point accumulator. */
+struct fpacc87 {
+	uint8_t		fp_bytes[10];
+};
+
+/* Floating point context. (i386 fnsave/frstor) */
+struct save87 {
+	struct env87	sv_env;		/* floating point control/status */
+	struct fpacc87	sv_ac[8];	/* accumulator contents, 0-7 */
+	uint8_t		sv_pad0[4];	/* saved status word (now unused) */
+	uint8_t		sv_pad[64];
+};
+
+/* Contents of each SSE extended accumulator. */
+struct xmmacc {
+	uint8_t		xmm_bytes[16];
+};
+
+/* Contents of the upper 16 bytes of each AVX extended accumulator. */
+struct ymmacc {
+	uint8_t		ymm_bytes[16];
+};
+
+/* Rename structs below depending on machine architecture. */
+#ifdef __i386__
+#define	__envxmm32	envxmm
+#else
+#define	__envxmm32	envxmm32
+#define	__envxmm64	envxmm
+#endif
+
+struct __envxmm32 {
+	uint16_t	en_cw;		/* control word (16bits) */
+	uint16_t	en_sw;		/* status word (16bits) */
+	uint16_t	en_tw;		/* tag word (16bits) */
+	uint16_t	en_opcode;	/* opcode last executed (11 bits) */
+	uint32_t	en_fip;		/* fp instruction pointer */
+	uint16_t	en_fcs;		/* fp code segment selector */
+	uint16_t	en_pad0;	/* padding */
+	uint32_t	en_foo;		/* fp operand offset */
+	uint16_t	en_fos;		/* fp operand segment selector */
+	uint16_t	en_pad1;	/* padding */
+	uint32_t	en_mxcsr;	/* SSE control/status register */
+	uint32_t	en_mxcsr_mask;	/* valid bits in mxcsr */
+};
+
+struct __envxmm64 {
+	uint16_t	en_cw;		/* control word (16bits) */
+	uint16_t	en_sw;		/* status word (16bits) */
+	uint8_t		en_tw;		/* tag word (8bits) */
+	uint8_t		en_zero;
+	uint16_t	en_opcode;	/* opcode last executed (11 bits ) */
+	uint64_t	en_rip;		/* fp instruction pointer */
+	uint64_t	en_rdp;		/* fp operand pointer */
+	uint32_t	en_mxcsr;	/* SSE control/status register */
+	uint32_t	en_mxcsr_mask;	/* valid bits in mxcsr */
+};
+
+/* Floating point context. (i386 fxsave/fxrstor) */
+struct savexmm {
+	struct __envxmm32	sv_env;
+	struct {
+		struct fpacc87	fp_acc;
+		uint8_t		fp_pad[6];      /* padding */
+	} sv_fp[8];
+	struct xmmacc		sv_xmm[8];
+	uint8_t			sv_pad[224];
+} __aligned(16);
+
+#ifdef __i386__
+union savefpu {
+	struct save87	sv_87;
+	struct savexmm	sv_xmm;
+};
+#else
+/* Floating point context. (amd64 fxsave/fxrstor) */
+struct savefpu {
+	struct __envxmm64	sv_env;
+	struct {
+		struct fpacc87	fp_acc;
+		uint8_t		fp_pad[6];	/* padding */
+	} sv_fp[8];
+	struct xmmacc		sv_xmm[16];
+	uint8_t			sv_pad[96];
+} __aligned(16);
+#endif
+
+struct xstate_hdr {
+	uint64_t	xstate_bv;
+	uint64_t	xstate_xcomp_bv;
+	uint8_t		xstate_rsrv0[8];
+	uint8_t		xstate_rsrv[40];
+};
+#define	XSTATE_XCOMP_BV_COMPACT	(1ULL << 63)
+
+struct savexmm_xstate {
+	struct xstate_hdr	sx_hd;
+	struct ymmacc		sx_ymm[16];
+};
+
+struct savexmm_ymm {
+	struct __envxmm32	sv_env;
+	struct {
+		struct fpacc87	fp_acc;
+		int8_t		fp_pad[6];	/* padding */
+	} sv_fp[8];
+	struct xmmacc		sv_xmm[16];
+	uint8_t			sv_pad[96];
+	struct savexmm_xstate	sv_xstate;
+} __aligned(64);
+
+struct savefpu_xstate {
+	struct xstate_hdr	sx_hd;
+	struct ymmacc		sx_ymm[16];
+};
+
+struct savefpu_ymm {
+	struct __envxmm64	sv_env;
+	struct {
+		struct fpacc87	fp_acc;
+		int8_t		fp_pad[6];	/* padding */
+	} sv_fp[8];
+	struct xmmacc		sv_xmm[16];
+	uint8_t			sv_pad[96];
+	struct savefpu_xstate	sv_xstate;
+} __aligned(64);
+
+#undef __envxmm32
+#undef __envxmm64
+
+/*
+ * The hardware default control word for i387's and later coprocessors is
+ * 0x37F, giving:
+ *
+ *	round to nearest
+ *	64-bit precision
+ *	all exceptions masked.
+ *
+ * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc
+ * because of the difference between memory and fpu register stack arguments.
+ * If its using an intermediate fpu register, it has 80/64 bits to work
+ * with.  If it uses memory, it has 64/53 bits to work with.  However,
+ * gcc is aware of this and goes to a fair bit of trouble to make the
+ * best use of it.
+ *
+ * This is mostly academic for AMD64, because the ABI prefers the use
+ * SSE2 based math.  For FreeBSD/amd64, we go with the default settings.
+ */
+#define	__INITIAL_FPUCW__	0x037F
+#define	__INITIAL_FPUCW_I386__	0x127F
+#define	__INITIAL_NPXCW__	__INITIAL_FPUCW_I386__
+#define	__INITIAL_MXCSR__	0x1F80
+#define	__INITIAL_MXCSR_MASK__	0xFFBF
+
+/*
+ * The current value of %xcr0 is saved in the sv_pad[] field of the FPU
+ * state in the NT_X86_XSTATE note in core dumps.  This offset is chosen
+ * to match the offset used by NT_X86_XSTATE in other systems.
+ */
+#define	X86_XSTATE_XCR0_OFFSET	464
+
+#endif /* !_X86_FPU_H_ */


Property changes on: trunk/sys/x86/include/fpu.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/frame.h
===================================================================
--- trunk/sys/x86/include/frame.h	                        (rev 0)
+++ trunk/sys/x86/include/frame.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,149 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)frame.h	5.2 (Berkeley) 1/18/91
+ * $FreeBSD: stable/10/sys/x86/include/frame.h 247047 2013-02-20 17:39:52Z kib $
+ */
+
+#ifndef _MACHINE_FRAME_H_
+#define _MACHINE_FRAME_H_ 1
+
+/*
+ * System stack frames.
+ */
+
+#ifdef __i386__
+/*
+ * Exception/Trap Stack Frame
+ */
+
+struct trapframe {
+	int	tf_fs;
+	int	tf_es;
+	int	tf_ds;
+	int	tf_edi;
+	int	tf_esi;
+	int	tf_ebp;
+	int	tf_isp;
+	int	tf_ebx;
+	int	tf_edx;
+	int	tf_ecx;
+	int	tf_eax;
+	int	tf_trapno;
+	/* below portion defined in 386 hardware */
+	int	tf_err;
+	int	tf_eip;
+	int	tf_cs;
+	int	tf_eflags;
+	/* below only when crossing rings (e.g. user to kernel) */
+	int	tf_esp;
+	int	tf_ss;
+};
+
+/* Superset of trap frame, for traps from virtual-8086 mode */
+
+struct trapframe_vm86 {
+	int	tf_fs;
+	int	tf_es;
+	int	tf_ds;
+	int	tf_edi;
+	int	tf_esi;
+	int	tf_ebp;
+	int	tf_isp;
+	int	tf_ebx;
+	int	tf_edx;
+	int	tf_ecx;
+	int	tf_eax;
+	int	tf_trapno;
+	/* below portion defined in 386 hardware */
+	int	tf_err;
+	int	tf_eip;
+	int	tf_cs;
+	int	tf_eflags;
+	/* below only when crossing rings (e.g. user to kernel) */
+	int	tf_esp;
+	int	tf_ss;
+	/* below only when switching out of VM86 mode */
+	int	tf_vm86_es;
+	int	tf_vm86_ds;
+	int	tf_vm86_fs;
+	int	tf_vm86_gs;
+};
+#endif /* __i386__ */
+
+#ifdef __amd64__
+/*
+ * Exception/Trap Stack Frame
+ *
+ * The ordering of this is specifically so that we can take first 6
+ * the syscall arguments directly from the beginning of the frame.
+ */
+
+struct trapframe {
+	register_t	tf_rdi;
+	register_t	tf_rsi;
+	register_t	tf_rdx;
+	register_t	tf_rcx;
+	register_t	tf_r8;
+	register_t	tf_r9;
+	register_t	tf_rax;
+	register_t	tf_rbx;
+	register_t	tf_rbp;
+	register_t	tf_r10;
+	register_t	tf_r11;
+	register_t	tf_r12;
+	register_t	tf_r13;
+	register_t	tf_r14;
+	register_t	tf_r15;
+	uint32_t	tf_trapno;
+	uint16_t	tf_fs;
+	uint16_t	tf_gs;
+	register_t	tf_addr;
+	uint32_t	tf_flags;
+	uint16_t	tf_es;
+	uint16_t	tf_ds;
+	/* below portion defined in hardware */
+	register_t	tf_err;
+	register_t	tf_rip;
+	register_t	tf_cs;
+	register_t	tf_rflags;
+	register_t	tf_rsp;
+	register_t	tf_ss;
+};
+
+#define	TF_HASSEGS	0x1
+#define	TF_HASBASES	0x2
+#define	TF_HASFPXSTATE	0x4
+#endif /* __amd64__ */
+
+#endif /* _MACHINE_FRAME_H_ */


Property changes on: trunk/sys/x86/include/frame.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/legacyvar.h
===================================================================
--- trunk/sys/x86/include/legacyvar.h	                        (rev 0)
+++ trunk/sys/x86/include/legacyvar.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,71 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter at 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: stable/10/sys/x86/include/legacyvar.h 280970 2015-04-01 21:48:54Z jhb $
+ */
+
+#ifndef _X86_LEGACYVAR_H_
+#define	_X86_LEGACYVAR_H_
+
+enum legacy_device_ivars {
+	LEGACY_IVAR_PCIDOMAIN,
+	LEGACY_IVAR_PCIBUS,
+	LEGACY_IVAR_PCISLOT,
+	LEGACY_IVAR_PCIFUNC
+};
+
+#define LEGACY_ACCESSOR(var, ivar, type)				\
+    __BUS_ACCESSOR(legacy, var, LEGACY, ivar, type)
+
+LEGACY_ACCESSOR(pcidomain,		PCIDOMAIN,	uint32_t)
+LEGACY_ACCESSOR(pcibus,			PCIBUS,		uint32_t)
+LEGACY_ACCESSOR(pcislot,		PCISLOT,	int)
+LEGACY_ACCESSOR(pcifunc,		PCIFUNC,	int)
+
+#undef LEGACY_ACCESSOR
+
+int	legacy_pcib_maxslots(device_t dev);
+uint32_t legacy_pcib_read_config(device_t dev, u_int bus, u_int slot,
+    u_int func, u_int reg, int bytes);
+int	legacy_pcib_read_ivar(device_t dev, device_t child, int which,
+    uintptr_t *result);
+void	legacy_pcib_write_config(device_t dev, u_int bus, u_int slot,
+    u_int func, u_int reg, uint32_t data, int bytes);
+int	legacy_pcib_write_ivar(device_t dev, device_t child, int which,
+    uintptr_t value);
+struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child,
+    int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
+int	legacy_pcib_adjust_resource(device_t dev, device_t child, int type,
+    struct resource *r, u_long start, u_long end);
+int	legacy_pcib_release_resource(device_t dev, device_t child, int type,
+    int rid, struct resource *r);
+int	legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count,
+    int maxcount, int *irqs);
+int	legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq);
+int	legacy_pcib_map_msi(device_t pcib, device_t dev, int irq,
+    uint64_t *addr, uint32_t *data);
+
+#endif /* !_X86_LEGACYVAR_H_ */


Property changes on: trunk/sys/x86/include/legacyvar.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/include/mca.h
===================================================================
--- trunk/sys/x86/include/mca.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/mca.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
  * Written by: John H. Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
  *
@@ -24,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/include/mca.h 283927 2015-06-02 19:20:39Z jhb $
  */
 
 #ifndef __X86_MCA_H__

Added: trunk/sys/x86/include/metadata.h
===================================================================
--- trunk/sys/x86/include/metadata.h	                        (rev 0)
+++ trunk/sys/x86/include/metadata.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,58 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2003 Peter Wemm <peter at 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: stable/10/sys/x86/include/metadata.h 294274 2016-01-18 15:52:07Z emaste $
+ */
+
+#ifndef _MACHINE_METADATA_H_
+#define	_MACHINE_METADATA_H_
+
+#define	MODINFOMD_SMAP		0x1001
+#define	MODINFOMD_SMAP_XATTR	0x1002
+#define	MODINFOMD_DTBP		0x1003
+#define	MODINFOMD_EFI_MAP	0x1004
+#define	MODINFOMD_EFI_FB	0x1005
+#define	MODINFOMD_MODULEP	0x1006
+
+struct efi_map_header {
+	uint64_t	memory_size;
+	uint64_t	descriptor_size;
+	uint32_t	descriptor_version;
+};
+
+struct efi_fb {
+	uint64_t	fb_addr;
+	uint64_t	fb_size;
+	uint32_t	fb_height;
+	uint32_t	fb_width;
+	uint32_t	fb_stride;
+	uint32_t	fb_mask_red;
+	uint32_t	fb_mask_green;
+	uint32_t	fb_mask_blue;
+	uint32_t	fb_mask_reserved;
+};
+
+#endif /* !_MACHINE_METADATA_H_ */


Property changes on: trunk/sys/x86/include/metadata.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/include/mptable.h
===================================================================
--- trunk/sys/x86/include/mptable.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/mptable.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1996, by Steve Passe
  * All rights reserved.
@@ -22,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/include/mptable.h 259837 2013-12-24 19:10:56Z jhb $
  */
 
 #ifndef __MACHINE_MPTABLE_H__
@@ -85,10 +86,10 @@
 	u_char  apic_id;
 	u_char  apic_version;
 	u_char  cpu_flags;
-	u_long  cpu_signature;
-	u_long  feature_flags;
-	u_long  reserved1;
-	u_long  reserved2;
+	u_int32_t cpu_signature;
+	u_int32_t feature_flags;
+	u_int32_t reserved1;
+	u_int32_t reserved2;
 }      *proc_entry_ptr;
 
 #define PROCENTRY_FLAG_EN	0x01

Added: trunk/sys/x86/include/ofw_machdep.h
===================================================================
--- trunk/sys/x86/include/ofw_machdep.h	                        (rev 0)
+++ trunk/sys/x86/include/ofw_machdep.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,43 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Juniper Networks, 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 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: stable/10/sys/x86/include/ofw_machdep.h 266084 2014-05-14 19:18:58Z ian $
+ */
+
+#ifndef _MACHINE_OFW_MACHDEP_H_
+#define _MACHINE_OFW_MACHDEP_H_
+
+#include <x86/bus.h>
+#include <vm/vm.h>
+
+typedef	uint32_t	cell_t;
+
+struct mem_region {
+	vm_offset_t	mr_start;
+	vm_size_t	mr_size;
+};
+
+#endif /* _MACHINE_OFW_MACHDEP_H_ */


Property changes on: trunk/sys/x86/include/ofw_machdep.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/include/pci_cfgreg.h
===================================================================
--- trunk/sys/x86/include/pci_cfgreg.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/pci_cfgreg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -23,7 +24,7 @@
  * (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$
+ * $FreeBSD: stable/10/sys/x86/include/pci_cfgreg.h 223440 2011-06-22 21:04:13Z jhb $
  *
  */
 

Added: trunk/sys/x86/include/psl.h
===================================================================
--- trunk/sys/x86/include/psl.h	                        (rev 0)
+++ trunk/sys/x86/include/psl.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,93 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)psl.h	5.2 (Berkeley) 1/18/91
+ * $FreeBSD: stable/10/sys/x86/include/psl.h 258559 2013-11-25 15:58:48Z emaste $
+ */
+
+#ifndef _MACHINE_PSL_H_
+#define	_MACHINE_PSL_H_
+
+/*
+ * 386 processor status longword.
+ */
+#define	PSL_C		0x00000001	/* carry bit */
+#define	PSL_PF		0x00000004	/* parity bit */
+#define	PSL_AF		0x00000010	/* bcd carry bit */
+#define	PSL_Z		0x00000040	/* zero bit */
+#define	PSL_N		0x00000080	/* negative bit */
+#define	PSL_T		0x00000100	/* trace enable bit */
+#define	PSL_I		0x00000200	/* interrupt enable bit */
+#define	PSL_D		0x00000400	/* string instruction direction bit */
+#define	PSL_V		0x00000800	/* overflow bit */
+#define	PSL_IOPL	0x00003000	/* i/o privilege level */
+#define	PSL_NT		0x00004000	/* nested task bit */
+#define	PSL_RF		0x00010000	/* resume flag bit */
+#define	PSL_VM		0x00020000	/* virtual 8086 mode bit */
+#define	PSL_AC		0x00040000	/* alignment checking */
+#define	PSL_VIF		0x00080000	/* virtual interrupt enable */
+#define	PSL_VIP		0x00100000	/* virtual interrupt pending */
+#define	PSL_ID		0x00200000	/* identification bit */
+
+/*
+ * The i486 manual says that we are not supposed to change reserved flags,
+ * but this is too much trouble since the reserved flags depend on the cpu
+ * and setting them to their historical values works in practice.
+ */
+#define	PSL_RESERVED_DEFAULT	0x00000002
+
+/*
+ * Initial flags for kernel and user mode.  The kernel later inherits
+ * PSL_I and some other flags from user mode.
+ */
+#define	PSL_KERNEL	PSL_RESERVED_DEFAULT
+#define	PSL_USER	(PSL_RESERVED_DEFAULT | PSL_I)
+
+/*
+ * Bits that can be changed in user mode on 486's.  We allow these bits
+ * to be changed using ptrace(), sigreturn() and procfs.  Setting PS_NT
+ * is undesirable but it may as well be allowed since users can inflict
+ * it on the kernel directly.  Changes to PSL_AC are silently ignored on
+ * 386's.
+ *
+ * Users are allowed to change the privileged flag PSL_RF.  The cpu sets PSL_RF
+ * in tf_eflags for faults.  Debuggers should sometimes set it there too.
+ * tf_eflags is kept in the signal context during signal handling and there is
+ * no other place to remember it, so the PSL_RF bit may be corrupted by the
+ * signal handler without us knowing.  Corruption of the PSL_RF bit at worst
+ * causes one more or one less debugger trap, so allowing it is fairly
+ * harmless.   
+ */
+#define	PSL_USERCHANGE (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_T \
+			| PSL_D | PSL_V | PSL_NT | PSL_RF | PSL_AC | PSL_ID)
+
+#endif /* !_MACHINE_PSL_H_ */


Property changes on: trunk/sys/x86/include/psl.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/ptrace.h
===================================================================
--- trunk/sys/x86/include/ptrace.h	                        (rev 0)
+++ trunk/sys/x86/include/ptrace.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,66 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)ptrace.h	8.1 (Berkeley) 6/11/93
+ * $FreeBSD: stable/10/sys/x86/include/ptrace.h 286311 2015-08-05 08:17:10Z kib $
+ */
+
+#ifndef _MACHINE_PTRACE_H_
+#define _MACHINE_PTRACE_H_
+
+#define	__HAVE_PTRACE_MACHDEP
+
+/*
+ * On amd64 (PT_FIRSTMACH + 0) and (PT_FIRSTMACH + 1) are old values for
+ * PT_GETXSTATE_OLD and PT_SETXSTATE_OLD.  They should not be (re)used.
+ */
+
+#ifdef __i386__
+#define	PT_GETXMMREGS	(PT_FIRSTMACH + 0)
+#define	PT_SETXMMREGS	(PT_FIRSTMACH + 1)
+#endif
+#ifdef _KERNEL
+#define	PT_GETXSTATE_OLD (PT_FIRSTMACH + 2)
+#define	PT_SETXSTATE_OLD (PT_FIRSTMACH + 3)
+#endif
+#define	PT_GETXSTATE_INFO (PT_FIRSTMACH + 4)
+#define	PT_GETXSTATE	(PT_FIRSTMACH + 5)
+#define	PT_SETXSTATE	(PT_FIRSTMACH + 6)
+#define	PT_GETFSBASE	(PT_FIRSTMACH + 7)
+#define	PT_SETFSBASE	(PT_FIRSTMACH + 8)
+#define	PT_GETGSBASE	(PT_FIRSTMACH + 9)
+#define	PT_SETGSBASE	(PT_FIRSTMACH + 10)
+
+/* Argument structure for PT_GETXSTATE_INFO. */
+struct ptrace_xstate_info {
+	uint64_t	xsave_mask;
+	uint32_t	xsave_len;
+};
+
+#endif


Property changes on: trunk/sys/x86/include/ptrace.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/reg.h
===================================================================
--- trunk/sys/x86/include/reg.h	                        (rev 0)
+++ trunk/sys/x86/include/reg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,258 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)reg.h	5.5 (Berkeley) 1/18/91
+ * $FreeBSD: stable/10/sys/x86/include/reg.h 283910 2015-06-02 14:54:53Z jhb $
+ */
+
+#ifndef _MACHINE_REG_H_
+#define	_MACHINE_REG_H_
+
+#include <machine/_types.h>
+
+#ifdef __i386__
+/*
+ * Indices for registers in `struct trapframe' and `struct regs'.
+ *
+ * This interface is deprecated.  In the kernel, it is only used in FPU
+ * emulators to convert from register numbers encoded in instructions to
+ * register values.  Everything else just accesses the relevant struct
+ * members.  In userland, debuggers tend to abuse this interface since
+ * they don't understand that `struct regs' is a struct.  I hope they have
+ * stopped accessing the registers in the trap frame via PT_{READ,WRITE}_U
+ * and we can stop supporting the user area soon.
+ */
+#define	tFS	(0)
+#define	tES	(1)
+#define	tDS	(2)
+#define	tEDI	(3)
+#define	tESI	(4)
+#define	tEBP	(5)
+#define	tISP	(6)
+#define	tEBX	(7)
+#define	tEDX	(8)
+#define	tECX	(9)
+#define	tEAX	(10)
+#define	tERR	(12)
+#define	tEIP	(13)
+#define	tCS	(14)
+#define	tEFLAGS	(15)
+#define	tESP	(16)
+#define	tSS	(17)
+
+/*
+ * Indices for registers in `struct regs' only.
+ *
+ * Some registers live in the pcb and are only in an "array" with the
+ * other registers in application interfaces that copy all the registers
+ * to or from a `struct regs'.
+ */
+#define	tGS	(18)
+#endif /* __i386__ */
+
+/* Rename the structs below depending on the machine architecture. */
+#ifdef	__i386__
+#define	__reg32		reg
+#define	__fpreg32	fpreg
+#define	__dbreg32	dbreg
+#else
+#define	__reg32		reg32
+#define	__reg64		reg
+#define	__fpreg32	fpreg32
+#define	__fpreg64	fpreg
+#define	__dbreg32	dbreg32
+#define	__dbreg64	dbreg
+#define	__HAVE_REG32
+#endif
+
+/*
+ * Register set accessible via /proc/$pid/regs and PT_{SET,GET}REGS.
+ */
+struct __reg32 {
+	__uint32_t	r_fs;
+	__uint32_t	r_es;
+	__uint32_t	r_ds;
+	__uint32_t	r_edi;
+	__uint32_t	r_esi;
+	__uint32_t	r_ebp;
+	__uint32_t	r_isp;
+	__uint32_t	r_ebx;
+	__uint32_t	r_edx;
+	__uint32_t	r_ecx;
+	__uint32_t	r_eax;
+	__uint32_t	r_trapno;
+	__uint32_t	r_err;
+	__uint32_t	r_eip;
+	__uint32_t	r_cs;
+	__uint32_t	r_eflags;
+	__uint32_t	r_esp;
+	__uint32_t	r_ss;
+	__uint32_t	r_gs;
+};
+
+struct __reg64 {
+	__int64_t	r_r15;
+	__int64_t	r_r14;
+	__int64_t	r_r13;
+	__int64_t	r_r12;
+	__int64_t	r_r11;
+	__int64_t	r_r10;
+	__int64_t	r_r9;
+	__int64_t	r_r8;
+	__int64_t	r_rdi;
+	__int64_t	r_rsi;
+	__int64_t	r_rbp;
+	__int64_t	r_rbx;
+	__int64_t	r_rdx;
+	__int64_t	r_rcx;
+	__int64_t	r_rax;
+	__uint32_t	r_trapno;
+	__uint16_t	r_fs;
+	__uint16_t	r_gs;
+	__uint32_t	r_err;
+	__uint16_t	r_es;
+	__uint16_t	r_ds;
+	__int64_t	r_rip;
+	__int64_t	r_cs;
+	__int64_t	r_rflags;
+	__int64_t	r_rsp;
+	__int64_t	r_ss;
+};
+
+/*
+ * Register set accessible via /proc/$pid/fpregs.
+ *
+ * XXX should get struct from fpu.h.  Here we give a slightly
+ * simplified struct.  This may be too much detail.  Perhaps
+ * an array of unsigned longs is best.
+ */
+struct __fpreg32 {
+	__uint32_t	fpr_env[7];
+	__uint8_t	fpr_acc[8][10];
+	__uint32_t	fpr_ex_sw;
+	__uint8_t	fpr_pad[64];
+};
+
+struct __fpreg64 {
+	__uint64_t	fpr_env[4];
+	__uint8_t	fpr_acc[8][16];
+	__uint8_t	fpr_xacc[16][16];
+	__uint64_t	fpr_spare[12];
+};
+
+/*
+ * Register set accessible via PT_GETXMMREGS (i386).
+ */
+struct xmmreg {
+	/*
+	 * XXX should get struct from npx.h.  Here we give a slightly
+	 * simplified struct.  This may be too much detail.  Perhaps
+	 * an array of unsigned longs is best.
+	 */
+	__uint32_t	xmm_env[8];
+	__uint8_t	xmm_acc[8][16];
+	__uint8_t	xmm_reg[8][16];
+	__uint8_t	xmm_pad[224];
+};
+
+/*
+ * Register set accessible via /proc/$pid/dbregs.
+ */
+struct __dbreg32 {
+	__uint32_t	dr[8];	/* debug registers */
+				/* Index 0-3: debug address registers */
+				/* Index 4-5: reserved */
+				/* Index 6: debug status */
+				/* Index 7: debug control */
+};
+
+struct __dbreg64 {
+	__uint64_t	dr[16];	/* debug registers */
+				/* Index 0-3: debug address registers */
+				/* Index 4-5: reserved */
+				/* Index 6: debug status */
+				/* Index 7: debug control */
+				/* Index 8-15: reserved */
+};
+
+#define	DBREG_DR7_LOCAL_ENABLE	0x01
+#define	DBREG_DR7_GLOBAL_ENABLE	0x02
+#define	DBREG_DR7_LEN_1		0x00	/* 1 byte length          */
+#define	DBREG_DR7_LEN_2		0x01
+#define	DBREG_DR7_LEN_4		0x03
+#define	DBREG_DR7_LEN_8		0x02
+#define	DBREG_DR7_EXEC		0x00	/* break on execute       */
+#define	DBREG_DR7_WRONLY	0x01	/* break on write         */
+#define	DBREG_DR7_RDWR		0x03	/* break on read or write */
+#define	DBREG_DR7_MASK(i)	\
+	((__u_register_t)(0xf) << ((i) * 4 + 16) | 0x3 << (i) * 2)
+#define	DBREG_DR7_SET(i, len, access, enable)				\
+	((__u_register_t)((len) << 2 | (access)) << ((i) * 4 + 16) | 	\
+	(enable) << (i) * 2)
+#define	DBREG_DR7_GD		0x2000
+#define	DBREG_DR7_ENABLED(d, i)	(((d) & 0x3 << (i) * 2) != 0)
+#define	DBREG_DR7_ACCESS(d, i)	((d) >> ((i) * 4 + 16) & 0x3)
+#define	DBREG_DR7_LEN(d, i)	((d) >> ((i) * 4 + 18) & 0x3)
+
+#define	DBREG_DRX(d,x)	((d)->dr[(x)])	/* reference dr0 - dr7 by
+					   register number */
+
+#undef __reg32
+#undef __reg64
+#undef __fpreg32
+#undef __fpreg64
+#undef __dbreg32
+#undef __dbreg64
+
+#ifdef _KERNEL
+/*
+ * XXX these interfaces are MI, so they should be declared in a MI place.
+ */
+int	fill_regs(struct thread *, struct reg *);
+int	fill_frame_regs(struct trapframe *, struct reg *);
+int	set_regs(struct thread *, struct reg *);
+int	fill_fpregs(struct thread *, struct fpreg *);
+int	set_fpregs(struct thread *, struct fpreg *);
+int	fill_dbregs(struct thread *, struct dbreg *);
+int	set_dbregs(struct thread *, struct dbreg *);
+#ifdef COMPAT_FREEBSD32
+int	fill_regs32(struct thread *, struct reg32 *);
+int	set_regs32(struct thread *, struct reg32 *);
+int	fill_fpregs32(struct thread *, struct fpreg32 *);
+int	set_fpregs32(struct thread *, struct fpreg32 *);
+int	fill_dbregs32(struct thread *, struct dbreg32 *);
+int	set_dbregs32(struct thread *, struct dbreg32 *);
+#endif
+#endif
+
+#endif /* !_MACHINE_REG_H_ */


Property changes on: trunk/sys/x86/include/reg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/segments.h
===================================================================
--- trunk/sys/x86/include/segments.h	                        (rev 0)
+++ trunk/sys/x86/include/segments.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,288 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)segments.h	7.1 (Berkeley) 5/9/91
+ * $FreeBSD: stable/10/sys/x86/include/segments.h 255040 2013-08-29 19:52:18Z gibbs $
+ */
+
+#ifndef _X86_SEGMENTS_H_
+#define	_X86_SEGMENTS_H_
+
+/*
+ * X86 Segmentation Data Structures and definitions
+ */
+
+/*
+ * Selectors
+ */
+#define	SEL_RPL_MASK	3		/* requester priv level */
+#define	ISPL(s)		((s)&3)		/* priority level of a selector */
+#ifdef XEN
+#define	SEL_KPL		1		/* kernel priority level */
+#else
+#define	SEL_KPL		0		/* kernel priority level */
+#endif
+#define	SEL_UPL		3		/* user priority level */
+#define	ISLDT(s)	((s)&SEL_LDT)	/* is it local or global */
+#define	SEL_LDT		4		/* local descriptor table */
+#define	IDXSEL(s)	(((s)>>3) & 0x1fff) /* index of selector */
+#define	LSEL(s,r)	(((s)<<3) | SEL_LDT | r) /* a local selector */
+#define	GSEL(s,r)	(((s)<<3) | r)	/* a global selector */
+
+/*
+ * User segment descriptors (%cs, %ds etc for i386 apps. 64 bit wide)
+ * For long-mode apps, %cs only has the conforming bit in sd_type, the sd_dpl,
+ * sd_p, sd_l and sd_def32 which must be zero).  %ds only has sd_p.
+ */
+struct segment_descriptor {
+	unsigned sd_lolimit:16;		/* segment extent (lsb) */
+	unsigned sd_lobase:24;		/* segment base address (lsb) */
+	unsigned sd_type:5;		/* segment type */
+	unsigned sd_dpl:2;		/* segment descriptor priority level */
+	unsigned sd_p:1;		/* segment descriptor present */
+	unsigned sd_hilimit:4;		/* segment extent (msb) */
+	unsigned sd_xx:2;		/* unused */
+	unsigned sd_def32:1;		/* default 32 vs 16 bit size */
+	unsigned sd_gran:1;		/* limit granularity (byte/page units)*/
+	unsigned sd_hibase:8;		/* segment base address  (msb) */
+} __packed;
+
+struct user_segment_descriptor {
+	unsigned sd_lolimit:16;		/* segment extent (lsb) */
+	unsigned sd_lobase:24;		/* segment base address (lsb) */
+	unsigned sd_type:5;		/* segment type */
+	unsigned sd_dpl:2;		/* segment descriptor priority level */
+	unsigned sd_p:1;		/* segment descriptor present */
+	unsigned sd_hilimit:4;		/* segment extent (msb) */
+	unsigned sd_xx:1;		/* unused */
+	unsigned sd_long:1;		/* long mode (cs only) */
+	unsigned sd_def32:1;		/* default 32 vs 16 bit size */
+	unsigned sd_gran:1;		/* limit granularity (byte/page units)*/
+	unsigned sd_hibase:8;		/* segment base address  (msb) */
+} __packed;
+
+#define	USD_GETBASE(sd)		(((sd)->sd_lobase) | (sd)->sd_hibase << 24)
+#define	USD_SETBASE(sd, b)	(sd)->sd_lobase = (b);	\
+				(sd)->sd_hibase = ((b) >> 24);
+#define	USD_GETLIMIT(sd)	(((sd)->sd_lolimit) | (sd)->sd_hilimit << 16)
+#define	USD_SETLIMIT(sd, l)	(sd)->sd_lolimit = (l);	\
+				(sd)->sd_hilimit = ((l) >> 16);
+
+#ifdef __i386__
+/*
+ * Gate descriptors (e.g. indirect descriptors)
+ */
+struct gate_descriptor {
+	unsigned gd_looffset:16;	/* gate offset (lsb) */
+	unsigned gd_selector:16;	/* gate segment selector */
+	unsigned gd_stkcpy:5;		/* number of stack wds to cpy */
+	unsigned gd_xx:3;		/* unused */
+	unsigned gd_type:5;		/* segment type */
+	unsigned gd_dpl:2;		/* segment descriptor priority level */
+	unsigned gd_p:1;		/* segment descriptor present */
+	unsigned gd_hioffset:16;	/* gate offset (msb) */
+} __packed;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+	struct segment_descriptor sd;
+	struct gate_descriptor gd;
+};
+#else
+/*
+ * Gate descriptors (e.g. indirect descriptors, trap, interrupt etc. 128 bit)
+ * Only interrupt and trap gates have gd_ist.
+ */
+struct gate_descriptor {
+	uint64_t gd_looffset:16;	/* gate offset (lsb) */
+	uint64_t gd_selector:16;	/* gate segment selector */
+	uint64_t gd_ist:3;		/* IST table index */
+	uint64_t gd_xx:5;		/* unused */
+	uint64_t gd_type:5;		/* segment type */
+	uint64_t gd_dpl:2;		/* segment descriptor priority level */
+	uint64_t gd_p:1;		/* segment descriptor present */
+	uint64_t gd_hioffset:48;	/* gate offset (msb) */
+	uint64_t sd_xx1:32;
+} __packed;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+	struct user_segment_descriptor sd;
+	struct gate_descriptor gd;
+};
+#endif
+
+	/* system segments and gate types */
+#define	SDT_SYSNULL	 0	/* system null */
+#define	SDT_SYS286TSS	 1	/* system 286 TSS available */
+#define	SDT_SYSLDT	 2	/* system local descriptor table */
+#define	SDT_SYS286BSY	 3	/* system 286 TSS busy */
+#define	SDT_SYS286CGT	 4	/* system 286 call gate */
+#define	SDT_SYSTASKGT	 5	/* system task gate */
+#define	SDT_SYS286IGT	 6	/* system 286 interrupt gate */
+#define	SDT_SYS286TGT	 7	/* system 286 trap gate */
+#define	SDT_SYSNULL2	 8	/* system null again */
+#define	SDT_SYS386TSS	 9	/* system 386 TSS available */
+#define	SDT_SYSTSS	 9	/* system available 64 bit TSS */
+#define	SDT_SYSNULL3	10	/* system null again */
+#define	SDT_SYS386BSY	11	/* system 386 TSS busy */
+#define	SDT_SYSBSY	11	/* system busy 64 bit TSS */
+#define	SDT_SYS386CGT	12	/* system 386 call gate */
+#define	SDT_SYSCGT	12	/* system 64 bit call gate */
+#define	SDT_SYSNULL4	13	/* system null again */
+#define	SDT_SYS386IGT	14	/* system 386 interrupt gate */
+#define	SDT_SYSIGT	14	/* system 64 bit interrupt gate */
+#define	SDT_SYS386TGT	15	/* system 386 trap gate */
+#define	SDT_SYSTGT	15	/* system 64 bit trap gate */
+
+	/* memory segment types */
+#define	SDT_MEMRO	16	/* memory read only */
+#define	SDT_MEMROA	17	/* memory read only accessed */
+#define	SDT_MEMRW	18	/* memory read write */
+#define	SDT_MEMRWA	19	/* memory read write accessed */
+#define	SDT_MEMROD	20	/* memory read only expand dwn limit */
+#define	SDT_MEMRODA	21	/* memory read only expand dwn limit accessed */
+#define	SDT_MEMRWD	22	/* memory read write expand dwn limit */
+#define	SDT_MEMRWDA	23	/* memory read write expand dwn limit accessed*/
+#define	SDT_MEME	24	/* memory execute only */
+#define	SDT_MEMEA	25	/* memory execute only accessed */
+#define	SDT_MEMER	26	/* memory execute read */
+#define	SDT_MEMERA	27	/* memory execute read accessed */
+#define	SDT_MEMEC	28	/* memory execute only conforming */
+#define	SDT_MEMEAC	29	/* memory execute only accessed conforming */
+#define	SDT_MEMERC	30	/* memory execute read conforming */
+#define	SDT_MEMERAC	31	/* memory execute read accessed conforming */
+
+/*
+ * Size of IDT table
+ */
+#define	NIDT		256	/* 32 reserved, 0x80 syscall, most are h/w */
+#define	NRSVIDT		32	/* reserved entries for cpu exceptions */
+
+/*
+ * Entries in the Interrupt Descriptor Table (IDT)
+ */
+#define	IDT_DE		0	/* #DE: Divide Error */
+#define	IDT_DB		1	/* #DB: Debug */
+#define	IDT_NMI		2	/* Nonmaskable External Interrupt */
+#define	IDT_BP		3	/* #BP: Breakpoint */
+#define	IDT_OF		4	/* #OF: Overflow */
+#define	IDT_BR		5	/* #BR: Bound Range Exceeded */
+#define	IDT_UD		6	/* #UD: Undefined/Invalid Opcode */
+#define	IDT_NM		7	/* #NM: No Math Coprocessor */
+#define	IDT_DF		8	/* #DF: Double Fault */
+#define	IDT_FPUGP	9	/* Coprocessor Segment Overrun */
+#define	IDT_TS		10	/* #TS: Invalid TSS */
+#define	IDT_NP		11	/* #NP: Segment Not Present */
+#define	IDT_SS		12	/* #SS: Stack Segment Fault */
+#define	IDT_GP		13	/* #GP: General Protection Fault */
+#define	IDT_PF		14	/* #PF: Page Fault */
+#define	IDT_MF		16	/* #MF: FPU Floating-Point Error */
+#define	IDT_AC		17	/* #AC: Alignment Check */
+#define	IDT_MC		18	/* #MC: Machine Check */
+#define	IDT_XF		19	/* #XF: SIMD Floating-Point Exception */
+#define	IDT_IO_INTS	NRSVIDT	/* Base of IDT entries for I/O interrupts. */
+#define	IDT_SYSCALL	0x80	/* System Call Interrupt Vector */
+#define	IDT_DTRACE_RET	0x92	/* DTrace pid provider Interrupt Vector */
+#define	IDT_EVTCHN	0x93	/* Xen HVM Event Channel Interrupt Vector */
+
+#if defined(__i386__) || defined(__ia64__)
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ * Note that each 4 entries share a single 32 byte L1 cache line.
+ * Some of the fast syscall instructions require a specific order here.
+ */
+#define	GNULL_SEL	0	/* Null Descriptor */
+#define	GPRIV_SEL	1	/* SMP Per-Processor Private Data */
+#define	GUFS_SEL	2	/* User %fs Descriptor (order critical: 1) */
+#define	GUGS_SEL	3	/* User %gs Descriptor (order critical: 2) */
+#define	GCODE_SEL	4	/* Kernel Code Descriptor (order critical: 1) */
+#define	GDATA_SEL	5	/* Kernel Data Descriptor (order critical: 2) */
+#define	GUCODE_SEL	6	/* User Code Descriptor (order critical: 3) */
+#define	GUDATA_SEL	7	/* User Data Descriptor (order critical: 4) */
+#define	GBIOSLOWMEM_SEL	8	/* BIOS low memory access (must be entry 8) */
+#define	GPROC0_SEL	9	/* Task state process slot zero and up */
+#define	GLDT_SEL	10	/* Default User LDT */
+#define	GUSERLDT_SEL	11	/* User LDT */
+#define	GPANIC_SEL	12	/* Task state to consider panic from */
+#define	GBIOSCODE32_SEL	13	/* BIOS interface (32bit Code) */
+#define	GBIOSCODE16_SEL	14	/* BIOS interface (16bit Code) */
+#define	GBIOSDATA_SEL	15	/* BIOS interface (Data) */
+#define	GBIOSUTIL_SEL	16	/* BIOS interface (Utility) */
+#define	GBIOSARGS_SEL	17	/* BIOS interface (Arguments) */
+#define	GNDIS_SEL	18	/* For the NDIS layer */
+#ifdef XEN
+#define	NGDT		9
+#else
+#define	NGDT		19
+#endif
+
+/*
+ * Entries in the Local Descriptor Table (LDT)
+ */
+#define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
+#define	LSYS5SIGR_SEL	1
+#define	L43BSDCALLS_SEL	2	/* notyet */
+#define	LUCODE_SEL	3
+#define	LSOL26CALLS_SEL	4	/* Solaris >= 2.6 system call gate */
+#define	LUDATA_SEL	5
+/* separate stack, es,fs,gs sels ? */
+/* #define	LPOSIXCALLS_SEL	5*/	/* notyet */
+#define	LBSDICALLS_SEL	16	/* BSDI system call gate */
+#define	NLDT		(LBSDICALLS_SEL + 1)
+
+#else /* !__i386__ && !__ia64__ */
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ */
+#define	GNULL_SEL	0	/* Null Descriptor */
+#define	GNULL2_SEL	1	/* Null Descriptor */
+#define	GUFS32_SEL	2	/* User 32 bit %fs Descriptor */
+#define	GUGS32_SEL	3	/* User 32 bit %gs Descriptor */
+#define	GCODE_SEL	4	/* Kernel Code Descriptor */
+#define	GDATA_SEL	5	/* Kernel Data Descriptor */
+#define	GUCODE32_SEL	6	/* User 32 bit code Descriptor */
+#define	GUDATA_SEL	7	/* User 32/64 bit Data Descriptor */
+#define	GUCODE_SEL	8	/* User 64 bit Code Descriptor */
+#define	GPROC0_SEL	9	/* TSS for entering kernel etc */
+/* slot 10 is second half of GPROC0_SEL */
+#define	GUSERLDT_SEL	11	/* LDT */
+/* slot 12 is second half of GUSERLDT_SEL */
+#define	NGDT 		13
+#endif /* __i386__ || __ia64__ */
+
+#endif /* !_X86_SEGMENTS_H_ */


Property changes on: trunk/sys/x86/include/segments.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/setjmp.h
===================================================================
--- trunk/sys/x86/include/setjmp.h	                        (rev 0)
+++ trunk/sys/x86/include/setjmp.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,51 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1998 John Birrell <jb at cimlogic.com.au>.
+ * 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.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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: stable/10/sys/x86/include/setjmp.h 232275 2012-02-28 22:17:52Z tijl $
+ */
+
+#ifndef _MACHINE_SETJMP_H_
+#define	_MACHINE_SETJMP_H_
+
+#include <sys/cdefs.h>
+
+#define	_JBLEN	12		/* Size of the jmp_buf on AMD64. */
+
+/*
+ * jmp_buf and sigjmp_buf are encapsulated in different structs to force
+ * compile-time diagnostics for mismatches.  The structs are the same
+ * internally to avoid some run-time errors for mismatches.
+ */
+#if __BSD_VISIBLE || __POSIX_VISIBLE || __XSI_VISIBLE
+typedef	struct _sigjmp_buf { long _sjb[_JBLEN]; } sigjmp_buf[1];
+#endif
+
+typedef	struct _jmp_buf { long _jb[_JBLEN]; } jmp_buf[1];
+
+#endif /* !_MACHINE_SETJMP_H_ */


Property changes on: trunk/sys/x86/include/setjmp.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/sigframe.h
===================================================================
--- trunk/sys/x86/include/sigframe.h	                        (rev 0)
+++ trunk/sys/x86/include/sigframe.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,73 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1999 Marcel Moolenaar
+ * 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 
+ *    in this position and unchanged.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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: stable/10/sys/x86/include/sigframe.h 247047 2013-02-20 17:39:52Z kib $
+ */
+
+#ifndef _X86_SIGFRAME_H_
+#define	_X86_SIGFRAME_H_
+
+/*
+ * Signal frames, arguments passed to application signal handlers.
+ */
+
+#ifdef __i386__
+struct sigframe {
+	/*
+	 * The first four members may be used by applications.
+	 *
+	 * NOTE: The 4th argument is undocumented, ill commented
+	 * on and seems to be somewhat BSD "standard".  Handlers
+	 * installed with sigvec may be using it.
+	 */
+	register_t	sf_signum;
+	register_t	sf_siginfo;	/* code or pointer to sf_si */
+	register_t	sf_ucontext;	/* points to sf_uc */
+	register_t	sf_addr;	/* undocumented 4th arg */
+
+	union {
+		__siginfohandler_t	*sf_action;
+		__sighandler_t		*sf_handler;
+	} sf_ahu;
+	ucontext_t	sf_uc;		/* = *sf_ucontext */
+	siginfo_t	sf_si;		/* = *sf_siginfo (SA_SIGINFO case) */
+};
+#endif /* __i386__ */
+
+#ifdef __amd64__
+struct sigframe {
+	union {
+		__siginfohandler_t	*sf_action;
+		__sighandler_t		*sf_handler;
+	} sf_ahu;
+	ucontext_t	sf_uc;		/* = *sf_ucontext */
+	siginfo_t	sf_si;		/* = *sf_siginfo (SA_SIGINFO case) */
+};
+#endif /* __amd64__ */
+
+#endif /* _X86_SIGFRAME_H_ */


Property changes on: trunk/sys/x86/include/sigframe.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/signal.h
===================================================================
--- trunk/sys/x86/include/signal.h	                        (rev 0)
+++ trunk/sys/x86/include/signal.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,168 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1986, 1989, 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2003 Peter Wemm.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)signal.h	8.1 (Berkeley) 6/11/93
+ * $FreeBSD: stable/10/sys/x86/include/signal.h 247047 2013-02-20 17:39:52Z kib $
+ */
+
+#ifndef _X86_SIGNAL_H
+#define	_X86_SIGNAL_H 1
+
+/*
+ * Machine-dependent signal definitions
+ */
+
+#include <sys/cdefs.h>
+#include <sys/_sigset.h>
+
+#if __BSD_VISIBLE
+#include <machine/trap.h>	/* codes for SIGILL, SIGFPE */
+#endif
+
+#ifdef __i386__
+typedef int sig_atomic_t;
+
+#if __BSD_VISIBLE
+struct sigcontext {
+	struct __sigset sc_mask;	/* signal mask to restore */
+	int	sc_onstack;		/* sigstack state to restore */
+	int	sc_gs;			/* machine state (struct trapframe) */
+	int	sc_fs;
+	int	sc_es;
+	int	sc_ds;
+	int	sc_edi;
+	int	sc_esi;
+	int	sc_ebp;
+	int	sc_isp;
+	int	sc_ebx;
+	int	sc_edx;
+	int	sc_ecx;
+	int	sc_eax;
+	int	sc_trapno;
+	int	sc_err;
+	int	sc_eip;
+	int	sc_cs;
+	int	sc_efl;
+	int	sc_esp;
+	int	sc_ss;
+	int	sc_len;			/* sizeof(mcontext_t) */
+	/*
+	 * See <machine/ucontext.h> and <machine/npx.h> for
+	 * the following fields.
+	 */
+	int	sc_fpformat;
+	int	sc_ownedfp;
+	int	sc_flags;
+	int	sc_fpstate[128] __aligned(16);
+
+	int	sc_fsbase;
+	int	sc_gsbase;
+
+	int	sc_xfpustate;
+	int	sc_xfpustate_len;
+
+	int	sc_spare2[4];
+};
+
+#define	sc_sp		sc_esp
+#define	sc_fp		sc_ebp
+#define	sc_pc		sc_eip
+#define	sc_ps		sc_efl
+#define	sc_eflags	sc_efl
+
+#endif /* __BSD_VISIBLE */
+#endif /* __i386__ */
+
+#ifdef __amd64__
+typedef long sig_atomic_t;
+
+#if __BSD_VISIBLE
+/*
+ * Information pushed on stack when a signal is delivered.
+ * This is used by the kernel to restore state following
+ * execution of the signal handler.  It is also made available
+ * to the handler to allow it to restore state properly if
+ * a non-standard exit is performed.
+ *
+ * The sequence of the fields/registers after sc_mask in struct
+ * sigcontext must match those in mcontext_t and struct trapframe.
+ */
+struct sigcontext {
+	struct __sigset sc_mask;	/* signal mask to restore */
+	long	sc_onstack;		/* sigstack state to restore */
+	long	sc_rdi;		/* machine state (struct trapframe) */
+	long	sc_rsi;
+	long	sc_rdx;
+	long	sc_rcx;
+	long	sc_r8;
+	long	sc_r9;
+	long	sc_rax;
+	long	sc_rbx;
+	long	sc_rbp;
+	long	sc_r10;
+	long	sc_r11;
+	long	sc_r12;
+	long	sc_r13;
+	long	sc_r14;
+	long	sc_r15;
+	int	sc_trapno;
+	short	sc_fs;
+	short	sc_gs;
+	long	sc_addr;
+	int	sc_flags;
+	short	sc_es;
+	short	sc_ds;
+	long	sc_err;
+	long	sc_rip;
+	long	sc_cs;
+	long	sc_rflags;
+	long	sc_rsp;
+	long	sc_ss;
+	long	sc_len;			/* sizeof(mcontext_t) */
+	/*
+	 * See <machine/ucontext.h> and <machine/fpu.h> for the following
+	 * fields.
+	 */
+	long	sc_fpformat;
+	long	sc_ownedfp;
+	long	sc_fpstate[64] __aligned(16);
+
+	long	sc_fsbase;
+	long	sc_gsbase;
+
+	long	sc_xfpustate;
+	long	sc_xfpustate_len;
+
+	long	sc_spare[4];
+};
+#endif /* __BSD_VISIBLE */
+#endif /* __amd64__ */
+
+#endif


Property changes on: trunk/sys/x86/include/signal.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/specialreg.h
===================================================================
--- trunk/sys/x86/include/specialreg.h	                        (rev 0)
+++ trunk/sys/x86/include/specialreg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,872 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)specialreg.h	7.1 (Berkeley) 5/9/91
+ * $FreeBSD: stable/10/sys/x86/include/specialreg.h 315928 2017-03-25 05:09:03Z grehan $
+ */
+
+#ifndef _MACHINE_SPECIALREG_H_
+#define	_MACHINE_SPECIALREG_H_
+
+/*
+ * Bits in 386 special registers:
+ */
+#define	CR0_PE	0x00000001	/* Protected mode Enable */
+#define	CR0_MP	0x00000002	/* "Math" (fpu) Present */
+#define	CR0_EM	0x00000004	/* EMulate FPU instructions. (trap ESC only) */
+#define	CR0_TS	0x00000008	/* Task Switched (if MP, trap ESC and WAIT) */
+#define	CR0_PG	0x80000000	/* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+#define	CR0_NE	0x00000020	/* Numeric Error enable (EX16 vs IRQ13) */
+#define	CR0_WP	0x00010000	/* Write Protect (honor page protect in
+							   all modes) */
+#define	CR0_AM	0x00040000	/* Alignment Mask (set to enable AC flag) */
+#define	CR0_NW  0x20000000	/* Not Write-through */
+#define	CR0_CD  0x40000000	/* Cache Disable */
+
+#define	CR3_PCID_SAVE 0x8000000000000000
+
+/*
+ * Bits in PPro special registers
+ */
+#define	CR4_VME	0x00000001	/* Virtual 8086 mode extensions */
+#define	CR4_PVI	0x00000002	/* Protected-mode virtual interrupts */
+#define	CR4_TSD	0x00000004	/* Time stamp disable */
+#define	CR4_DE	0x00000008	/* Debugging extensions */
+#define	CR4_PSE	0x00000010	/* Page size extensions */
+#define	CR4_PAE	0x00000020	/* Physical address extension */
+#define	CR4_MCE	0x00000040	/* Machine check enable */
+#define	CR4_PGE	0x00000080	/* Page global enable */
+#define	CR4_PCE	0x00000100	/* Performance monitoring counter enable */
+#define	CR4_FXSR 0x00000200	/* Fast FPU save/restore used by OS */
+#define	CR4_XMM	0x00000400	/* enable SIMD/MMX2 to use except 16 */
+#define	CR4_VMXE 0x00002000	/* enable VMX operation (Intel-specific) */
+#define	CR4_FSGSBASE 0x00010000	/* Enable FS/GS BASE accessing instructions */
+#define	CR4_PCIDE 0x00020000	/* Enable Context ID */
+#define	CR4_XSAVE 0x00040000	/* XSETBV/XGETBV */
+#define	CR4_SMEP 0x00100000	/* Supervisor-Mode Execution Prevention */
+
+/*
+ * Bits in AMD64 special registers.  EFER is 64 bits wide.
+ */
+#define	EFER_SCE 0x000000001	/* System Call Extensions (R/W) */
+#define	EFER_LME 0x000000100	/* Long mode enable (R/W) */
+#define	EFER_LMA 0x000000400	/* Long mode active (R) */
+#define	EFER_NXE 0x000000800	/* PTE No-Execute bit enable (R/W) */
+#define	EFER_SVM 0x000001000	/* SVM enable bit for AMD, reserved for Intel */
+#define	EFER_LMSLE 0x000002000	/* Long Mode Segment Limit Enable */
+#define	EFER_FFXSR 0x000004000	/* Fast FXSAVE/FSRSTOR */
+#define	EFER_TCE   0x000008000	/* Translation Cache Extension */
+
+/*
+ * Intel Extended Features registers
+ */
+#define	XCR0	0		/* XFEATURE_ENABLED_MASK register */
+
+#define	XFEATURE_ENABLED_X87		0x00000001
+#define	XFEATURE_ENABLED_SSE		0x00000002
+#define	XFEATURE_ENABLED_YMM_HI128	0x00000004
+#define	XFEATURE_ENABLED_AVX		XFEATURE_ENABLED_YMM_HI128
+#define	XFEATURE_ENABLED_BNDREGS	0x00000008
+#define	XFEATURE_ENABLED_BNDCSR		0x00000010
+#define	XFEATURE_ENABLED_OPMASK		0x00000020
+#define	XFEATURE_ENABLED_ZMM_HI256	0x00000040
+#define	XFEATURE_ENABLED_HI16_ZMM	0x00000080
+
+#define	XFEATURE_AVX					\
+    (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX)
+#define	XFEATURE_AVX512						\
+    (XFEATURE_ENABLED_OPMASK | XFEATURE_ENABLED_ZMM_HI256 |	\
+    XFEATURE_ENABLED_HI16_ZMM)
+#define	XFEATURE_MPX					\
+    (XFEATURE_ENABLED_BNDREGS | XFEATURE_ENABLED_BNDCSR)
+
+/*
+ * CPUID instruction features register
+ */
+#define	CPUID_FPU	0x00000001
+#define	CPUID_VME	0x00000002
+#define	CPUID_DE	0x00000004
+#define	CPUID_PSE	0x00000008
+#define	CPUID_TSC	0x00000010
+#define	CPUID_MSR	0x00000020
+#define	CPUID_PAE	0x00000040
+#define	CPUID_MCE	0x00000080
+#define	CPUID_CX8	0x00000100
+#define	CPUID_APIC	0x00000200
+#define	CPUID_B10	0x00000400
+#define	CPUID_SEP	0x00000800
+#define	CPUID_MTRR	0x00001000
+#define	CPUID_PGE	0x00002000
+#define	CPUID_MCA	0x00004000
+#define	CPUID_CMOV	0x00008000
+#define	CPUID_PAT	0x00010000
+#define	CPUID_PSE36	0x00020000
+#define	CPUID_PSN	0x00040000
+#define	CPUID_CLFSH	0x00080000
+#define	CPUID_B20	0x00100000
+#define	CPUID_DS	0x00200000
+#define	CPUID_ACPI	0x00400000
+#define	CPUID_MMX	0x00800000
+#define	CPUID_FXSR	0x01000000
+#define	CPUID_SSE	0x02000000
+#define	CPUID_XMM	0x02000000
+#define	CPUID_SSE2	0x04000000
+#define	CPUID_SS	0x08000000
+#define	CPUID_HTT	0x10000000
+#define	CPUID_TM	0x20000000
+#define	CPUID_IA64	0x40000000
+#define	CPUID_PBE	0x80000000
+
+#define	CPUID2_SSE3	0x00000001
+#define	CPUID2_PCLMULQDQ 0x00000002
+#define	CPUID2_DTES64	0x00000004
+#define	CPUID2_MON	0x00000008
+#define	CPUID2_DS_CPL	0x00000010
+#define	CPUID2_VMX	0x00000020
+#define	CPUID2_SMX	0x00000040
+#define	CPUID2_EST	0x00000080
+#define	CPUID2_TM2	0x00000100
+#define	CPUID2_SSSE3	0x00000200
+#define	CPUID2_CNXTID	0x00000400
+#define	CPUID2_SDBG	0x00000800
+#define	CPUID2_FMA	0x00001000
+#define	CPUID2_CX16	0x00002000
+#define	CPUID2_XTPR	0x00004000
+#define	CPUID2_PDCM	0x00008000
+#define	CPUID2_PCID	0x00020000
+#define	CPUID2_DCA	0x00040000
+#define	CPUID2_SSE41	0x00080000
+#define	CPUID2_SSE42	0x00100000
+#define	CPUID2_X2APIC	0x00200000
+#define	CPUID2_MOVBE	0x00400000
+#define	CPUID2_POPCNT	0x00800000
+#define	CPUID2_TSCDLT	0x01000000
+#define	CPUID2_AESNI	0x02000000
+#define	CPUID2_XSAVE	0x04000000
+#define	CPUID2_OSXSAVE	0x08000000
+#define	CPUID2_AVX	0x10000000
+#define	CPUID2_F16C	0x20000000
+#define	CPUID2_RDRAND	0x40000000
+#define	CPUID2_HV	0x80000000
+
+/*
+ * Important bits in the Thermal and Power Management flags
+ * CPUID.6 EAX and ECX.
+ */
+#define	CPUTPM1_SENSOR	0x00000001
+#define	CPUTPM1_TURBO	0x00000002
+#define	CPUTPM1_ARAT	0x00000004
+#define	CPUTPM2_EFFREQ	0x00000001
+
+/*
+ * Important bits in the AMD extended cpuid flags
+ */
+#define	AMDID_SYSCALL	0x00000800
+#define	AMDID_MP	0x00080000
+#define	AMDID_NX	0x00100000
+#define	AMDID_EXT_MMX	0x00400000
+#define	AMDID_FFXSR	0x02000000
+#define	AMDID_PAGE1GB	0x04000000
+#define	AMDID_RDTSCP	0x08000000
+#define	AMDID_LM	0x20000000
+#define	AMDID_EXT_3DNOW	0x40000000
+#define	AMDID_3DNOW	0x80000000
+
+#define	AMDID2_LAHF	0x00000001
+#define	AMDID2_CMP	0x00000002
+#define	AMDID2_SVM	0x00000004
+#define	AMDID2_EXT_APIC	0x00000008
+#define	AMDID2_CR8	0x00000010
+#define	AMDID2_ABM	0x00000020
+#define	AMDID2_SSE4A	0x00000040
+#define	AMDID2_MAS	0x00000080
+#define	AMDID2_PREFETCH	0x00000100
+#define	AMDID2_OSVW	0x00000200
+#define	AMDID2_IBS	0x00000400
+#define	AMDID2_XOP	0x00000800
+#define	AMDID2_SKINIT	0x00001000
+#define	AMDID2_WDT	0x00002000
+#define	AMDID2_LWP	0x00008000
+#define	AMDID2_FMA4	0x00010000
+#define	AMDID2_TCE	0x00020000
+#define	AMDID2_NODE_ID	0x00080000
+#define	AMDID2_TBM	0x00200000
+#define	AMDID2_TOPOLOGY	0x00400000
+#define	AMDID2_PCXC	0x00800000
+#define	AMDID2_PNXC	0x01000000
+#define	AMDID2_DBE	0x04000000
+#define	AMDID2_PTSC	0x08000000
+#define	AMDID2_PTSCEL2I	0x10000000
+#define	AMDID2_MWAITX	0x20000000
+
+/*
+ * CPUID instruction 1 eax info
+ */
+#define	CPUID_STEPPING		0x0000000f
+#define	CPUID_MODEL		0x000000f0
+#define	CPUID_FAMILY		0x00000f00
+#define	CPUID_EXT_MODEL		0x000f0000
+#define	CPUID_EXT_FAMILY	0x0ff00000
+#ifdef __i386__
+#define	CPUID_TO_MODEL(id) \
+    ((((id) & CPUID_MODEL) >> 4) | \
+    ((((id) & CPUID_FAMILY) >= 0x600) ? \
+    (((id) & CPUID_EXT_MODEL) >> 12) : 0))
+#define	CPUID_TO_FAMILY(id) \
+    ((((id) & CPUID_FAMILY) >> 8) + \
+    ((((id) & CPUID_FAMILY) == 0xf00) ? \
+    (((id) & CPUID_EXT_FAMILY) >> 20) : 0))
+#else
+#define	CPUID_TO_MODEL(id) \
+    ((((id) & CPUID_MODEL) >> 4) | \
+    (((id) & CPUID_EXT_MODEL) >> 12))
+#define	CPUID_TO_FAMILY(id) \
+    ((((id) & CPUID_FAMILY) >> 8) + \
+    (((id) & CPUID_EXT_FAMILY) >> 20))
+#endif
+
+/*
+ * CPUID instruction 1 ebx info
+ */
+#define	CPUID_BRAND_INDEX	0x000000ff
+#define	CPUID_CLFUSH_SIZE	0x0000ff00
+#define	CPUID_HTT_CORES		0x00ff0000
+#define	CPUID_LOCAL_APIC_ID	0xff000000
+
+/*
+ * CPUID instruction 5 info
+ */
+#define	CPUID5_MON_MIN_SIZE	0x0000ffff	/* eax */
+#define	CPUID5_MON_MAX_SIZE	0x0000ffff	/* ebx */
+#define	CPUID5_MON_MWAIT_EXT	0x00000001	/* ecx */
+#define	CPUID5_MWAIT_INTRBREAK	0x00000002	/* ecx */
+
+/*
+ * MWAIT cpu power states.  Lower 4 bits are sub-states.
+ */
+#define	MWAIT_C0	0xf0
+#define	MWAIT_C1	0x00
+#define	MWAIT_C2	0x10
+#define	MWAIT_C3	0x20
+#define	MWAIT_C4	0x30
+
+/*
+ * MWAIT extensions.
+ */
+/* Interrupt breaks MWAIT even when masked. */
+#define	MWAIT_INTRBREAK		0x00000001
+
+/*
+ * CPUID instruction 6 ecx info
+ */
+#define	CPUID_PERF_STAT		0x00000001
+#define	CPUID_PERF_BIAS		0x00000008
+
+/* 
+ * CPUID instruction 0xb ebx info.
+ */
+#define	CPUID_TYPE_INVAL	0
+#define	CPUID_TYPE_SMT		1
+#define	CPUID_TYPE_CORE		2
+
+/*
+ * CPUID instruction 0xd Processor Extended State Enumeration Sub-leaf 1
+ */
+#define	CPUID_EXTSTATE_XSAVEOPT	0x00000001
+#define	CPUID_EXTSTATE_XSAVEC	0x00000002
+#define	CPUID_EXTSTATE_XINUSE	0x00000004
+#define	CPUID_EXTSTATE_XSAVES	0x00000008
+
+/*
+ * AMD extended function 8000_0007h edx info
+ */
+#define	AMDPM_TS		0x00000001
+#define	AMDPM_FID		0x00000002
+#define	AMDPM_VID		0x00000004
+#define	AMDPM_TTP		0x00000008
+#define	AMDPM_TM		0x00000010
+#define	AMDPM_STC		0x00000020
+#define	AMDPM_100MHZ_STEPS	0x00000040
+#define	AMDPM_HW_PSTATE		0x00000080
+#define	AMDPM_TSC_INVARIANT	0x00000100
+#define	AMDPM_CPB		0x00000200
+
+/*
+ * AMD extended function 8000_0008h ecx info
+ */
+#define	AMDID_CMP_CORES		0x000000ff
+#define	AMDID_COREID_SIZE	0x0000f000
+#define	AMDID_COREID_SIZE_SHIFT	12
+
+/*
+ * CPUID instruction 7 Structured Extended Features, leaf 0 ebx info
+ */
+#define	CPUID_STDEXT_FSGSBASE	0x00000001
+#define	CPUID_STDEXT_TSC_ADJUST	0x00000002
+#define	CPUID_STDEXT_SGX	0x00000004
+#define	CPUID_STDEXT_BMI1	0x00000008
+#define	CPUID_STDEXT_HLE	0x00000010
+#define	CPUID_STDEXT_AVX2	0x00000020
+#define	CPUID_STDEXT_FDP_EXC	0x00000040
+#define	CPUID_STDEXT_SMEP	0x00000080
+#define	CPUID_STDEXT_BMI2	0x00000100
+#define	CPUID_STDEXT_ERMS	0x00000200
+#define	CPUID_STDEXT_INVPCID	0x00000400
+#define	CPUID_STDEXT_RTM	0x00000800
+#define	CPUID_STDEXT_PQM	0x00001000
+#define	CPUID_STDEXT_NFPUSG	0x00002000
+#define	CPUID_STDEXT_MPX	0x00004000
+#define	CPUID_STDEXT_PQE	0x00008000
+#define	CPUID_STDEXT_AVX512F	0x00010000
+#define	CPUID_STDEXT_RDSEED	0x00040000
+#define	CPUID_STDEXT_ADX	0x00080000
+#define	CPUID_STDEXT_SMAP	0x00100000
+#define	CPUID_STDEXT_CLFLUSHOPT	0x00800000
+#define	CPUID_STDEXT_PROCTRACE	0x02000000
+#define	CPUID_STDEXT_AVX512PF	0x04000000
+#define	CPUID_STDEXT_AVX512ER	0x08000000
+#define	CPUID_STDEXT_AVX512CD	0x10000000
+#define	CPUID_STDEXT_SHA	0x20000000
+
+/*
+ * CPUID instruction 7 Structured Extended Features, leaf 0 ecx info
+ */
+#define	CPUID_STDEXT2_PREFETCHWT1 0x00000001
+#define	CPUID_STDEXT2_UMIP	0x00000004
+#define	CPUID_STDEXT2_PKU	0x00000008
+#define	CPUID_STDEXT2_OSPKE	0x00000010
+#define	CPUID_STDEXT2_RDPID	0x00400000
+#define	CPUID_STDEXT2_SGXLC	0x40000000
+
+/*
+ * CPUID manufacturers identifiers
+ */
+#define	AMD_VENDOR_ID		"AuthenticAMD"
+#define	CENTAUR_VENDOR_ID	"CentaurHauls"
+#define	CYRIX_VENDOR_ID		"CyrixInstead"
+#define	INTEL_VENDOR_ID		"GenuineIntel"
+#define	NEXGEN_VENDOR_ID	"NexGenDriven"
+#define	NSC_VENDOR_ID		"Geode by NSC"
+#define	RISE_VENDOR_ID		"RiseRiseRise"
+#define	SIS_VENDOR_ID		"SiS SiS SiS "
+#define	TRANSMETA_VENDOR_ID	"GenuineTMx86"
+#define	UMC_VENDOR_ID		"UMC UMC UMC "
+
+/*
+ * Model-specific registers for the i386 family
+ */
+#define	MSR_P5_MC_ADDR		0x000
+#define	MSR_P5_MC_TYPE		0x001
+#define	MSR_TSC			0x010
+#define	MSR_P5_CESR		0x011
+#define	MSR_P5_CTR0		0x012
+#define	MSR_P5_CTR1		0x013
+#define	MSR_IA32_PLATFORM_ID	0x017
+#define	MSR_APICBASE		0x01b
+#define	MSR_EBL_CR_POWERON	0x02a
+#define	MSR_TEST_CTL		0x033
+#define	MSR_IA32_FEATURE_CONTROL 0x03a
+#define	MSR_BIOS_UPDT_TRIG	0x079
+#define	MSR_BBL_CR_D0		0x088
+#define	MSR_BBL_CR_D1		0x089
+#define	MSR_BBL_CR_D2		0x08a
+#define	MSR_BIOS_SIGN		0x08b
+#define	MSR_PERFCTR0		0x0c1
+#define	MSR_PERFCTR1		0x0c2
+#define	MSR_PLATFORM_INFO	0x0ce
+#define	MSR_MPERF		0x0e7
+#define	MSR_APERF		0x0e8
+#define	MSR_IA32_EXT_CONFIG	0x0ee	/* Undocumented. Core Solo/Duo only */
+#define	MSR_MTRRcap		0x0fe
+#define	MSR_BBL_CR_ADDR		0x116
+#define	MSR_BBL_CR_DECC		0x118
+#define	MSR_BBL_CR_CTL		0x119
+#define	MSR_BBL_CR_TRIG		0x11a
+#define	MSR_BBL_CR_BUSY		0x11b
+#define	MSR_BBL_CR_CTL3		0x11e
+#define	MSR_SYSENTER_CS_MSR	0x174
+#define	MSR_SYSENTER_ESP_MSR	0x175
+#define	MSR_SYSENTER_EIP_MSR	0x176
+#define	MSR_MCG_CAP		0x179
+#define	MSR_MCG_STATUS		0x17a
+#define	MSR_MCG_CTL		0x17b
+#define	MSR_EVNTSEL0		0x186
+#define	MSR_EVNTSEL1		0x187
+#define	MSR_THERM_CONTROL	0x19a
+#define	MSR_THERM_INTERRUPT	0x19b
+#define	MSR_THERM_STATUS	0x19c
+#define	MSR_IA32_MISC_ENABLE	0x1a0
+#define	MSR_IA32_TEMPERATURE_TARGET	0x1a2
+#define	MSR_TURBO_RATIO_LIMIT	0x1ad
+#define	MSR_TURBO_RATIO_LIMIT1	0x1ae
+#define	MSR_DEBUGCTLMSR		0x1d9
+#define	MSR_LASTBRANCHFROMIP	0x1db
+#define	MSR_LASTBRANCHTOIP	0x1dc
+#define	MSR_LASTINTFROMIP	0x1dd
+#define	MSR_LASTINTTOIP		0x1de
+#define	MSR_ROB_CR_BKUPTMPDR6	0x1e0
+#define	MSR_MTRRVarBase		0x200
+#define	MSR_MTRR64kBase		0x250
+#define	MSR_MTRR16kBase		0x258
+#define	MSR_MTRR4kBase		0x268
+#define	MSR_PAT			0x277
+#define	MSR_MC0_CTL2		0x280
+#define	MSR_MTRRdefType		0x2ff
+#define	MSR_MC0_CTL		0x400
+#define	MSR_MC0_STATUS		0x401
+#define	MSR_MC0_ADDR		0x402
+#define	MSR_MC0_MISC		0x403
+#define	MSR_MC1_CTL		0x404
+#define	MSR_MC1_STATUS		0x405
+#define	MSR_MC1_ADDR		0x406
+#define	MSR_MC1_MISC		0x407
+#define	MSR_MC2_CTL		0x408
+#define	MSR_MC2_STATUS		0x409
+#define	MSR_MC2_ADDR		0x40a
+#define	MSR_MC2_MISC		0x40b
+#define	MSR_MC3_CTL		0x40c
+#define	MSR_MC3_STATUS		0x40d
+#define	MSR_MC3_ADDR		0x40e
+#define	MSR_MC3_MISC		0x40f
+#define	MSR_MC4_CTL		0x410
+#define	MSR_MC4_STATUS		0x411
+#define	MSR_MC4_ADDR		0x412
+#define	MSR_MC4_MISC		0x413
+#define	MSR_RAPL_POWER_UNIT	0x606
+#define	MSR_PKG_ENERGY_STATUS	0x611
+#define	MSR_DRAM_ENERGY_STATUS	0x619
+#define	MSR_PP0_ENERGY_STATUS	0x639
+#define	MSR_PP1_ENERGY_STATUS	0x641
+
+/*
+ * VMX MSRs
+ */
+#define	MSR_VMX_BASIC		0x480
+#define	MSR_VMX_PINBASED_CTLS	0x481
+#define	MSR_VMX_PROCBASED_CTLS	0x482
+#define	MSR_VMX_EXIT_CTLS	0x483
+#define	MSR_VMX_ENTRY_CTLS	0x484
+#define	MSR_VMX_CR0_FIXED0	0x486
+#define	MSR_VMX_CR0_FIXED1	0x487
+#define	MSR_VMX_CR4_FIXED0	0x488
+#define	MSR_VMX_CR4_FIXED1	0x489
+#define	MSR_VMX_PROCBASED_CTLS2	0x48b
+#define	MSR_VMX_EPT_VPID_CAP	0x48c
+#define	MSR_VMX_TRUE_PINBASED_CTLS	0x48d
+#define	MSR_VMX_TRUE_PROCBASED_CTLS	0x48e
+#define	MSR_VMX_TRUE_EXIT_CTLS	0x48f
+#define	MSR_VMX_TRUE_ENTRY_CTLS	0x490
+
+/*
+ * X2APIC MSRs
+ */
+#define	MSR_APIC_ID		0x802
+#define	MSR_APIC_VERSION	0x803
+#define	MSR_APIC_TPR		0x808
+#define	MSR_APIC_EOI		0x80b
+#define	MSR_APIC_LDR		0x80d
+#define	MSR_APIC_SVR		0x80f
+#define	MSR_APIC_ISR0		0x810
+#define	MSR_APIC_ISR1		0x811
+#define	MSR_APIC_ISR2		0x812
+#define	MSR_APIC_ISR3		0x813
+#define	MSR_APIC_ISR4		0x814
+#define	MSR_APIC_ISR5		0x815
+#define	MSR_APIC_ISR6		0x816
+#define	MSR_APIC_ISR7		0x817
+#define	MSR_APIC_TMR0		0x818
+#define	MSR_APIC_IRR0		0x820
+#define	MSR_APIC_ESR		0x828
+#define	MSR_APIC_LVT_CMCI	0x82F
+#define	MSR_APIC_ICR		0x830
+#define	MSR_APIC_LVT_TIMER	0x832
+#define	MSR_APIC_LVT_THERMAL	0x833
+#define	MSR_APIC_LVT_PCINT	0x834
+#define	MSR_APIC_LVT_LINT0	0x835
+#define	MSR_APIC_LVT_LINT1	0x836
+#define	MSR_APIC_LVT_ERROR	0x837
+#define	MSR_APIC_ICR_TIMER	0x838
+#define	MSR_APIC_CCR_TIMER	0x839
+#define	MSR_APIC_DCR_TIMER	0x83e
+#define	MSR_APIC_SELF_IPI	0x83f
+
+#define	MSR_IA32_XSS		0xda0
+
+/*
+ * Constants related to MSR's.
+ */
+#define	APICBASE_RESERVED	0x000002ff
+#define	APICBASE_BSP		0x00000100
+#define	APICBASE_X2APIC		0x00000400
+#define	APICBASE_ENABLED	0x00000800
+#define	APICBASE_ADDRESS	0xfffff000
+
+/* MSR_IA32_FEATURE_CONTROL related */
+#define	IA32_FEATURE_CONTROL_LOCK	0x01	/* lock bit */
+#define	IA32_FEATURE_CONTROL_SMX_EN	0x02	/* enable VMX inside SMX */
+#define	IA32_FEATURE_CONTROL_VMX_EN	0x04	/* enable VMX outside SMX */
+
+/* MSR IA32_MISC_ENABLE */
+#define	IA32_MISC_EN_FASTSTR	0x0000000000000001ULL
+#define	IA32_MISC_EN_ATCCE	0x0000000000000008ULL
+#define	IA32_MISC_EN_PERFMON	0x0000000000000080ULL
+#define	IA32_MISC_EN_PEBSU	0x0000000000001000ULL
+#define	IA32_MISC_EN_ESSTE	0x0000000000010000ULL
+#define	IA32_MISC_EN_MONE	0x0000000000040000ULL
+#define	IA32_MISC_EN_LIMCPUID	0x0000000000400000ULL
+#define	IA32_MISC_EN_xTPRD	0x0000000000800000ULL
+#define	IA32_MISC_EN_XDD	0x0000000400000000ULL
+
+/*
+ * PAT modes.
+ */
+#define	PAT_UNCACHEABLE		0x00
+#define	PAT_WRITE_COMBINING	0x01
+#define	PAT_WRITE_THROUGH	0x04
+#define	PAT_WRITE_PROTECTED	0x05
+#define	PAT_WRITE_BACK		0x06
+#define	PAT_UNCACHED		0x07
+#define	PAT_VALUE(i, m)		((long long)(m) << (8 * (i)))
+#define	PAT_MASK(i)		PAT_VALUE(i, 0xff)
+
+/*
+ * Constants related to MTRRs
+ */
+#define	MTRR_UNCACHEABLE	0x00
+#define	MTRR_WRITE_COMBINING	0x01
+#define	MTRR_WRITE_THROUGH	0x04
+#define	MTRR_WRITE_PROTECTED	0x05
+#define	MTRR_WRITE_BACK		0x06
+#define	MTRR_N64K		8	/* numbers of fixed-size entries */
+#define	MTRR_N16K		16
+#define	MTRR_N4K		64
+#define	MTRR_CAP_WC		0x0000000000000400
+#define	MTRR_CAP_FIXED		0x0000000000000100
+#define	MTRR_CAP_VCNT		0x00000000000000ff
+#define	MTRR_DEF_ENABLE		0x0000000000000800
+#define	MTRR_DEF_FIXED_ENABLE	0x0000000000000400
+#define	MTRR_DEF_TYPE		0x00000000000000ff
+#define	MTRR_PHYSBASE_PHYSBASE	0x000ffffffffff000
+#define	MTRR_PHYSBASE_TYPE	0x00000000000000ff
+#define	MTRR_PHYSMASK_PHYSMASK	0x000ffffffffff000
+#define	MTRR_PHYSMASK_VALID	0x0000000000000800
+
+/*
+ * Cyrix configuration registers, accessible as IO ports.
+ */
+#define	CCR0			0xc0	/* Configuration control register 0 */
+#define	CCR0_NC0		0x01	/* First 64K of each 1M memory region is
+								   non-cacheable */
+#define	CCR0_NC1		0x02	/* 640K-1M region is non-cacheable */
+#define	CCR0_A20M		0x04	/* Enables A20M# input pin */
+#define	CCR0_KEN		0x08	/* Enables KEN# input pin */
+#define	CCR0_FLUSH		0x10	/* Enables FLUSH# input pin */
+#define	CCR0_BARB		0x20	/* Flushes internal cache when entering hold
+								   state */
+#define	CCR0_CO			0x40	/* Cache org: 1=direct mapped, 0=2x set
+								   assoc */
+#define	CCR0_SUSPEND	0x80	/* Enables SUSP# and SUSPA# pins */
+
+#define	CCR1			0xc1	/* Configuration control register 1 */
+#define	CCR1_RPL		0x01	/* Enables RPLSET and RPLVAL# pins */
+#define	CCR1_SMI		0x02	/* Enables SMM pins */
+#define	CCR1_SMAC		0x04	/* System management memory access */
+#define	CCR1_MMAC		0x08	/* Main memory access */
+#define	CCR1_NO_LOCK	0x10	/* Negate LOCK# */
+#define	CCR1_SM3		0x80	/* SMM address space address region 3 */
+
+#define	CCR2			0xc2
+#define	CCR2_WB			0x02	/* Enables WB cache interface pins */
+#define	CCR2_SADS		0x02	/* Slow ADS */
+#define	CCR2_LOCK_NW	0x04	/* LOCK NW Bit */
+#define	CCR2_SUSP_HLT	0x08	/* Suspend on HALT */
+#define	CCR2_WT1		0x10	/* WT region 1 */
+#define	CCR2_WPR1		0x10	/* Write-protect region 1 */
+#define	CCR2_BARB		0x20	/* Flushes write-back cache when entering
+								   hold state. */
+#define	CCR2_BWRT		0x40	/* Enables burst write cycles */
+#define	CCR2_USE_SUSP	0x80	/* Enables suspend pins */
+
+#define	CCR3			0xc3
+#define	CCR3_SMILOCK	0x01	/* SMM register lock */
+#define	CCR3_NMI		0x02	/* Enables NMI during SMM */
+#define	CCR3_LINBRST	0x04	/* Linear address burst cycles */
+#define	CCR3_SMMMODE	0x08	/* SMM Mode */
+#define	CCR3_MAPEN0		0x10	/* Enables Map0 */
+#define	CCR3_MAPEN1		0x20	/* Enables Map1 */
+#define	CCR3_MAPEN2		0x40	/* Enables Map2 */
+#define	CCR3_MAPEN3		0x80	/* Enables Map3 */
+
+#define	CCR4			0xe8
+#define	CCR4_IOMASK		0x07
+#define	CCR4_MEM		0x08	/* Enables momory bypassing */
+#define	CCR4_DTE		0x10	/* Enables directory table entry cache */
+#define	CCR4_FASTFPE	0x20	/* Fast FPU exception */
+#define	CCR4_CPUID		0x80	/* Enables CPUID instruction */
+
+#define	CCR5			0xe9
+#define	CCR5_WT_ALLOC	0x01	/* Write-through allocate */
+#define	CCR5_SLOP		0x02	/* LOOP instruction slowed down */
+#define	CCR5_LBR1		0x10	/* Local bus region 1 */
+#define	CCR5_ARREN		0x20	/* Enables ARR region */
+
+#define	CCR6			0xea
+
+#define	CCR7			0xeb
+
+/* Performance Control Register (5x86 only). */
+#define	PCR0			0x20
+#define	PCR0_RSTK		0x01	/* Enables return stack */
+#define	PCR0_BTB		0x02	/* Enables branch target buffer */
+#define	PCR0_LOOP		0x04	/* Enables loop */
+#define	PCR0_AIS		0x08	/* Enables all instrcutions stalled to
+								   serialize pipe. */
+#define	PCR0_MLR		0x10	/* Enables reordering of misaligned loads */
+#define	PCR0_BTBRT		0x40	/* Enables BTB test register. */
+#define	PCR0_LSSER		0x80	/* Disable reorder */
+
+/* Device Identification Registers */
+#define	DIR0			0xfe
+#define	DIR1			0xff
+
+/*
+ * Machine Check register constants.
+ */
+#define	MCG_CAP_COUNT		0x000000ff
+#define	MCG_CAP_CTL_P		0x00000100
+#define	MCG_CAP_EXT_P		0x00000200
+#define	MCG_CAP_CMCI_P		0x00000400
+#define	MCG_CAP_TES_P		0x00000800
+#define	MCG_CAP_EXT_CNT		0x00ff0000
+#define	MCG_CAP_SER_P		0x01000000
+#define	MCG_STATUS_RIPV		0x00000001
+#define	MCG_STATUS_EIPV		0x00000002
+#define	MCG_STATUS_MCIP		0x00000004
+#define	MCG_CTL_ENABLE		0xffffffffffffffff
+#define	MCG_CTL_DISABLE		0x0000000000000000
+#define	MSR_MC_CTL(x)		(MSR_MC0_CTL + (x) * 4)
+#define	MSR_MC_STATUS(x)	(MSR_MC0_STATUS + (x) * 4)
+#define	MSR_MC_ADDR(x)		(MSR_MC0_ADDR + (x) * 4)
+#define	MSR_MC_MISC(x)		(MSR_MC0_MISC + (x) * 4)
+#define	MSR_MC_CTL2(x)		(MSR_MC0_CTL2 + (x))	/* If MCG_CAP_CMCI_P */
+#define	MC_STATUS_MCA_ERROR	0x000000000000ffff
+#define	MC_STATUS_MODEL_ERROR	0x00000000ffff0000
+#define	MC_STATUS_OTHER_INFO	0x01ffffff00000000
+#define	MC_STATUS_COR_COUNT	0x001fffc000000000	/* If MCG_CAP_CMCI_P */
+#define	MC_STATUS_TES_STATUS	0x0060000000000000	/* If MCG_CAP_TES_P */
+#define	MC_STATUS_AR		0x0080000000000000	/* If MCG_CAP_TES_P */
+#define	MC_STATUS_S		0x0100000000000000	/* If MCG_CAP_TES_P */
+#define	MC_STATUS_PCC		0x0200000000000000
+#define	MC_STATUS_ADDRV		0x0400000000000000
+#define	MC_STATUS_MISCV		0x0800000000000000
+#define	MC_STATUS_EN		0x1000000000000000
+#define	MC_STATUS_UC		0x2000000000000000
+#define	MC_STATUS_OVER		0x4000000000000000
+#define	MC_STATUS_VAL		0x8000000000000000
+#define	MC_MISC_RA_LSB		0x000000000000003f	/* If MCG_CAP_SER_P */
+#define	MC_MISC_ADDRESS_MODE	0x00000000000001c0	/* If MCG_CAP_SER_P */
+#define	MC_CTL2_THRESHOLD	0x0000000000007fff
+#define	MC_CTL2_CMCI_EN		0x0000000040000000
+
+/*
+ * The following four 3-byte registers control the non-cacheable regions.
+ * These registers must be written as three separate bytes.
+ *
+ * NCRx+0: A31-A24 of starting address
+ * NCRx+1: A23-A16 of starting address
+ * NCRx+2: A15-A12 of starting address | NCR_SIZE_xx.
+ *
+ * The non-cacheable region's starting address must be aligned to the
+ * size indicated by the NCR_SIZE_xx field.
+ */
+#define	NCR1	0xc4
+#define	NCR2	0xc7
+#define	NCR3	0xca
+#define	NCR4	0xcd
+
+#define	NCR_SIZE_0K	0
+#define	NCR_SIZE_4K	1
+#define	NCR_SIZE_8K	2
+#define	NCR_SIZE_16K	3
+#define	NCR_SIZE_32K	4
+#define	NCR_SIZE_64K	5
+#define	NCR_SIZE_128K	6
+#define	NCR_SIZE_256K	7
+#define	NCR_SIZE_512K	8
+#define	NCR_SIZE_1M	9
+#define	NCR_SIZE_2M	10
+#define	NCR_SIZE_4M	11
+#define	NCR_SIZE_8M	12
+#define	NCR_SIZE_16M	13
+#define	NCR_SIZE_32M	14
+#define	NCR_SIZE_4G	15
+
+/*
+ * The address region registers are used to specify the location and
+ * size for the eight address regions.
+ *
+ * ARRx + 0: A31-A24 of start address
+ * ARRx + 1: A23-A16 of start address
+ * ARRx + 2: A15-A12 of start address | ARR_SIZE_xx
+ */
+#define	ARR0	0xc4
+#define	ARR1	0xc7
+#define	ARR2	0xca
+#define	ARR3	0xcd
+#define	ARR4	0xd0
+#define	ARR5	0xd3
+#define	ARR6	0xd6
+#define	ARR7	0xd9
+
+#define	ARR_SIZE_0K		0
+#define	ARR_SIZE_4K		1
+#define	ARR_SIZE_8K		2
+#define	ARR_SIZE_16K	3
+#define	ARR_SIZE_32K	4
+#define	ARR_SIZE_64K	5
+#define	ARR_SIZE_128K	6
+#define	ARR_SIZE_256K	7
+#define	ARR_SIZE_512K	8
+#define	ARR_SIZE_1M		9
+#define	ARR_SIZE_2M		10
+#define	ARR_SIZE_4M		11
+#define	ARR_SIZE_8M		12
+#define	ARR_SIZE_16M	13
+#define	ARR_SIZE_32M	14
+#define	ARR_SIZE_4G		15
+
+/*
+ * The region control registers specify the attributes associated with
+ * the ARRx addres regions.
+ */
+#define	RCR0	0xdc
+#define	RCR1	0xdd
+#define	RCR2	0xde
+#define	RCR3	0xdf
+#define	RCR4	0xe0
+#define	RCR5	0xe1
+#define	RCR6	0xe2
+#define	RCR7	0xe3
+
+#define	RCR_RCD	0x01	/* Disables caching for ARRx (x = 0-6). */
+#define	RCR_RCE	0x01	/* Enables caching for ARR7. */
+#define	RCR_WWO	0x02	/* Weak write ordering. */
+#define	RCR_WL	0x04	/* Weak locking. */
+#define	RCR_WG	0x08	/* Write gathering. */
+#define	RCR_WT	0x10	/* Write-through. */
+#define	RCR_NLB	0x20	/* LBA# pin is not asserted. */
+
+/* AMD Write Allocate Top-Of-Memory and Control Register */
+#define	AMD_WT_ALLOC_TME	0x40000	/* top-of-memory enable */
+#define	AMD_WT_ALLOC_PRE	0x20000	/* programmable range enable */
+#define	AMD_WT_ALLOC_FRE	0x10000	/* fixed (A0000-FFFFF) range enable */
+
+/* AMD64 MSR's */
+#define	MSR_EFER	0xc0000080	/* extended features */
+#define	MSR_STAR	0xc0000081	/* legacy mode SYSCALL target/cs/ss */
+#define	MSR_LSTAR	0xc0000082	/* long mode SYSCALL target rip */
+#define	MSR_CSTAR	0xc0000083	/* compat mode SYSCALL target rip */
+#define	MSR_SF_MASK	0xc0000084	/* syscall flags mask */
+#define	MSR_FSBASE	0xc0000100	/* base address of the %fs "segment" */
+#define	MSR_GSBASE	0xc0000101	/* base address of the %gs "segment" */
+#define	MSR_KGSBASE	0xc0000102	/* base address of the kernel %gs */
+#define	MSR_PERFEVSEL0	0xc0010000
+#define	MSR_PERFEVSEL1	0xc0010001
+#define	MSR_PERFEVSEL2	0xc0010002
+#define	MSR_PERFEVSEL3	0xc0010003
+#define	MSR_K7_PERFCTR0	0xc0010004
+#define	MSR_K7_PERFCTR1	0xc0010005
+#define	MSR_K7_PERFCTR2	0xc0010006
+#define	MSR_K7_PERFCTR3	0xc0010007
+#define	MSR_SYSCFG	0xc0010010
+#define	MSR_HWCR	0xc0010015
+#define	MSR_IORRBASE0	0xc0010016
+#define	MSR_IORRMASK0	0xc0010017
+#define	MSR_IORRBASE1	0xc0010018
+#define	MSR_IORRMASK1	0xc0010019
+#define	MSR_TOP_MEM	0xc001001a	/* boundary for ram below 4G */
+#define	MSR_TOP_MEM2	0xc001001d	/* boundary for ram above 4G */
+#define	MSR_NB_CFG1	0xc001001f	/* NB configuration 1 */
+#define	MSR_P_STATE_LIMIT 0xc0010061	/* P-state Current Limit Register */
+#define	MSR_P_STATE_CONTROL 0xc0010062	/* P-state Control Register */
+#define	MSR_P_STATE_STATUS 0xc0010063	/* P-state Status Register */
+#define	MSR_P_STATE_CONFIG(n) (0xc0010064 + (n)) /* P-state Config */
+#define	MSR_SMM_ADDR	0xc0010112	/* SMM TSEG base address */
+#define	MSR_SMM_MASK	0xc0010113	/* SMM TSEG address mask */
+#define	MSR_EXTFEATURES	0xc0011005	/* Extended CPUID Features override */
+#define	MSR_IC_CFG	0xc0011021	/* Instruction Cache Configuration */
+#define	MSR_K8_UCODE_UPDATE	0xc0010020	/* update microcode */
+#define	MSR_MC0_CTL_MASK	0xc0010044
+#define	MSR_VM_CR		0xc0010114 /* SVM: feature control */
+#define	MSR_VM_HSAVE_PA		0xc0010117 /* SVM: host save area address */
+
+/* MSR_VM_CR related */
+#define	VM_CR_SVMDIS		0x10	/* SVM: disabled by BIOS */
+
+/* VIA ACE crypto featureset: for via_feature_rng */
+#define	VIA_HAS_RNG		1	/* cpu has RNG */
+
+/* VIA ACE crypto featureset: for via_feature_xcrypt */
+#define	VIA_HAS_AES		1	/* cpu has AES */
+#define	VIA_HAS_SHA		2	/* cpu has SHA1 & SHA256 */
+#define	VIA_HAS_MM		4	/* cpu has RSA instructions */
+#define	VIA_HAS_AESCTR		8	/* cpu has AES-CTR instructions */
+
+/* Centaur Extended Feature flags */
+#define	VIA_CPUID_HAS_RNG	0x000004
+#define	VIA_CPUID_DO_RNG	0x000008
+#define	VIA_CPUID_HAS_ACE	0x000040
+#define	VIA_CPUID_DO_ACE	0x000080
+#define	VIA_CPUID_HAS_ACE2	0x000100
+#define	VIA_CPUID_DO_ACE2	0x000200
+#define	VIA_CPUID_HAS_PHE	0x000400
+#define	VIA_CPUID_DO_PHE	0x000800
+#define	VIA_CPUID_HAS_PMM	0x001000
+#define	VIA_CPUID_DO_PMM	0x002000
+
+/* VIA ACE xcrypt-* instruction context control options */
+#define	VIA_CRYPT_CWLO_ROUND_M		0x0000000f
+#define	VIA_CRYPT_CWLO_ALG_M		0x00000070
+#define	VIA_CRYPT_CWLO_ALG_AES		0x00000000
+#define	VIA_CRYPT_CWLO_KEYGEN_M		0x00000080
+#define	VIA_CRYPT_CWLO_KEYGEN_HW	0x00000000
+#define	VIA_CRYPT_CWLO_KEYGEN_SW	0x00000080
+#define	VIA_CRYPT_CWLO_NORMAL		0x00000000
+#define	VIA_CRYPT_CWLO_INTERMEDIATE	0x00000100
+#define	VIA_CRYPT_CWLO_ENCRYPT		0x00000000
+#define	VIA_CRYPT_CWLO_DECRYPT		0x00000200
+#define	VIA_CRYPT_CWLO_KEY128		0x0000000a	/* 128bit, 10 rds */
+#define	VIA_CRYPT_CWLO_KEY192		0x0000040c	/* 192bit, 12 rds */
+#define	VIA_CRYPT_CWLO_KEY256		0x0000080e	/* 256bit, 15 rds */
+
+#endif /* !_MACHINE_SPECIALREG_H_ */


Property changes on: trunk/sys/x86/include/specialreg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/stdarg.h
===================================================================
--- trunk/sys/x86/include/stdarg.h	                        (rev 0)
+++ trunk/sys/x86/include/stdarg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,78 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2002 David E. O'Brien.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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: stable/10/sys/x86/include/stdarg.h 256105 2013-10-07 10:01:23Z phk $
+ */
+
+#ifndef _MACHINE_STDARG_H_
+#define	_MACHINE_STDARG_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+#ifndef _VA_LIST_DECLARED
+#define	_VA_LIST_DECLARED
+typedef	__va_list	va_list;
+#endif
+
+#ifdef __GNUCLIKE_BUILTIN_STDARG
+
+#define	va_start(ap, last) \
+	__builtin_va_start((ap), (last))
+
+#define	va_arg(ap, type) \
+	__builtin_va_arg((ap), type)
+
+#define	__va_copy(dest, src) \
+	__builtin_va_copy((dest), (src))
+
+#if __ISO_C_VISIBLE >= 1999
+#define	va_copy(dest, src) \
+	__va_copy(dest, src)
+#endif
+
+#define	va_end(ap) \
+	__builtin_va_end(ap)
+
+#elif defined(lint)
+/* Provide a fake implementation for lint's benefit */
+#define	__va_size(type) \
+	(((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+#define	va_start(ap, last) \
+	((ap) = (va_list)&(last) + __va_size(last))
+#define va_copy(dst, src) \
+	((dst) = (src))
+#define	va_arg(ap, type) \
+	(*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
+#define	va_end(ap)
+
+#else
+#error this file needs to be ported to your compiler
+#endif
+
+#endif /* !_MACHINE_STDARG_H_ */


Property changes on: trunk/sys/x86/include/stdarg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/sysarch.h
===================================================================
--- trunk/sys/x86/include/sysarch.h	                        (rev 0)
+++ trunk/sys/x86/include/sysarch.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,139 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: stable/10/sys/x86/include/sysarch.h 233209 2012-03-19 21:57:31Z tijl $
+ */
+
+/*
+ * Architecture specific syscalls (X86)
+ */
+#ifndef _MACHINE_SYSARCH_H_
+#define _MACHINE_SYSARCH_H_
+
+#include <sys/cdefs.h>
+
+#define I386_GET_LDT	0
+#define I386_SET_LDT	1
+#define	LDT_AUTO_ALLOC	0xffffffff
+				/* I386_IOPL */
+#define I386_GET_IOPERM	3
+#define I386_SET_IOPERM	4
+				/* xxxxx */
+#define	I386_VM86		6	/* XXX Not implementable on amd64 */
+#define	I386_GET_FSBASE		7
+#define	I386_SET_FSBASE		8
+#define	I386_GET_GSBASE		9
+#define	I386_SET_GSBASE		10
+#define	I386_GET_XFPUSTATE	11
+
+/* Leave space for 0-127 for to avoid translating syscalls */
+#define	AMD64_GET_FSBASE	128
+#define	AMD64_SET_FSBASE	129
+#define	AMD64_GET_GSBASE	130
+#define	AMD64_SET_GSBASE	131
+#define	AMD64_GET_XFPUSTATE	132
+
+struct i386_ioperm_args {
+	unsigned int start;
+	unsigned int length;
+	int	enable;
+};
+
+#ifdef __i386__
+struct i386_ldt_args {
+	unsigned int start;
+	union descriptor *descs;
+	unsigned int num;
+};
+
+struct i386_vm86_args {
+	int	sub_op;			/* sub-operation to perform */
+	char	*sub_args;		/* args */
+};
+
+struct i386_get_xfpustate {
+	void *addr;
+	int len;
+};
+#else
+struct i386_ldt_args {
+	unsigned int start;
+	struct user_segment_descriptor *descs __packed;
+	unsigned int num;
+};
+
+struct i386_get_xfpustate {
+	unsigned int addr;
+	int len;
+};
+
+struct amd64_get_xfpustate {
+	void *addr;
+	int len;
+};
+#endif
+
+#ifndef _KERNEL
+union descriptor;
+struct dbreg;
+
+__BEGIN_DECLS
+int i386_get_ldt(int, union descriptor *, int);
+int i386_set_ldt(int, union descriptor *, int);
+int i386_get_ioperm(unsigned int, unsigned int *, int *);
+int i386_set_ioperm(unsigned int, unsigned int, int);
+int i386_vm86(int, void *);
+int i386_get_fsbase(void **);
+int i386_get_gsbase(void **);
+int i386_set_fsbase(void *);
+int i386_set_gsbase(void *);
+int i386_set_watch(int, unsigned int, int, int, struct dbreg *);
+int i386_clr_watch(int, struct dbreg *);
+int amd64_get_fsbase(void **);
+int amd64_get_gsbase(void **);
+int amd64_set_fsbase(void *);
+int amd64_set_gsbase(void *);
+int sysarch(int, void *);
+__END_DECLS
+#else
+struct thread;
+union descriptor;
+
+int i386_get_ldt(struct thread *, struct i386_ldt_args *);
+int i386_set_ldt(struct thread *, struct i386_ldt_args *, union descriptor *);
+int i386_get_ioperm(struct thread *, struct i386_ioperm_args *);
+int i386_set_ioperm(struct thread *, struct i386_ioperm_args *);
+int amd64_get_ldt(struct thread *, struct i386_ldt_args *);
+int amd64_set_ldt(struct thread *, struct i386_ldt_args *,
+    struct user_segment_descriptor *);
+int amd64_get_ioperm(struct thread *, struct i386_ioperm_args *);
+int amd64_set_ioperm(struct thread *, struct i386_ioperm_args *);
+#endif
+
+#endif /* !_MACHINE_SYSARCH_H_ */


Property changes on: trunk/sys/x86/include/sysarch.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/trap.h
===================================================================
--- trunk/sys/x86/include/trap.h	                        (rev 0)
+++ trunk/sys/x86/include/trap.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,95 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)trap.h	5.4 (Berkeley) 5/9/91
+ * $FreeBSD: stable/10/sys/x86/include/trap.h 262042 2014-02-17 12:57:13Z avg $
+ */
+
+#ifndef _MACHINE_TRAP_H_
+#define	_MACHINE_TRAP_H_
+
+/*
+ * Trap type values
+ * also known in trap.c for name strings
+ */
+
+#define	T_PRIVINFLT	1	/* privileged instruction */
+#define	T_BPTFLT	3	/* breakpoint instruction */
+#define	T_ARITHTRAP	6	/* arithmetic trap */
+#define	T_PROTFLT	9	/* protection fault */
+#define	T_TRCTRAP	10	/* debug exception (sic) */
+#define	T_PAGEFLT	12	/* page fault */
+#define	T_ALIGNFLT	14	/* alignment fault */
+
+#define	T_DIVIDE	18	/* integer divide fault */
+#define	T_NMI		19	/* non-maskable trap */
+#define	T_OFLOW		20	/* overflow trap */
+#define	T_BOUND		21	/* bound instruction fault */
+#define	T_DNA		22	/* device not available fault */
+#define	T_DOUBLEFLT	23	/* double fault */
+#define	T_FPOPFLT	24	/* fp coprocessor operand fetch fault */
+#define	T_TSSFLT	25	/* invalid tss fault */
+#define	T_SEGNPFLT	26	/* segment not present fault */
+#define	T_STKFLT	27	/* stack fault */
+#define	T_MCHK		28	/* machine check trap */
+#define	T_XMMFLT	29	/* SIMD floating-point exception */
+#define	T_RESERVED	30	/* reserved (unknown) */
+#define	T_DTRACE_RET	32	/* DTrace pid return */
+
+/* XXX most of the following codes aren't used, but could be. */
+
+/* definitions for <sys/signal.h> */
+#define	    ILL_RESAD_FAULT	T_RESADFLT
+#define	    ILL_PRIVIN_FAULT	T_PRIVINFLT
+#define	    ILL_RESOP_FAULT	T_RESOPFLT
+#define	    ILL_ALIGN_FAULT	T_ALIGNFLT
+#define	    ILL_FPOP_FAULT	T_FPOPFLT	/* coprocessor operand fault */
+
+/* old FreeBSD macros, deprecated */
+#define	FPE_INTOVF_TRAP	0x1	/* integer overflow */
+#define	FPE_INTDIV_TRAP	0x2	/* integer divide by zero */
+#define	FPE_FLTDIV_TRAP	0x3	/* floating/decimal divide by zero */
+#define	FPE_FLTOVF_TRAP	0x4	/* floating overflow */
+#define	FPE_FLTUND_TRAP	0x5	/* floating underflow */
+#define	FPE_FPU_NP_TRAP	0x6	/* floating point unit not present  */
+#define	FPE_SUBRNG_TRAP	0x7	/* subrange out of bounds */
+
+/* codes for SIGBUS */
+#define	    BUS_PAGE_FAULT	T_PAGEFLT	/* page fault protection base */
+#define	    BUS_SEGNP_FAULT	T_SEGNPFLT	/* segment not present */
+#define	    BUS_STK_FAULT	T_STKFLT	/* stack segment */
+#define	    BUS_SEGM_FAULT	T_RESERVED	/* segment protection base */
+
+/* Trap's coming from user mode */
+#define	T_USER	0x100
+
+#endif /* !_MACHINE_TRAP_H_ */


Property changes on: trunk/sys/x86/include/trap.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/include/ucontext.h
===================================================================
--- trunk/sys/x86/include/ucontext.h	                        (rev 0)
+++ trunk/sys/x86/include/ucontext.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,166 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * Copyright (c) 1999 Marcel Moolenaar
+ * 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 
+ *    in this position and unchanged.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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: stable/10/sys/x86/include/ucontext.h 247047 2013-02-20 17:39:52Z kib $
+ */
+
+#ifndef _X86_UCONTEXT_H_
+#define	_X86_UCONTEXT_H_
+
+#ifdef __i386__
+/* Keep _MC_* values similar to amd64 */
+#define	_MC_HASSEGS	0x1
+#define	_MC_HASBASES	0x2
+#define	_MC_HASFPXSTATE	0x4
+#define	_MC_FLAG_MASK	(_MC_HASSEGS | _MC_HASBASES | _MC_HASFPXSTATE)
+
+typedef struct __mcontext {
+	/*
+	 * The definition of mcontext_t must match the layout of
+	 * struct sigcontext after the sc_mask member.  This is so
+	 * that we can support sigcontext and ucontext_t at the same
+	 * time.
+	 */
+	__register_t	mc_onstack;	/* XXX - sigcontext compat. */
+	__register_t	mc_gs;		/* machine state (struct trapframe) */
+	__register_t	mc_fs;
+	__register_t	mc_es;
+	__register_t	mc_ds;
+	__register_t	mc_edi;
+	__register_t	mc_esi;
+	__register_t	mc_ebp;
+	__register_t	mc_isp;
+	__register_t	mc_ebx;
+	__register_t	mc_edx;
+	__register_t	mc_ecx;
+	__register_t	mc_eax;
+	__register_t	mc_trapno;
+	__register_t	mc_err;
+	__register_t	mc_eip;
+	__register_t	mc_cs;
+	__register_t	mc_eflags;
+	__register_t	mc_esp;
+	__register_t	mc_ss;
+
+	int	mc_len;			/* sizeof(mcontext_t) */
+#define	_MC_FPFMT_NODEV		0x10000	/* device not present or configured */
+#define	_MC_FPFMT_387		0x10001
+#define	_MC_FPFMT_XMM		0x10002
+	int	mc_fpformat;
+#define	_MC_FPOWNED_NONE	0x20000	/* FP state not used */
+#define	_MC_FPOWNED_FPU		0x20001	/* FP state came from FPU */
+#define	_MC_FPOWNED_PCB		0x20002	/* FP state came from PCB */
+	int	mc_ownedfp;
+	__register_t mc_flags;
+	/*
+	 * See <machine/npx.h> for the internals of mc_fpstate[].
+	 */
+	int	mc_fpstate[128] __aligned(16);
+
+	__register_t mc_fsbase;
+	__register_t mc_gsbase;
+
+	__register_t mc_xfpustate;
+	__register_t mc_xfpustate_len;
+
+	int	mc_spare2[4];
+} mcontext_t;
+#endif /* __i386__ */
+
+#ifdef __amd64__
+/*
+ * mc_trapno bits. Shall be in sync with TF_XXX.
+ */
+#define	_MC_HASSEGS	0x1
+#define	_MC_HASBASES	0x2
+#define	_MC_HASFPXSTATE	0x4
+#define	_MC_FLAG_MASK	(_MC_HASSEGS | _MC_HASBASES | _MC_HASFPXSTATE)
+
+typedef struct __mcontext {
+	/*
+	 * The definition of mcontext_t must match the layout of
+	 * struct sigcontext after the sc_mask member.  This is so
+	 * that we can support sigcontext and ucontext_t at the same
+	 * time.
+	 */
+	__register_t	mc_onstack;	/* XXX - sigcontext compat. */
+	__register_t	mc_rdi;		/* machine state (struct trapframe) */
+	__register_t	mc_rsi;
+	__register_t	mc_rdx;
+	__register_t	mc_rcx;
+	__register_t	mc_r8;
+	__register_t	mc_r9;
+	__register_t	mc_rax;
+	__register_t	mc_rbx;
+	__register_t	mc_rbp;
+	__register_t	mc_r10;
+	__register_t	mc_r11;
+	__register_t	mc_r12;
+	__register_t	mc_r13;
+	__register_t	mc_r14;
+	__register_t	mc_r15;
+	__uint32_t	mc_trapno;
+	__uint16_t	mc_fs;
+	__uint16_t	mc_gs;
+	__register_t	mc_addr;
+	__uint32_t	mc_flags;
+	__uint16_t	mc_es;
+	__uint16_t	mc_ds;
+	__register_t	mc_err;
+	__register_t	mc_rip;
+	__register_t	mc_cs;
+	__register_t	mc_rflags;
+	__register_t	mc_rsp;
+	__register_t	mc_ss;
+
+	long	mc_len;			/* sizeof(mcontext_t) */
+
+#define	_MC_FPFMT_NODEV		0x10000	/* device not present or configured */
+#define	_MC_FPFMT_XMM		0x10002
+	long	mc_fpformat;
+#define	_MC_FPOWNED_NONE	0x20000	/* FP state not used */
+#define	_MC_FPOWNED_FPU		0x20001	/* FP state came from FPU */
+#define	_MC_FPOWNED_PCB		0x20002	/* FP state came from PCB */
+	long	mc_ownedfp;
+	/*
+	 * See <machine/fpu.h> for the internals of mc_fpstate[].
+	 */
+	long	mc_fpstate[64] __aligned(16);
+
+	__register_t	mc_fsbase;
+	__register_t	mc_gsbase;
+
+	__register_t	mc_xfpustate;
+	__register_t	mc_xfpustate_len;
+
+	long	mc_spare[4];
+} mcontext_t;
+#endif /* __amd64__ */
+
+#endif /* !_X86_UCONTEXT_H_ */


Property changes on: trunk/sys/x86/include/ucontext.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/include/vdso.h
===================================================================
--- trunk/sys/x86/include/vdso.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/include/vdso.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright 2012 Konstantin Belousov <kib at FreeBSD.ORG>.
  * All rights reserved.
@@ -22,7 +23,7 @@
  * (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$
+ * $FreeBSD: stable/10/sys/x86/include/vdso.h 237433 2012-06-22 07:06:40Z kib $
  */
 
 #ifndef _X86_VDSO_H

Added: trunk/sys/x86/include/vmware.h
===================================================================
--- trunk/sys/x86/include/vmware.h	                        (rev 0)
+++ trunk/sys/x86/include/vmware.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,48 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2011-2014 Jung-uk Kim <jkim at 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: stable/10/sys/x86/include/vmware.h 278522 2015-02-10 16:34:42Z jhb $
+ */
+
+#ifndef _X86_VMWARE_H_
+#define	_X86_VMWARE_H_
+
+#define	VMW_HVMAGIC		0x564d5868
+#define	VMW_HVPORT		0x5658
+#define	VMW_HVCMD_GETVERSION	10
+#define	VMW_HVCMD_GETHZ		45
+
+static __inline void
+vmware_hvcall(u_int cmd, u_int *p)
+{
+
+	__asm __volatile("inl %w3, %0"
+	: "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
+	: "0" (VMW_HVMAGIC), "1" (UINT_MAX), "2" (cmd), "3" (VMW_HVPORT)
+	: "memory");
+}
+
+#endif /* !_X86_VMWARE_H_ */


Property changes on: trunk/sys/x86/include/vmware.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/busdma_dmar.c
===================================================================
--- trunk/sys/x86/iommu/busdma_dmar.c	                        (rev 0)
+++ trunk/sys/x86/iommu/busdma_dmar.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,877 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/busdma_dmar.c 284021 2015-06-05 08:36:25Z kib $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/rman.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+/*
+ * busdma_dmar.c, the implementation of the busdma(9) interface using
+ * DMAR units from Intel VT-d.
+ */
+
+static bool
+dmar_bus_dma_is_dev_disabled(int domain, int bus, int slot, int func)
+{
+	char str[128], *env;
+
+	snprintf(str, sizeof(str), "hw.busdma.pci%d.%d.%d.%d.bounce",
+	    domain, bus, slot, func);
+	env = getenv(str);
+	if (env == NULL)
+		return (false);
+	freeenv(env);
+	return (true);
+}
+
+/*
+ * Given original device, find the requester ID that will be seen by
+ * the DMAR unit and used for page table lookup.  PCI bridges may take
+ * ownership of transactions from downstream devices, so it may not be
+ * the same as the BSF of the target device.  In those cases, all
+ * devices downstream of the bridge must share a single mapping
+ * domain, and must collectively be assigned to use either DMAR or
+ * bounce mapping.
+ */
+static device_t
+dmar_get_requester(device_t dev, uint16_t *rid)
+{
+	devclass_t pci_class;
+	device_t l, pci, pcib, pcip, pcibp, requester;
+	int cap_offset;
+	uint16_t pcie_flags;
+	bool bridge_is_pcie;
+
+	pci_class = devclass_find("pci");
+	l = requester = dev;
+
+	*rid = pci_get_rid(dev);
+
+	/*
+	 * Walk the bridge hierarchy from the target device to the
+	 * host port to find the translating bridge nearest the DMAR
+	 * unit.
+	 */
+	for (;;) {
+		pci = device_get_parent(l);
+		KASSERT(pci != NULL, ("dmar_get_requester(%s): NULL parent "
+		    "for %s", device_get_name(dev), device_get_name(l)));
+		KASSERT(device_get_devclass(pci) == pci_class,
+		    ("dmar_get_requester(%s): non-pci parent %s for %s",
+		    device_get_name(dev), device_get_name(pci),
+		    device_get_name(l)));
+
+		pcib = device_get_parent(pci);
+		KASSERT(pcib != NULL, ("dmar_get_requester(%s): NULL bridge "
+		    "for %s", device_get_name(dev), device_get_name(pci)));
+
+		/*
+		 * The parent of our "bridge" isn't another PCI bus,
+		 * so pcib isn't a PCI->PCI bridge but rather a host
+		 * port, and the requester ID won't be translated
+		 * further.
+		 */
+		pcip = device_get_parent(pcib);
+		if (device_get_devclass(pcip) != pci_class)
+			break;
+		pcibp = device_get_parent(pcip);
+
+		if (pci_find_cap(l, PCIY_EXPRESS, &cap_offset) == 0) {
+			/*
+			 * Do not stop the loop even if the target
+			 * device is PCIe, because it is possible (but
+			 * unlikely) to have a PCI->PCIe bridge
+			 * somewhere in the hierarchy.
+			 */
+			l = pcib;
+		} else {
+			/*
+			 * Device is not PCIe, it cannot be seen as a
+			 * requester by DMAR unit.  Check whether the
+			 * bridge is PCIe.
+			 */
+			bridge_is_pcie = pci_find_cap(pcib, PCIY_EXPRESS,
+			    &cap_offset) == 0;
+			requester = pcib;
+
+			/*
+			 * Check for a buggy PCIe/PCI bridge that
+			 * doesn't report the express capability.  If
+			 * the bridge above it is express but isn't a
+			 * PCI bridge, then we know pcib is actually a
+			 * PCIe/PCI bridge.
+			 */
+			if (!bridge_is_pcie && pci_find_cap(pcibp,
+			    PCIY_EXPRESS, &cap_offset) == 0) {
+				pcie_flags = pci_read_config(pcibp,
+				    cap_offset + PCIER_FLAGS, 2);
+				if ((pcie_flags & PCIEM_FLAGS_TYPE) !=
+				    PCIEM_TYPE_PCI_BRIDGE)
+					bridge_is_pcie = true;
+			}
+
+			if (bridge_is_pcie) {
+				/*
+				 * The current device is not PCIe, but
+				 * the bridge above it is.  This is a
+				 * PCIe->PCI bridge.  Assume that the
+				 * requester ID will be the secondary
+				 * bus number with slot and function
+				 * set to zero.
+				 *
+				 * XXX: Doesn't handle the case where
+				 * the bridge is PCIe->PCI-X, and the
+				 * bridge will only take ownership of
+				 * requests in some cases.  We should
+				 * provide context entries with the
+				 * same page tables for taken and
+				 * non-taken transactions.
+				 */
+				*rid = PCI_RID(pci_get_bus(l), 0, 0);
+				l = pcibp;
+			} else {
+				/*
+				 * Neither the device nor the bridge
+				 * above it are PCIe.  This is a
+				 * conventional PCI->PCI bridge, which
+				 * will use the bridge's BSF as the
+				 * requester ID.
+				 */
+				*rid = pci_get_rid(pcib);
+				l = pcib;
+			}
+		}
+	}
+	return (requester);
+}
+
+struct dmar_ctx *
+dmar_instantiate_ctx(struct dmar_unit *dmar, device_t dev, bool rmrr)
+{
+	device_t requester;
+	struct dmar_ctx *ctx;
+	bool disabled;
+	uint16_t rid;
+
+	requester = dmar_get_requester(dev, &rid);
+
+	/*
+	 * If the user requested the IOMMU disabled for the device, we
+	 * cannot disable the DMAR, due to possibility of other
+	 * devices on the same DMAR still requiring translation.
+	 * Instead provide the identity mapping for the device
+	 * context.
+	 */
+	disabled = dmar_bus_dma_is_dev_disabled(pci_get_domain(requester), 
+	    pci_get_bus(requester), pci_get_slot(requester), 
+	    pci_get_function(requester));
+	ctx = dmar_get_ctx(dmar, requester, rid, disabled, rmrr);
+	if (ctx == NULL)
+		return (NULL);
+	if (disabled) {
+		/*
+		 * Keep the first reference on context, release the
+		 * later refs.
+		 */
+		DMAR_LOCK(dmar);
+		if ((ctx->flags & DMAR_CTX_DISABLED) == 0) {
+			ctx->flags |= DMAR_CTX_DISABLED;
+			DMAR_UNLOCK(dmar);
+		} else {
+			dmar_free_ctx_locked(dmar, ctx);
+		}
+		ctx = NULL;
+	}
+	return (ctx);
+}
+
+bus_dma_tag_t
+dmar_get_dma_tag(device_t dev, device_t child)
+{
+	struct dmar_unit *dmar;
+	struct dmar_ctx *ctx;
+	bus_dma_tag_t res;
+
+	dmar = dmar_find(child);
+	/* Not in scope of any DMAR ? */
+	if (dmar == NULL)
+		return (NULL);
+	dmar_quirks_pre_use(dmar);
+	dmar_instantiate_rmrr_ctxs(dmar);
+
+	ctx = dmar_instantiate_ctx(dmar, child, false);
+	res = ctx == NULL ? NULL : (bus_dma_tag_t)&ctx->ctx_tag;
+	return (res);
+}
+
+static MALLOC_DEFINE(M_DMAR_DMAMAP, "dmar_dmamap", "Intel DMAR DMA Map");
+
+static void dmar_bus_schedule_dmamap(struct dmar_unit *unit,
+    struct bus_dmamap_dmar *map);
+
+static int
+dmar_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
+    bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
+    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
+    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+    void *lockfuncarg, bus_dma_tag_t *dmat)
+{
+	struct bus_dma_tag_dmar *newtag, *oldtag;
+	int error;
+
+	*dmat = NULL;
+	error = common_bus_dma_tag_create(parent != NULL ?
+	    &((struct bus_dma_tag_dmar *)parent)->common : NULL, alignment,
+	    boundary, lowaddr, highaddr, filter, filterarg, maxsize,
+	    nsegments, maxsegsz, flags, lockfunc, lockfuncarg,
+	    sizeof(struct bus_dma_tag_dmar), (void **)&newtag);
+	if (error != 0)
+		goto out;
+
+	oldtag = (struct bus_dma_tag_dmar *)parent;
+	newtag->common.impl = &bus_dma_dmar_impl;
+	newtag->ctx = oldtag->ctx;
+	newtag->owner = oldtag->owner;
+
+	*dmat = (bus_dma_tag_t)newtag;
+out:
+	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
+	    __func__, newtag, (newtag != NULL ? newtag->common.flags : 0),
+	    error);
+	return (error);
+}
+
+static int
+dmar_bus_dma_tag_destroy(bus_dma_tag_t dmat1)
+{
+	struct bus_dma_tag_dmar *dmat, *dmat_copy, *parent;
+	int error;
+
+	error = 0;
+	dmat_copy = dmat = (struct bus_dma_tag_dmar *)dmat1;
+
+	if (dmat != NULL) {
+		if (dmat->map_count != 0) {
+			error = EBUSY;
+			goto out;
+		}
+		while (dmat != NULL) {
+			parent = (struct bus_dma_tag_dmar *)dmat->common.parent;
+			if (atomic_fetchadd_int(&dmat->common.ref_count, -1) ==
+			    1) {
+				if (dmat == &dmat->ctx->ctx_tag)
+					dmar_free_ctx(dmat->ctx);
+				free(dmat->segments, M_DMAR_DMAMAP);
+				free(dmat, M_DEVBUF);
+				dmat = parent;
+			} else
+				dmat = NULL;
+		}
+	}
+out:
+	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error);
+	return (error);
+}
+
+static int
+dmar_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = malloc(sizeof(*map), M_DMAR_DMAMAP, M_NOWAIT | M_ZERO);
+	if (map == NULL) {
+		*mapp = NULL;
+		return (ENOMEM);
+	}
+	if (tag->segments == NULL) {
+		tag->segments = malloc(sizeof(bus_dma_segment_t) *
+		    tag->common.nsegments, M_DMAR_DMAMAP, M_NOWAIT);
+		if (tag->segments == NULL) {
+			free(map, M_DMAR_DMAMAP);
+			*mapp = NULL;
+			return (ENOMEM);
+		}
+	}
+	TAILQ_INIT(&map->map_entries);
+	map->tag = tag;
+	map->locked = true;
+	map->cansleep = false;
+	tag->map_count++;
+	*mapp = (bus_dmamap_t)map;
+
+	return (0);
+}
+
+static int
+dmar_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map1)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+	if (map != NULL) {
+		DMAR_CTX_LOCK(tag->ctx);
+		if (!TAILQ_EMPTY(&map->map_entries)) {
+			DMAR_CTX_UNLOCK(tag->ctx);
+			return (EBUSY);
+		}
+		DMAR_CTX_UNLOCK(tag->ctx);
+		free(map, M_DMAR_DMAMAP);
+	}
+	tag->map_count--;
+	return (0);
+}
+
+
+static int
+dmar_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
+    bus_dmamap_t *mapp)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+	int error, mflags;
+	vm_memattr_t attr;
+
+	error = dmar_bus_dmamap_create(dmat, flags, mapp);
+	if (error != 0)
+		return (error);
+
+	mflags = (flags & BUS_DMA_NOWAIT) != 0 ? M_NOWAIT : M_WAITOK;
+	mflags |= (flags & BUS_DMA_ZERO) != 0 ? M_ZERO : 0;
+	attr = (flags & BUS_DMA_NOCACHE) != 0 ? VM_MEMATTR_UNCACHEABLE :
+	    VM_MEMATTR_DEFAULT;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)*mapp;
+
+	if (tag->common.maxsize < PAGE_SIZE &&
+	    tag->common.alignment <= tag->common.maxsize &&
+	    attr == VM_MEMATTR_DEFAULT) {
+		*vaddr = malloc(tag->common.maxsize, M_DEVBUF, mflags);
+		map->flags |= BUS_DMAMAP_DMAR_MALLOC;
+	} else {
+		*vaddr = (void *)kmem_alloc_attr(kernel_arena,
+		    tag->common.maxsize, mflags, 0ul, BUS_SPACE_MAXADDR,
+		    attr);
+		map->flags |= BUS_DMAMAP_DMAR_KMEM_ALLOC;
+	}
+	if (*vaddr == NULL) {
+		dmar_bus_dmamap_destroy(dmat, *mapp);
+		*mapp = NULL;
+		return (ENOMEM);
+	}
+	return (0);
+}
+
+static void
+dmar_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map1)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+
+	if ((map->flags & BUS_DMAMAP_DMAR_MALLOC) != 0) {
+		free(vaddr, M_DEVBUF);
+		map->flags &= ~BUS_DMAMAP_DMAR_MALLOC;
+	} else {
+		KASSERT((map->flags & BUS_DMAMAP_DMAR_KMEM_ALLOC) != 0,
+		    ("dmar_bus_dmamem_free for non alloced map %p", map));
+		kmem_free(kernel_arena, (vm_offset_t)vaddr, tag->common.maxsize);
+		map->flags &= ~BUS_DMAMAP_DMAR_KMEM_ALLOC;
+	}
+
+	dmar_bus_dmamap_destroy(dmat, map1);
+}
+
+static int
+dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
+    struct bus_dmamap_dmar *map, vm_page_t *ma, int offset, bus_size_t buflen,
+    int flags, bus_dma_segment_t *segs, int *segp,
+    struct dmar_map_entries_tailq *unroll_list)
+{
+	struct dmar_ctx *ctx;
+	struct dmar_map_entry *entry;
+	dmar_gaddr_t size;
+	bus_size_t buflen1;
+	int error, idx, gas_flags, seg;
+
+	KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset));
+	if (segs == NULL)
+		segs = tag->segments;
+	ctx = tag->ctx;
+	seg = *segp;
+	error = 0;
+	idx = 0;
+	while (buflen > 0) {
+		seg++;
+		if (seg >= tag->common.nsegments) {
+			error = EFBIG;
+			break;
+		}
+		buflen1 = buflen > tag->common.maxsegsz ?
+		    tag->common.maxsegsz : buflen;
+		size = round_page(offset + buflen1);
+
+		/*
+		 * (Too) optimistically allow split if there are more
+		 * then one segments left.
+		 */
+		gas_flags = map->cansleep ? DMAR_GM_CANWAIT : 0;
+		if (seg + 1 < tag->common.nsegments)
+			gas_flags |= DMAR_GM_CANSPLIT;
+
+		error = dmar_gas_map(ctx, &tag->common, size, offset,
+		    DMAR_MAP_ENTRY_READ | DMAR_MAP_ENTRY_WRITE,
+		    gas_flags, ma + idx, &entry);
+		if (error != 0)
+			break;
+		if ((gas_flags & DMAR_GM_CANSPLIT) != 0) {
+			KASSERT(size >= entry->end - entry->start,
+			    ("split increased entry size %jx %jx %jx",
+			    (uintmax_t)size, (uintmax_t)entry->start,
+			    (uintmax_t)entry->end));
+			size = entry->end - entry->start;
+			if (buflen1 > size)
+				buflen1 = size;
+		} else {
+			KASSERT(entry->end - entry->start == size,
+			    ("no split allowed %jx %jx %jx",
+			    (uintmax_t)size, (uintmax_t)entry->start,
+			    (uintmax_t)entry->end));
+		}
+		if (offset + buflen1 > size)
+			buflen1 = size - offset;
+		if (buflen1 > tag->common.maxsegsz)
+			buflen1 = tag->common.maxsegsz;
+
+		KASSERT(((entry->start + offset) & (tag->common.alignment - 1))
+		    == 0,
+		    ("alignment failed: ctx %p start 0x%jx offset %x "
+		    "align 0x%jx", ctx, (uintmax_t)entry->start, offset,
+		    (uintmax_t)tag->common.alignment));
+		KASSERT(entry->end <= tag->common.lowaddr ||
+		    entry->start >= tag->common.highaddr,
+		    ("entry placement failed: ctx %p start 0x%jx end 0x%jx "
+		    "lowaddr 0x%jx highaddr 0x%jx", ctx,
+		    (uintmax_t)entry->start, (uintmax_t)entry->end,
+		    (uintmax_t)tag->common.lowaddr,
+		    (uintmax_t)tag->common.highaddr));
+		KASSERT(dmar_test_boundary(entry->start + offset, buflen1,
+		    tag->common.boundary),
+		    ("boundary failed: ctx %p start 0x%jx end 0x%jx "
+		    "boundary 0x%jx", ctx, (uintmax_t)entry->start,
+		    (uintmax_t)entry->end, (uintmax_t)tag->common.boundary));
+		KASSERT(buflen1 <= tag->common.maxsegsz,
+		    ("segment too large: ctx %p start 0x%jx end 0x%jx "
+		    "buflen1 0x%jx maxsegsz 0x%jx", ctx,
+		    (uintmax_t)entry->start, (uintmax_t)entry->end,
+		    (uintmax_t)buflen1, (uintmax_t)tag->common.maxsegsz));
+
+		DMAR_CTX_LOCK(ctx);
+		TAILQ_INSERT_TAIL(&map->map_entries, entry, dmamap_link);
+		entry->flags |= DMAR_MAP_ENTRY_MAP;
+		DMAR_CTX_UNLOCK(ctx);
+		TAILQ_INSERT_TAIL(unroll_list, entry, unroll_link);
+
+		segs[seg].ds_addr = entry->start + offset;
+		segs[seg].ds_len = buflen1;
+
+		idx += OFF_TO_IDX(trunc_page(offset + buflen1));
+		offset += buflen1;
+		offset &= DMAR_PAGE_MASK;
+		buflen -= buflen1;
+	}
+	if (error == 0)
+		*segp = seg;
+	return (error);
+}
+
+static int
+dmar_bus_dmamap_load_something(struct bus_dma_tag_dmar *tag,
+    struct bus_dmamap_dmar *map, vm_page_t *ma, int offset, bus_size_t buflen,
+    int flags, bus_dma_segment_t *segs, int *segp)
+{
+	struct dmar_ctx *ctx;
+	struct dmar_map_entry *entry, *entry1;
+	struct dmar_map_entries_tailq unroll_list;
+	int error;
+
+	ctx = tag->ctx;
+	atomic_add_long(&ctx->loads, 1);
+
+	TAILQ_INIT(&unroll_list);
+	error = dmar_bus_dmamap_load_something1(tag, map, ma, offset,
+	    buflen, flags, segs, segp, &unroll_list);
+	if (error != 0) {
+		/*
+		 * The busdma interface does not allow us to report
+		 * partial buffer load, so unfortunately we have to
+		 * revert all work done.
+		 */
+		DMAR_CTX_LOCK(ctx);
+		TAILQ_FOREACH_SAFE(entry, &unroll_list, unroll_link,
+		    entry1) {
+			/*
+			 * No entries other than what we have created
+			 * during the failed run might have been
+			 * inserted there in between, since we own ctx
+			 * pglock.
+			 */
+			TAILQ_REMOVE(&map->map_entries, entry, dmamap_link);
+			TAILQ_REMOVE(&unroll_list, entry, unroll_link);
+			TAILQ_INSERT_TAIL(&ctx->unload_entries, entry,
+			    dmamap_link);
+		}
+		DMAR_CTX_UNLOCK(ctx);
+		taskqueue_enqueue(ctx->dmar->delayed_taskqueue,
+		    &ctx->unload_task);
+	}
+
+	if (error == ENOMEM && (flags & BUS_DMA_NOWAIT) == 0 &&
+	    !map->cansleep)
+		error = EINPROGRESS;
+	if (error == EINPROGRESS)
+		dmar_bus_schedule_dmamap(ctx->dmar, map);
+	return (error);
+}
+
+static int
+dmar_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map1,
+    struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
+    bus_dma_segment_t *segs, int *segp)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+	return (dmar_bus_dmamap_load_something(tag, map, ma, ma_offs, tlen,
+	    flags, segs, segp));
+}
+
+static int
+dmar_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map1,
+    vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+	vm_page_t *ma;
+	vm_paddr_t pstart, pend;
+	int error, i, ma_cnt, offset;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+	pstart = trunc_page(buf);
+	pend = round_page(buf + buflen);
+	offset = buf & PAGE_MASK;
+	ma_cnt = OFF_TO_IDX(pend - pstart);
+	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
+	    M_WAITOK : M_NOWAIT);
+	if (ma == NULL)
+		return (ENOMEM);
+	for (i = 0; i < ma_cnt; i++)
+		ma[i] = PHYS_TO_VM_PAGE(pstart + i * PAGE_SIZE);
+	error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,
+	    flags, segs, segp);
+	free(ma, M_DEVBUF);
+	return (error);
+}
+
+static int
+dmar_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map1, void *buf,
+    bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+	vm_page_t *ma, fma;
+	vm_paddr_t pstart, pend, paddr;
+	int error, i, ma_cnt, offset;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+	pstart = trunc_page((vm_offset_t)buf);
+	pend = round_page((vm_offset_t)buf + buflen);
+	offset = (vm_offset_t)buf & PAGE_MASK;
+	ma_cnt = OFF_TO_IDX(pend - pstart);
+	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
+	    M_WAITOK : M_NOWAIT);
+	if (ma == NULL)
+		return (ENOMEM);
+	if (dumping) {
+		/*
+		 * If dumping, do not attempt to call
+		 * PHYS_TO_VM_PAGE() at all.  It may return non-NULL
+		 * but the vm_page returned might be not initialized,
+		 * e.g. for the kernel itself.
+		 */
+		KASSERT(pmap == kernel_pmap, ("non-kernel address write"));
+		fma = malloc(sizeof(struct vm_page) * ma_cnt, M_DEVBUF,
+		    M_ZERO | (map->cansleep ? M_WAITOK : M_NOWAIT));
+		if (fma == NULL) {
+			free(ma, M_DEVBUF);
+			return (ENOMEM);
+		}
+		for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
+			paddr = pmap_kextract(pstart);
+			vm_page_initfake(&fma[i], paddr, VM_MEMATTR_DEFAULT);
+			ma[i] = &fma[i];
+		}
+	} else {
+		fma = NULL;
+		for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
+			if (pmap == kernel_pmap)
+				paddr = pmap_kextract(pstart);
+			else
+				paddr = pmap_extract(pmap, pstart);
+			ma[i] = PHYS_TO_VM_PAGE(paddr);
+			KASSERT(VM_PAGE_TO_PHYS(ma[i]) == paddr,
+			    ("PHYS_TO_VM_PAGE failed %jx %jx m %p",
+			    (uintmax_t)paddr, (uintmax_t)VM_PAGE_TO_PHYS(ma[i]),
+			    ma[i]));
+		}
+	}
+	error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,
+	    flags, segs, segp);
+	free(ma, M_DEVBUF);
+	free(fma, M_DEVBUF);
+	return (error);
+}
+
+static void
+dmar_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map1,
+    struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
+{
+	struct bus_dmamap_dmar *map;
+
+	if (map1 == NULL)
+		return;
+	map = (struct bus_dmamap_dmar *)map1;
+	map->mem = *mem;
+	map->tag = (struct bus_dma_tag_dmar *)dmat;
+	map->callback = callback;
+	map->callback_arg = callback_arg;
+}
+
+static bus_dma_segment_t *
+dmar_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map1,
+    bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+
+	if (!map->locked) {
+		KASSERT(map->cansleep,
+		    ("map not locked and not sleepable context %p", map));
+
+		/*
+		 * We are called from the delayed context.  Relock the
+		 * driver.
+		 */
+		(tag->common.lockfunc)(tag->common.lockfuncarg, BUS_DMA_LOCK);
+		map->locked = true;
+	}
+
+	if (segs == NULL)
+		segs = tag->segments;
+	return (segs);
+}
+
+/*
+ * The limitations of busdma KPI forces the dmar to perform the actual
+ * unload, consisting of the unmapping of the map entries page tables,
+ * from the delayed context on i386, since page table page mapping
+ * might require a sleep to be successfull.  The unfortunate
+ * consequence is that the DMA requests can be served some time after
+ * the bus_dmamap_unload() call returned.
+ *
+ * On amd64, we assume that sf allocation cannot fail.
+ */
+static void
+dmar_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map1)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+	struct dmar_ctx *ctx;
+#if defined(__amd64__)
+	struct dmar_map_entries_tailq entries;
+#endif
+
+	tag = (struct bus_dma_tag_dmar *)dmat;
+	map = (struct bus_dmamap_dmar *)map1;
+	ctx = tag->ctx;
+	atomic_add_long(&ctx->unloads, 1);
+
+#if defined(__i386__)
+	DMAR_CTX_LOCK(ctx);
+	TAILQ_CONCAT(&ctx->unload_entries, &map->map_entries, dmamap_link);
+	DMAR_CTX_UNLOCK(ctx);
+	taskqueue_enqueue(ctx->dmar->delayed_taskqueue, &ctx->unload_task);
+#else /* defined(__amd64__) */
+	TAILQ_INIT(&entries);
+	DMAR_CTX_LOCK(ctx);
+	TAILQ_CONCAT(&entries, &map->map_entries, dmamap_link);
+	DMAR_CTX_UNLOCK(ctx);
+	THREAD_NO_SLEEPING();
+	dmar_ctx_unload(ctx, &entries, false);
+	THREAD_SLEEPING_OK();
+	KASSERT(TAILQ_EMPTY(&entries), ("lazy dmar_ctx_unload %p", ctx));
+#endif
+}
+
+static void
+dmar_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map,
+    bus_dmasync_op_t op)
+{
+}
+
+struct bus_dma_impl bus_dma_dmar_impl = {
+	.tag_create = dmar_bus_dma_tag_create,
+	.tag_destroy = dmar_bus_dma_tag_destroy,
+	.map_create = dmar_bus_dmamap_create,
+	.map_destroy = dmar_bus_dmamap_destroy,
+	.mem_alloc = dmar_bus_dmamem_alloc,
+	.mem_free = dmar_bus_dmamem_free,
+	.load_phys = dmar_bus_dmamap_load_phys,
+	.load_buffer = dmar_bus_dmamap_load_buffer,
+	.load_ma = dmar_bus_dmamap_load_ma,
+	.map_waitok = dmar_bus_dmamap_waitok,
+	.map_complete = dmar_bus_dmamap_complete,
+	.map_unload = dmar_bus_dmamap_unload,
+	.map_sync = dmar_bus_dmamap_sync
+};
+
+static void
+dmar_bus_task_dmamap(void *arg, int pending)
+{
+	struct bus_dma_tag_dmar *tag;
+	struct bus_dmamap_dmar *map;
+	struct dmar_unit *unit;
+
+	unit = arg;
+	DMAR_LOCK(unit);
+	while ((map = TAILQ_FIRST(&unit->delayed_maps)) != NULL) {
+		TAILQ_REMOVE(&unit->delayed_maps, map, delay_link);
+		DMAR_UNLOCK(unit);
+		tag = map->tag;
+		map->cansleep = true;
+		map->locked = false;
+		bus_dmamap_load_mem((bus_dma_tag_t)tag, (bus_dmamap_t)map,
+		    &map->mem, map->callback, map->callback_arg,
+		    BUS_DMA_WAITOK);
+		map->cansleep = false;
+		if (map->locked) {
+			(tag->common.lockfunc)(tag->common.lockfuncarg,
+			    BUS_DMA_UNLOCK);
+		} else
+			map->locked = true;
+		map->cansleep = false;
+		DMAR_LOCK(unit);
+	}
+	DMAR_UNLOCK(unit);
+}
+
+static void
+dmar_bus_schedule_dmamap(struct dmar_unit *unit, struct bus_dmamap_dmar *map)
+{
+
+	map->locked = false;
+	DMAR_LOCK(unit);
+	TAILQ_INSERT_TAIL(&unit->delayed_maps, map, delay_link);
+	DMAR_UNLOCK(unit);
+	taskqueue_enqueue(unit->delayed_taskqueue, &unit->dmamap_load_task);
+}
+
+int
+dmar_init_busdma(struct dmar_unit *unit)
+{
+
+	TAILQ_INIT(&unit->delayed_maps);
+	TASK_INIT(&unit->dmamap_load_task, 0, dmar_bus_task_dmamap, unit);
+	unit->delayed_taskqueue = taskqueue_create("dmar", M_WAITOK,
+	    taskqueue_thread_enqueue, &unit->delayed_taskqueue);
+	taskqueue_start_threads(&unit->delayed_taskqueue, 1, PI_DISK,
+	    "dmar%d busdma taskq", unit->unit);
+	return (0);
+}
+
+void
+dmar_fini_busdma(struct dmar_unit *unit)
+{
+
+	if (unit->delayed_taskqueue == NULL)
+		return;
+
+	taskqueue_drain(unit->delayed_taskqueue, &unit->dmamap_load_task);
+	taskqueue_free(unit->delayed_taskqueue);
+	unit->delayed_taskqueue = NULL;
+}


Property changes on: trunk/sys/x86/iommu/busdma_dmar.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/busdma_dmar.h
===================================================================
--- trunk/sys/x86/iommu/busdma_dmar.h	                        (rev 0)
+++ trunk/sys/x86/iommu/busdma_dmar.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,66 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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: stable/10/sys/x86/iommu/busdma_dmar.h 257251 2013-10-28 13:33:29Z kib $
+ */
+
+#ifndef __X86_IOMMU_BUSDMA_DMAR_H
+#define __X86_IOMMU_BUSDMA_DMAR_H
+
+struct dmar_map_entry;
+TAILQ_HEAD(dmar_map_entries_tailq, dmar_map_entry);
+
+struct bus_dma_tag_dmar {
+	struct bus_dma_tag_common common;
+	struct dmar_ctx *ctx;
+	device_t owner;
+	int map_count;
+	bus_dma_segment_t *segments;
+};
+
+struct bus_dmamap_dmar {
+	struct bus_dma_tag_dmar *tag;
+	struct memdesc mem;
+	bus_dmamap_callback_t *callback;
+	void *callback_arg;
+	struct dmar_map_entries_tailq map_entries;
+	TAILQ_ENTRY(bus_dmamap_dmar) delay_link;
+	bool locked;
+	bool cansleep;
+	int flags;
+};
+
+#define	BUS_DMAMAP_DMAR_MALLOC	0x0001
+#define	BUS_DMAMAP_DMAR_KMEM_ALLOC 0x0002
+
+extern struct bus_dma_impl bus_dma_dmar_impl;
+
+bus_dma_tag_t dmar_get_dma_tag(device_t dev, device_t child);
+
+#endif


Property changes on: trunk/sys/x86/iommu/busdma_dmar.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_ctx.c
===================================================================
--- trunk/sys/x86/iommu/intel_ctx.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_ctx.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,651 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_ctx.c 279485 2015-03-01 10:35:54Z kib $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+static MALLOC_DEFINE(M_DMAR_CTX, "dmar_ctx", "Intel DMAR Context");
+
+static void dmar_ctx_unload_task(void *arg, int pending);
+
+static void
+dmar_ensure_ctx_page(struct dmar_unit *dmar, int bus)
+{
+	struct sf_buf *sf;
+	dmar_root_entry_t *re;
+	vm_page_t ctxm;
+
+	/*
+	 * Allocated context page must be linked.
+	 */
+	ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, DMAR_PGF_NOALLOC);
+	if (ctxm != NULL)
+		return;
+
+	/*
+	 * Page not present, allocate and link.  Note that other
+	 * thread might execute this sequence in parallel.  This
+	 * should be safe, because the context entries written by both
+	 * threads are equal.
+	 */
+	TD_PREP_PINNED_ASSERT;
+	ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, DMAR_PGF_ZERO |
+	    DMAR_PGF_WAITOK);
+	re = dmar_map_pgtbl(dmar->ctx_obj, 0, DMAR_PGF_NOALLOC, &sf);
+	re += bus;
+	dmar_pte_store(&re->r1, DMAR_ROOT_R1_P | (DMAR_ROOT_R1_CTP_MASK &
+	    VM_PAGE_TO_PHYS(ctxm)));
+	dmar_flush_root_to_ram(dmar, re);
+	dmar_unmap_pgtbl(sf);
+	TD_PINNED_ASSERT;
+}
+
+static dmar_ctx_entry_t *
+dmar_map_ctx_entry(struct dmar_ctx *ctx, struct sf_buf **sfp)
+{
+	dmar_ctx_entry_t *ctxp;
+
+	ctxp = dmar_map_pgtbl(ctx->dmar->ctx_obj, 1 + PCI_RID2BUS(ctx->rid),
+	    DMAR_PGF_NOALLOC | DMAR_PGF_WAITOK, sfp);
+	ctxp += ctx->rid & 0xff;
+	return (ctxp);
+}
+
+static void
+ctx_tag_init(struct dmar_ctx *ctx, device_t dev)
+{
+	bus_addr_t maxaddr;
+
+	maxaddr = MIN(ctx->end, BUS_SPACE_MAXADDR);
+	ctx->ctx_tag.common.ref_count = 1; /* Prevent free */
+	ctx->ctx_tag.common.impl = &bus_dma_dmar_impl;
+	ctx->ctx_tag.common.boundary = PCI_DMA_BOUNDARY;
+	ctx->ctx_tag.common.lowaddr = maxaddr;
+	ctx->ctx_tag.common.highaddr = maxaddr;
+	ctx->ctx_tag.common.maxsize = maxaddr;
+	ctx->ctx_tag.common.nsegments = BUS_SPACE_UNRESTRICTED;
+	ctx->ctx_tag.common.maxsegsz = maxaddr;
+	ctx->ctx_tag.ctx = ctx;
+	ctx->ctx_tag.owner = dev;
+	/* XXXKIB initialize tag further */
+}
+
+static void
+ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp)
+{
+	struct dmar_unit *unit;
+	vm_page_t ctx_root;
+
+	unit = ctx->dmar;
+	KASSERT(ctxp->ctx1 == 0 && ctxp->ctx2 == 0,
+	    ("dmar%d: initialized ctx entry %d:%d:%d 0x%jx 0x%jx",
+	    unit->unit, pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner),
+	    ctxp->ctx1,
+	    ctxp->ctx2));
+	ctxp->ctx2 = DMAR_CTX2_DID(ctx->domain);
+	ctxp->ctx2 |= ctx->awlvl;
+	if ((ctx->flags & DMAR_CTX_IDMAP) != 0 &&
+	    (unit->hw_ecap & DMAR_ECAP_PT) != 0) {
+		KASSERT(ctx->pgtbl_obj == NULL,
+		    ("ctx %p non-null pgtbl_obj", ctx));
+		dmar_pte_store(&ctxp->ctx1, DMAR_CTX1_T_PASS | DMAR_CTX1_P);
+	} else {
+		ctx_root = dmar_pgalloc(ctx->pgtbl_obj, 0, DMAR_PGF_NOALLOC);
+		dmar_pte_store(&ctxp->ctx1, DMAR_CTX1_T_UNTR |
+		    (DMAR_CTX1_ASR_MASK & VM_PAGE_TO_PHYS(ctx_root)) |
+		    DMAR_CTX1_P);
+	}
+	dmar_flush_ctx_to_ram(unit, ctxp);
+}
+
+static int
+ctx_init_rmrr(struct dmar_ctx *ctx, device_t dev)
+{
+	struct dmar_map_entries_tailq rmrr_entries;
+	struct dmar_map_entry *entry, *entry1;
+	vm_page_t *ma;
+	dmar_gaddr_t start, end;
+	vm_pindex_t size, i;
+	int error, error1;
+
+	error = 0;
+	TAILQ_INIT(&rmrr_entries);
+	dmar_ctx_parse_rmrr(ctx, dev, &rmrr_entries);
+	TAILQ_FOREACH_SAFE(entry, &rmrr_entries, unroll_link, entry1) {
+		/*
+		 * VT-d specification requires that the start of an
+		 * RMRR entry is 4k-aligned.  Buggy BIOSes put
+		 * anything into the start and end fields.  Truncate
+		 * and round as neccesary.
+		 *
+		 * We also allow the overlapping RMRR entries, see
+		 * dmar_gas_alloc_region().
+		 */
+		start = entry->start;
+		end = entry->end;
+		entry->start = trunc_page(start);
+		entry->end = round_page(end);
+		if (entry->start == entry->end) {
+			/* Workaround for some AMI (?) BIOSes */
+			if (bootverbose) {
+				device_printf(dev, "BIOS bug: dmar%d RMRR "
+				    "region (%jx, %jx) corrected\n",
+				    ctx->dmar->unit, start, end);
+			}
+			entry->end += DMAR_PAGE_SIZE * 0x20;
+		}
+		size = OFF_TO_IDX(entry->end - entry->start);
+		ma = malloc(sizeof(vm_page_t) * size, M_TEMP, M_WAITOK);
+		for (i = 0; i < size; i++) {
+			ma[i] = vm_page_getfake(entry->start + PAGE_SIZE * i,
+			    VM_MEMATTR_DEFAULT);
+		}
+		error1 = dmar_gas_map_region(ctx, entry, DMAR_MAP_ENTRY_READ |
+		    DMAR_MAP_ENTRY_WRITE, DMAR_GM_CANWAIT, ma);
+		/*
+		 * Non-failed RMRR entries are owned by context rb
+		 * tree.  Get rid of the failed entry, but do not stop
+		 * the loop.  Rest of the parsed RMRR entries are
+		 * loaded and removed on the context destruction.
+		 */
+		if (error1 == 0 && entry->end != entry->start) {
+			DMAR_LOCK(ctx->dmar);
+			ctx->flags |= DMAR_CTX_RMRR;
+			DMAR_UNLOCK(ctx->dmar);
+		} else {
+			if (error1 != 0) {
+				device_printf(dev,
+			    "dmar%d failed to map RMRR region (%jx, %jx) %d\n",
+				    ctx->dmar->unit, start, end, error1);
+				error = error1;
+			}
+			TAILQ_REMOVE(&rmrr_entries, entry, unroll_link);
+			dmar_gas_free_entry(ctx, entry);
+		}
+		for (i = 0; i < size; i++)
+			vm_page_putfake(ma[i]);
+		free(ma, M_TEMP);
+	}
+	return (error);
+}
+
+static struct dmar_ctx *
+dmar_get_ctx_alloc(struct dmar_unit *dmar, uint16_t rid)
+{
+	struct dmar_ctx *ctx;
+
+	ctx = malloc(sizeof(*ctx), M_DMAR_CTX, M_WAITOK | M_ZERO);
+	RB_INIT(&ctx->rb_root);
+	TAILQ_INIT(&ctx->unload_entries);
+	TASK_INIT(&ctx->unload_task, 0, dmar_ctx_unload_task, ctx);
+	mtx_init(&ctx->lock, "dmarctx", NULL, MTX_DEF);
+	ctx->dmar = dmar;
+	ctx->rid = rid;
+	return (ctx);
+}
+
+static void
+dmar_ctx_dtr(struct dmar_ctx *ctx, bool gas_inited, bool pgtbl_inited)
+{
+
+	if (gas_inited) {
+		DMAR_CTX_LOCK(ctx);
+		dmar_gas_fini_ctx(ctx);
+		DMAR_CTX_UNLOCK(ctx);
+	}
+	if (pgtbl_inited) {
+		if (ctx->pgtbl_obj != NULL)
+			DMAR_CTX_PGLOCK(ctx);
+		ctx_free_pgtbl(ctx);
+	}
+	mtx_destroy(&ctx->lock);
+	free(ctx, M_DMAR_CTX);
+}
+
+struct dmar_ctx *
+dmar_get_ctx(struct dmar_unit *dmar, device_t dev, uint16_t rid, bool id_mapped,
+    bool rmrr_init)
+{
+	struct dmar_ctx *ctx, *ctx1;
+	dmar_ctx_entry_t *ctxp;
+	struct sf_buf *sf;
+	int bus, slot, func, error, mgaw;
+	bool enable;
+
+	bus = pci_get_bus(dev);
+	slot = pci_get_slot(dev);
+	func = pci_get_function(dev);
+	enable = false;
+	TD_PREP_PINNED_ASSERT;
+	DMAR_LOCK(dmar);
+	ctx = dmar_find_ctx_locked(dmar, rid);
+	error = 0;
+	if (ctx == NULL) {
+		/*
+		 * Perform the allocations which require sleep or have
+		 * higher chance to succeed if the sleep is allowed.
+		 */
+		DMAR_UNLOCK(dmar);
+		dmar_ensure_ctx_page(dmar, PCI_RID2BUS(rid));
+		ctx1 = dmar_get_ctx_alloc(dmar, rid);
+
+		if (id_mapped) {
+			/*
+			 * For now, use the maximal usable physical
+			 * address of the installed memory to
+			 * calculate the mgaw.  It is useful for the
+			 * identity mapping, and less so for the
+			 * virtualized bus address space.
+			 */
+			ctx1->end = ptoa(Maxmem);
+			mgaw = dmar_maxaddr2mgaw(dmar, ctx1->end, false);
+			error = ctx_set_agaw(ctx1, mgaw);
+			if (error != 0) {
+				dmar_ctx_dtr(ctx1, false, false);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+		} else {
+			ctx1->end = BUS_SPACE_MAXADDR;
+			mgaw = dmar_maxaddr2mgaw(dmar, ctx1->end, true);
+			error = ctx_set_agaw(ctx1, mgaw);
+			if (error != 0) {
+				dmar_ctx_dtr(ctx1, false, false);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+			/* Use all supported address space for remapping. */
+			ctx1->end = 1ULL << (ctx1->agaw - 1);
+		}
+
+
+		dmar_gas_init_ctx(ctx1);
+		if (id_mapped) {
+			if ((dmar->hw_ecap & DMAR_ECAP_PT) == 0) {
+				ctx1->pgtbl_obj = ctx_get_idmap_pgtbl(ctx1,
+				    ctx1->end);
+			}
+			ctx1->flags |= DMAR_CTX_IDMAP;
+		} else {
+			error = ctx_alloc_pgtbl(ctx1);
+			if (error != 0) {
+				dmar_ctx_dtr(ctx1, true, false);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+			/* Disable local apic region access */
+			error = dmar_gas_reserve_region(ctx1, 0xfee00000,
+			    0xfeefffff + 1);
+			if (error != 0) {
+				dmar_ctx_dtr(ctx1, true, true);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+			error = ctx_init_rmrr(ctx1, dev);
+			if (error != 0) {
+				dmar_ctx_dtr(ctx1, true, true);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+		}
+		ctxp = dmar_map_ctx_entry(ctx1, &sf);
+		DMAR_LOCK(dmar);
+
+		/*
+		 * Recheck the contexts, other thread might have
+		 * already allocated needed one.
+		 */
+		ctx = dmar_find_ctx_locked(dmar, rid);
+		if (ctx == NULL) {
+			ctx = ctx1;
+			ctx->ctx_tag.owner = dev;
+			ctx->domain = alloc_unrl(dmar->domids);
+			if (ctx->domain == -1) {
+				DMAR_UNLOCK(dmar);
+				dmar_unmap_pgtbl(sf);
+				dmar_ctx_dtr(ctx, true, true);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+			ctx_tag_init(ctx, dev);
+
+			/*
+			 * This is the first activated context for the
+			 * DMAR unit.  Enable the translation after
+			 * everything is set up.
+			 */
+			if (LIST_EMPTY(&dmar->contexts))
+				enable = true;
+			LIST_INSERT_HEAD(&dmar->contexts, ctx, link);
+			ctx_id_entry_init(ctx, ctxp);
+			device_printf(dev,
+			    "dmar%d pci%d:%d:%d:%d rid %x domain %d mgaw %d "
+			    "agaw %d %s-mapped\n",
+			    dmar->unit, dmar->segment, bus, slot,
+			    func, rid, ctx->domain, ctx->mgaw, ctx->agaw,
+			    id_mapped ? "id" : "re");
+		} else {
+			dmar_ctx_dtr(ctx1, true, true);
+		}
+		dmar_unmap_pgtbl(sf);
+	}
+	ctx->refs++;
+	if ((ctx->flags & DMAR_CTX_RMRR) != 0)
+		ctx->refs++; /* XXXKIB */
+
+	/*
+	 * If dmar declares Caching Mode as Set, follow 11.5 "Caching
+	 * Mode Consideration" and do the (global) invalidation of the
+	 * negative TLB entries.
+	 */
+	if ((dmar->hw_cap & DMAR_CAP_CM) != 0 || enable) {
+		if (dmar->qi_enabled) {
+			dmar_qi_invalidate_ctx_glob_locked(dmar);
+			if ((dmar->hw_ecap & DMAR_ECAP_DI) != 0)
+				dmar_qi_invalidate_iotlb_glob_locked(dmar);
+		} else {
+			error = dmar_inv_ctx_glob(dmar);
+			if (error == 0 &&
+			    (dmar->hw_ecap & DMAR_ECAP_DI) != 0)
+				error = dmar_inv_iotlb_glob(dmar);
+			if (error != 0) {
+				dmar_free_ctx_locked(dmar, ctx);
+				TD_PINNED_ASSERT;
+				return (NULL);
+			}
+		}
+	}
+
+	/*
+	 * The dmar lock was potentially dropped between check for the
+	 * empty context list and now.  Recheck the state of GCMD_TE
+	 * to avoid unneeded command.
+	 */
+	if (enable && !rmrr_init && (dmar->hw_gcmd & DMAR_GCMD_TE) == 0) {
+		error = dmar_enable_translation(dmar);
+		if (error != 0) {
+			dmar_free_ctx_locked(dmar, ctx);
+			TD_PINNED_ASSERT;
+			return (NULL);
+		}
+	}
+	DMAR_UNLOCK(dmar);
+	TD_PINNED_ASSERT;
+	return (ctx);
+}
+
+void
+dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
+{
+	struct sf_buf *sf;
+	dmar_ctx_entry_t *ctxp;
+
+	DMAR_ASSERT_LOCKED(dmar);
+	KASSERT(ctx->refs >= 1,
+	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
+
+	/*
+	 * If our reference is not last, only the dereference should
+	 * be performed.
+	 */
+	if (ctx->refs > 1) {
+		ctx->refs--;
+		DMAR_UNLOCK(dmar);
+		return;
+	}
+
+	KASSERT((ctx->flags & DMAR_CTX_RMRR) == 0,
+	    ("lost ref on RMRR ctx %p", ctx));
+	KASSERT((ctx->flags & DMAR_CTX_DISABLED) == 0,
+	    ("lost ref on disabled ctx %p", ctx));
+
+	/*
+	 * Otherwise, the context entry must be cleared before the
+	 * page table is destroyed.  The mapping of the context
+	 * entries page could require sleep, unlock the dmar.
+	 */
+	DMAR_UNLOCK(dmar);
+	TD_PREP_PINNED_ASSERT;
+	ctxp = dmar_map_ctx_entry(ctx, &sf);
+	DMAR_LOCK(dmar);
+	KASSERT(ctx->refs >= 1,
+	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
+
+	/*
+	 * Other thread might have referenced the context, in which
+	 * case again only the dereference should be performed.
+	 */
+	if (ctx->refs > 1) {
+		ctx->refs--;
+		DMAR_UNLOCK(dmar);
+		dmar_unmap_pgtbl(sf);
+		TD_PINNED_ASSERT;
+		return;
+	}
+
+	KASSERT((ctx->flags & DMAR_CTX_RMRR) == 0,
+	    ("lost ref on RMRR ctx %p", ctx));
+	KASSERT((ctx->flags & DMAR_CTX_DISABLED) == 0,
+	    ("lost ref on disabled ctx %p", ctx));
+
+	/*
+	 * Clear the context pointer and flush the caches.
+	 * XXXKIB: cannot do this if any RMRR entries are still present.
+	 */
+	dmar_pte_clear(&ctxp->ctx1);
+	ctxp->ctx2 = 0;
+	dmar_flush_ctx_to_ram(dmar, ctxp);
+	dmar_inv_ctx_glob(dmar);
+	if ((dmar->hw_ecap & DMAR_ECAP_DI) != 0) {
+		if (dmar->qi_enabled)
+			dmar_qi_invalidate_iotlb_glob_locked(dmar);
+		else
+			dmar_inv_iotlb_glob(dmar);
+	}
+	LIST_REMOVE(ctx, link);
+	DMAR_UNLOCK(dmar);
+
+	/*
+	 * The rest of the destruction is invisible for other users of
+	 * the dmar unit.
+	 */
+	taskqueue_drain(dmar->delayed_taskqueue, &ctx->unload_task);
+	KASSERT(TAILQ_EMPTY(&ctx->unload_entries),
+	    ("unfinished unloads %p", ctx));
+	dmar_unmap_pgtbl(sf);
+	free_unr(dmar->domids, ctx->domain);
+	dmar_ctx_dtr(ctx, true, true);
+	TD_PINNED_ASSERT;
+}
+
+void
+dmar_free_ctx(struct dmar_ctx *ctx)
+{
+	struct dmar_unit *dmar;
+
+	dmar = ctx->dmar;
+	DMAR_LOCK(dmar);
+	dmar_free_ctx_locked(dmar, ctx);
+}
+
+struct dmar_ctx *
+dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid)
+{
+	struct dmar_ctx *ctx;
+
+	DMAR_ASSERT_LOCKED(dmar);
+
+	LIST_FOREACH(ctx, &dmar->contexts, link) {
+		if (ctx->rid == rid)
+			return (ctx);
+	}
+	return (NULL);
+}
+
+void
+dmar_ctx_free_entry(struct dmar_map_entry *entry, bool free)
+{
+	struct dmar_ctx *ctx;
+
+	ctx = entry->ctx;
+	DMAR_CTX_LOCK(ctx);
+	if ((entry->flags & DMAR_MAP_ENTRY_RMRR) != 0)
+		dmar_gas_free_region(ctx, entry);
+	else
+		dmar_gas_free_space(ctx, entry);
+	DMAR_CTX_UNLOCK(ctx);
+	if (free)
+		dmar_gas_free_entry(ctx, entry);
+	else
+		entry->flags = 0;
+}
+
+void
+dmar_ctx_unload_entry(struct dmar_map_entry *entry, bool free)
+{
+	struct dmar_unit *unit;
+
+	unit = entry->ctx->dmar;
+	if (unit->qi_enabled) {
+		DMAR_LOCK(unit);
+		dmar_qi_invalidate_locked(entry->ctx, entry->start,
+		    entry->end - entry->start, &entry->gseq);
+		if (!free)
+			entry->flags |= DMAR_MAP_ENTRY_QI_NF;
+		TAILQ_INSERT_TAIL(&unit->tlb_flush_entries, entry, dmamap_link);
+		DMAR_UNLOCK(unit);
+	} else {
+		ctx_flush_iotlb_sync(entry->ctx, entry->start, entry->end -
+		    entry->start);
+		dmar_ctx_free_entry(entry, free);
+	}
+}
+
+void
+dmar_ctx_unload(struct dmar_ctx *ctx, struct dmar_map_entries_tailq *entries,
+    bool cansleep)
+{
+	struct dmar_unit *unit;
+	struct dmar_map_entry *entry, *entry1;
+	struct dmar_qi_genseq gseq;
+	int error;
+
+	unit = ctx->dmar;
+
+	TAILQ_FOREACH_SAFE(entry, entries, dmamap_link, entry1) {
+		KASSERT((entry->flags & DMAR_MAP_ENTRY_MAP) != 0,
+		    ("not mapped entry %p %p", ctx, entry));
+		error = ctx_unmap_buf(ctx, entry->start, entry->end -
+		    entry->start, cansleep ? DMAR_PGF_WAITOK : 0);
+		KASSERT(error == 0, ("unmap %p error %d", ctx, error));
+		if (!unit->qi_enabled) {
+			ctx_flush_iotlb_sync(ctx, entry->start,
+			    entry->end - entry->start);
+			TAILQ_REMOVE(entries, entry, dmamap_link);
+			dmar_ctx_free_entry(entry, true);
+		}
+	}
+	if (TAILQ_EMPTY(entries))
+		return;
+
+	KASSERT(unit->qi_enabled, ("loaded entry left"));
+	DMAR_LOCK(unit);
+	TAILQ_FOREACH(entry, entries, dmamap_link) {
+		entry->gseq.gen = 0;
+		entry->gseq.seq = 0;
+		dmar_qi_invalidate_locked(ctx, entry->start, entry->end -
+		    entry->start, TAILQ_NEXT(entry, dmamap_link) == NULL ?
+		    &gseq : NULL);
+	}
+	TAILQ_FOREACH_SAFE(entry, entries, dmamap_link, entry1) {
+		entry->gseq = gseq;
+		TAILQ_REMOVE(entries, entry, dmamap_link);
+		TAILQ_INSERT_TAIL(&unit->tlb_flush_entries, entry, dmamap_link);
+	}
+	DMAR_UNLOCK(unit);
+}	
+
+static void
+dmar_ctx_unload_task(void *arg, int pending)
+{
+	struct dmar_ctx *ctx;
+	struct dmar_map_entries_tailq entries;
+
+	ctx = arg;
+	TAILQ_INIT(&entries);
+
+	for (;;) {
+		DMAR_CTX_LOCK(ctx);
+		TAILQ_SWAP(&ctx->unload_entries, &entries, dmar_map_entry,
+		    dmamap_link);
+		DMAR_CTX_UNLOCK(ctx);
+		if (TAILQ_EMPTY(&entries))
+			break;
+		dmar_ctx_unload(ctx, &entries, true);
+	}
+}


Property changes on: trunk/sys/x86/iommu/intel_ctx.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_dmar.h
===================================================================
--- trunk/sys/x86/iommu/intel_dmar.h	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_dmar.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,436 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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: stable/10/sys/x86/iommu/intel_dmar.h 281545 2015-04-15 06:56:51Z kib $
+ */
+
+#ifndef __X86_IOMMU_INTEL_DMAR_H
+#define	__X86_IOMMU_INTEL_DMAR_H
+
+/* Host or physical memory address, after translation. */
+typedef uint64_t dmar_haddr_t;
+/* Guest or bus address, before translation. */
+typedef uint64_t dmar_gaddr_t;
+
+struct dmar_qi_genseq {
+	u_int gen;
+	uint32_t seq;
+};
+
+struct dmar_map_entry {
+	dmar_gaddr_t start;
+	dmar_gaddr_t end;
+	dmar_gaddr_t free_after;	/* Free space after the entry */
+	dmar_gaddr_t free_down;		/* Max free space below the
+					   current R/B tree node */
+	u_int flags;
+	TAILQ_ENTRY(dmar_map_entry) dmamap_link; /* Link for dmamap entries */
+	RB_ENTRY(dmar_map_entry) rb_entry;	 /* Links for ctx entries */
+	TAILQ_ENTRY(dmar_map_entry) unroll_link; /* Link for unroll after
+						    dmamap_load failure */
+	struct dmar_ctx *ctx;
+	struct dmar_qi_genseq gseq;
+};
+
+RB_HEAD(dmar_gas_entries_tree, dmar_map_entry);
+RB_PROTOTYPE(dmar_gas_entries_tree, dmar_map_entry, rb_entry,
+    dmar_gas_cmp_entries);
+
+#define	DMAR_MAP_ENTRY_PLACE	0x0001	/* Fake entry */
+#define	DMAR_MAP_ENTRY_RMRR	0x0002	/* Permanent, not linked by
+					   dmamap_link */
+#define	DMAR_MAP_ENTRY_MAP	0x0004	/* Busdma created, linked by
+					   dmamap_link */
+#define	DMAR_MAP_ENTRY_UNMAPPED	0x0010	/* No backing pages */
+#define	DMAR_MAP_ENTRY_QI_NF	0x0020	/* qi task, do not free entry */
+#define	DMAR_MAP_ENTRY_READ	0x1000	/* Read permitted */
+#define	DMAR_MAP_ENTRY_WRITE	0x2000	/* Write permitted */
+#define	DMAR_MAP_ENTRY_SNOOP	0x4000	/* Snoop */
+#define	DMAR_MAP_ENTRY_TM	0x8000	/* Transient */
+
+struct dmar_ctx {
+	uint16_t rid;	/* pci RID */
+	int domain;	/* DID */
+	int mgaw;	/* Real max address width */
+	int agaw;	/* Adjusted guest address width */
+	int pglvl;	/* The pagelevel */
+	int awlvl;	/* The pagelevel as the bitmask, to set in
+			   context entry */
+	dmar_gaddr_t end;/* Highest address + 1 in the guest AS */
+	u_int refs;	/* References to the context, from tags */
+	struct dmar_unit *dmar;
+	struct bus_dma_tag_dmar ctx_tag; /* Root tag */
+	struct mtx lock;
+	LIST_ENTRY(dmar_ctx) link;	/* Member in the dmar list */
+	vm_object_t pgtbl_obj;		/* Page table pages */
+	u_int flags;			/* Protected by dmar lock */
+	uint64_t last_fault_rec[2];	/* Last fault reported */
+	u_int entries_cnt;
+	u_long loads;
+	u_long unloads;
+	struct dmar_gas_entries_tree rb_root;
+	struct dmar_map_entries_tailq unload_entries; /* Entries to unload */
+	struct dmar_map_entry *first_place, *last_place;
+	struct task unload_task;
+};
+
+/* struct dmar_ctx flags */
+#define	DMAR_CTX_FAULTED	0x0001	/* Fault was reported,
+					   last_fault_rec is valid */
+#define	DMAR_CTX_IDMAP		0x0002	/* Context uses identity page table */
+#define	DMAR_CTX_RMRR		0x0004	/* Context contains RMRR entry,
+					   cannot be turned off */
+#define	DMAR_CTX_DISABLED	0x0008	/* Device is disabled, the
+					   ephemeral reference is kept
+					   to prevent context destruction */
+
+#define	DMAR_CTX_PGLOCK(ctx)	VM_OBJECT_WLOCK((ctx)->pgtbl_obj)
+#define	DMAR_CTX_PGTRYLOCK(ctx)	VM_OBJECT_TRYWLOCK((ctx)->pgtbl_obj)
+#define	DMAR_CTX_PGUNLOCK(ctx)	VM_OBJECT_WUNLOCK((ctx)->pgtbl_obj)
+#define	DMAR_CTX_ASSERT_PGLOCKED(ctx) \
+	VM_OBJECT_ASSERT_WLOCKED((ctx)->pgtbl_obj)
+
+#define	DMAR_CTX_LOCK(ctx)	mtx_lock(&(ctx)->lock)
+#define	DMAR_CTX_UNLOCK(ctx)	mtx_unlock(&(ctx)->lock)
+#define	DMAR_CTX_ASSERT_LOCKED(ctx) mtx_assert(&(ctx)->lock, MA_OWNED)
+
+struct dmar_msi_data {
+	int irq;
+	int irq_rid;
+	struct resource *irq_res;
+	void *intr_handle;
+	int (*handler)(void *);
+	int msi_data_reg;
+	int msi_addr_reg;
+	int msi_uaddr_reg;
+	void (*enable_intr)(struct dmar_unit *);
+	void (*disable_intr)(struct dmar_unit *);
+	const char *name;
+};
+
+#define	DMAR_INTR_FAULT		0
+#define	DMAR_INTR_QI		1
+#define	DMAR_INTR_TOTAL		2
+
+struct dmar_unit {
+	device_t dev;
+	int unit;
+	uint16_t segment;
+	uint64_t base;
+
+	/* Resources */
+	int reg_rid;
+	struct resource *regs;
+
+	struct dmar_msi_data intrs[DMAR_INTR_TOTAL];
+
+	/* Hardware registers cache */
+	uint32_t hw_ver;
+	uint64_t hw_cap;
+	uint64_t hw_ecap;
+	uint32_t hw_gcmd;
+
+	/* Data for being a dmar */
+	struct mtx lock;
+	LIST_HEAD(, dmar_ctx) contexts;
+	struct unrhdr *domids;
+	vm_object_t ctx_obj;
+	u_int barrier_flags;
+
+	/* Fault handler data */
+	struct mtx fault_lock;
+	uint64_t *fault_log;
+	int fault_log_head;
+	int fault_log_tail;
+	int fault_log_size;
+	struct task fault_task;
+	struct taskqueue *fault_taskqueue;
+
+	/* QI */
+	int qi_enabled;
+	vm_offset_t inv_queue;
+	vm_size_t inv_queue_size;
+	uint32_t inv_queue_avail;
+	uint32_t inv_queue_tail;
+	volatile uint32_t inv_waitd_seq_hw; /* hw writes there on wait
+					       descr completion */
+	uint64_t inv_waitd_seq_hw_phys;
+	uint32_t inv_waitd_seq; /* next sequence number to use for wait descr */
+	u_int inv_waitd_gen;	/* seq number generation AKA seq overflows */
+	u_int inv_seq_waiters;	/* count of waiters for seq */
+	u_int inv_queue_full;	/* informational counter */
+
+	/* Delayed freeing of map entries queue processing */
+	struct dmar_map_entries_tailq tlb_flush_entries;
+	struct task qi_task;
+	struct taskqueue *qi_taskqueue;
+
+	/* Busdma delayed map load */
+	struct task dmamap_load_task;
+	TAILQ_HEAD(, bus_dmamap_dmar) delayed_maps;
+	struct taskqueue *delayed_taskqueue;
+};
+
+#define	DMAR_LOCK(dmar)		mtx_lock(&(dmar)->lock)
+#define	DMAR_UNLOCK(dmar)	mtx_unlock(&(dmar)->lock)
+#define	DMAR_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->lock, MA_OWNED)
+
+#define	DMAR_FAULT_LOCK(dmar)	mtx_lock_spin(&(dmar)->fault_lock)
+#define	DMAR_FAULT_UNLOCK(dmar)	mtx_unlock_spin(&(dmar)->fault_lock)
+#define	DMAR_FAULT_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->fault_lock, MA_OWNED)
+
+#define	DMAR_IS_COHERENT(dmar)	(((dmar)->hw_ecap & DMAR_ECAP_C) != 0)
+#define	DMAR_HAS_QI(dmar)	(((dmar)->hw_ecap & DMAR_ECAP_QI) != 0)
+
+/* Barrier ids */
+#define	DMAR_BARRIER_RMRR	0
+#define	DMAR_BARRIER_USEQ	1
+
+struct dmar_unit *dmar_find(device_t dev);
+
+u_int dmar_nd2mask(u_int nd);
+bool dmar_pglvl_supported(struct dmar_unit *unit, int pglvl);
+int ctx_set_agaw(struct dmar_ctx *ctx, int mgaw);
+int dmar_maxaddr2mgaw(struct dmar_unit* unit, dmar_gaddr_t maxaddr,
+    bool allow_less);
+vm_pindex_t pglvl_max_pages(int pglvl);
+int ctx_is_sp_lvl(struct dmar_ctx *ctx, int lvl);
+dmar_gaddr_t pglvl_page_size(int total_pglvl, int lvl);
+dmar_gaddr_t ctx_page_size(struct dmar_ctx *ctx, int lvl);
+int calc_am(struct dmar_unit *unit, dmar_gaddr_t base, dmar_gaddr_t size,
+    dmar_gaddr_t *isizep);
+struct vm_page *dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags);
+void dmar_pgfree(vm_object_t obj, vm_pindex_t idx, int flags);
+void *dmar_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
+    struct sf_buf **sf);
+void dmar_unmap_pgtbl(struct sf_buf *sf);
+int dmar_load_root_entry_ptr(struct dmar_unit *unit);
+int dmar_inv_ctx_glob(struct dmar_unit *unit);
+int dmar_inv_iotlb_glob(struct dmar_unit *unit);
+int dmar_flush_write_bufs(struct dmar_unit *unit);
+void dmar_flush_pte_to_ram(struct dmar_unit *unit, dmar_pte_t *dst);
+void dmar_flush_ctx_to_ram(struct dmar_unit *unit, dmar_ctx_entry_t *dst);
+void dmar_flush_root_to_ram(struct dmar_unit *unit, dmar_root_entry_t *dst);
+int dmar_enable_translation(struct dmar_unit *unit);
+int dmar_disable_translation(struct dmar_unit *unit);
+bool dmar_barrier_enter(struct dmar_unit *dmar, u_int barrier_id);
+void dmar_barrier_exit(struct dmar_unit *dmar, u_int barrier_id);
+
+int dmar_fault_intr(void *arg);
+void dmar_enable_fault_intr(struct dmar_unit *unit);
+void dmar_disable_fault_intr(struct dmar_unit *unit);
+int dmar_init_fault_log(struct dmar_unit *unit);
+void dmar_fini_fault_log(struct dmar_unit *unit);
+
+int dmar_qi_intr(void *arg);
+void dmar_enable_qi_intr(struct dmar_unit *unit);
+void dmar_disable_qi_intr(struct dmar_unit *unit);
+int dmar_init_qi(struct dmar_unit *unit);
+void dmar_fini_qi(struct dmar_unit *unit);
+void dmar_qi_invalidate_locked(struct dmar_ctx *ctx, dmar_gaddr_t start,
+    dmar_gaddr_t size, struct dmar_qi_genseq *pseq);
+void dmar_qi_invalidate_ctx_glob_locked(struct dmar_unit *unit);
+void dmar_qi_invalidate_iotlb_glob_locked(struct dmar_unit *unit);
+
+vm_object_t ctx_get_idmap_pgtbl(struct dmar_ctx *ctx, dmar_gaddr_t maxaddr);
+void put_idmap_pgtbl(vm_object_t obj);
+int ctx_map_buf(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size,
+    vm_page_t *ma, uint64_t pflags, int flags);
+int ctx_unmap_buf(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size,
+    int flags);
+void ctx_flush_iotlb_sync(struct dmar_ctx *ctx, dmar_gaddr_t base,
+    dmar_gaddr_t size);
+int ctx_alloc_pgtbl(struct dmar_ctx *ctx);
+void ctx_free_pgtbl(struct dmar_ctx *ctx);
+
+struct dmar_ctx *dmar_instantiate_ctx(struct dmar_unit *dmar, device_t dev,
+    bool rmrr);
+struct dmar_ctx *dmar_get_ctx(struct dmar_unit *dmar, device_t dev, 
+    uint16_t rid, bool id_mapped, bool rmrr_init);
+void dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx);
+void dmar_free_ctx(struct dmar_ctx *ctx);
+struct dmar_ctx *dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid);
+void dmar_ctx_unload_entry(struct dmar_map_entry *entry, bool free);
+void dmar_ctx_unload(struct dmar_ctx *ctx,
+    struct dmar_map_entries_tailq *entries, bool cansleep);
+void dmar_ctx_free_entry(struct dmar_map_entry *entry, bool free);
+
+int dmar_init_busdma(struct dmar_unit *unit);
+void dmar_fini_busdma(struct dmar_unit *unit);
+
+void dmar_gas_init_ctx(struct dmar_ctx *ctx);
+void dmar_gas_fini_ctx(struct dmar_ctx *ctx);
+struct dmar_map_entry *dmar_gas_alloc_entry(struct dmar_ctx *ctx, u_int flags);
+void dmar_gas_free_entry(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
+void dmar_gas_free_space(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
+int dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
+    dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
+    struct dmar_map_entry **res);
+void dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
+int dmar_gas_map_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry,
+    u_int eflags, u_int flags, vm_page_t *ma);
+int dmar_gas_reserve_region(struct dmar_ctx *ctx, dmar_gaddr_t start,
+    dmar_gaddr_t end);
+
+void dmar_ctx_parse_rmrr(struct dmar_ctx *ctx, device_t dev,
+    struct dmar_map_entries_tailq *rmrr_entries);
+int dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar);
+
+void dmar_quirks_post_ident(struct dmar_unit *dmar);
+void dmar_quirks_pre_use(struct dmar_unit *dmar);
+
+#define	DMAR_GM_CANWAIT	0x0001
+#define	DMAR_GM_CANSPLIT 0x0002
+
+#define	DMAR_PGF_WAITOK	0x0001
+#define	DMAR_PGF_ZERO	0x0002
+#define	DMAR_PGF_ALLOC	0x0004
+#define	DMAR_PGF_NOALLOC 0x0008
+#define	DMAR_PGF_OBJL	0x0010
+
+extern dmar_haddr_t dmar_high;
+extern int haw;
+extern int dmar_tbl_pagecnt;
+extern int dmar_match_verbose;
+extern int dmar_check_free;
+
+static inline uint32_t
+dmar_read4(const struct dmar_unit *unit, int reg)
+{
+
+	return (bus_read_4(unit->regs, reg));
+}
+
+static inline uint64_t
+dmar_read8(const struct dmar_unit *unit, int reg)
+{
+#ifdef __i386__
+	uint32_t high, low;
+
+	low = bus_read_4(unit->regs, reg);
+	high = bus_read_4(unit->regs, reg + 4);
+	return (low | ((uint64_t)high << 32));
+#else
+	return (bus_read_8(unit->regs, reg));
+#endif
+}
+
+static inline void
+dmar_write4(const struct dmar_unit *unit, int reg, uint32_t val)
+{
+
+	KASSERT(reg != DMAR_GCMD_REG || (val & DMAR_GCMD_TE) ==
+	    (unit->hw_gcmd & DMAR_GCMD_TE),
+	    ("dmar%d clearing TE 0x%08x 0x%08x", unit->unit,
+	    unit->hw_gcmd, val));
+	bus_write_4(unit->regs, reg, val);
+}
+
+static inline void
+dmar_write8(const struct dmar_unit *unit, int reg, uint64_t val)
+{
+
+	KASSERT(reg != DMAR_GCMD_REG, ("8byte GCMD write"));
+#ifdef __i386__
+	uint32_t high, low;
+
+	low = val;
+	high = val >> 32;
+	bus_write_4(unit->regs, reg, low);
+	bus_write_4(unit->regs, reg + 4, high);
+#else
+	bus_write_8(unit->regs, reg, val);
+#endif
+}
+
+/*
+ * dmar_pte_store and dmar_pte_clear ensure that on i386, 32bit writes
+ * are issued in the correct order.  For store, the lower word,
+ * containing the P or R and W bits, is set only after the high word
+ * is written.  For clear, the P bit is cleared first, then the high
+ * word is cleared.
+ */
+static inline void
+dmar_pte_store(volatile uint64_t *dst, uint64_t val)
+{
+
+	KASSERT(*dst == 0, ("used pte %p oldval %jx newval %jx",
+	    dst, (uintmax_t)*dst, (uintmax_t)val));
+#ifdef __i386__
+	volatile uint32_t *p;
+	uint32_t hi, lo;
+
+	hi = val >> 32;
+	lo = val;
+	p = (volatile uint32_t *)dst;
+	*(p + 1) = hi;
+	*p = lo;
+#else
+	*dst = val;
+#endif
+}
+
+static inline void
+dmar_pte_clear(volatile uint64_t *dst)
+{
+#ifdef __i386__
+	volatile uint32_t *p;
+
+	p = (volatile uint32_t *)dst;
+	*p = 0;
+	*(p + 1) = 0;
+#else
+	*dst = 0;
+#endif
+}
+
+static inline bool
+dmar_test_boundary(dmar_gaddr_t start, dmar_gaddr_t size,
+    dmar_gaddr_t boundary)
+{
+
+	if (boundary == 0)
+		return (true);
+	return (start + size <= ((start + boundary) & ~(boundary - 1)));
+}
+
+#ifdef INVARIANTS
+#define	TD_PREP_PINNED_ASSERT						\
+	int old_td_pinned;						\
+	old_td_pinned = curthread->td_pinned
+#define	TD_PINNED_ASSERT						\
+	KASSERT(curthread->td_pinned == old_td_pinned,			\
+	    ("pin count leak: %d %d %s:%d", curthread->td_pinned,	\
+	    old_td_pinned, __FILE__, __LINE__))
+#else
+#define	TD_PREP_PINNED_ASSERT
+#define	TD_PINNED_ASSERT
+#endif
+
+#endif


Property changes on: trunk/sys/x86/iommu/intel_dmar.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_drv.c
===================================================================
--- trunk/sys/x86/iommu/intel_drv.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_drv.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,1188 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_drv.c 279470 2015-03-01 04:22:06Z rstone $");
+
+#include "opt_acpi.h"
+#if defined(__amd64__) /* || defined(__ia64__) */
+#define	DEV_APIC
+#else
+#include "opt_apic.h"
+#endif
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/memdesc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/rwlock.h>
+#include <sys/smp.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <machine/bus.h>
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+#include <dev/pci/pcivar.h>
+
+#ifdef DEV_APIC
+#include "pcib_if.h"
+#endif
+
+#define	DMAR_FAULT_IRQ_RID	0
+#define	DMAR_QI_IRQ_RID		1
+#define	DMAR_REG_RID		2
+
+static devclass_t dmar_devclass;
+static device_t *dmar_devs;
+static int dmar_devcnt;
+
+typedef int (*dmar_iter_t)(ACPI_DMAR_HEADER *, void *);
+
+static void
+dmar_iterate_tbl(dmar_iter_t iter, void *arg)
+{
+	ACPI_TABLE_DMAR *dmartbl;
+	ACPI_DMAR_HEADER *dmarh;
+	char *ptr, *ptrend;
+	ACPI_STATUS status;
+
+	status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl);
+	if (ACPI_FAILURE(status))
+		return;
+	ptr = (char *)dmartbl + sizeof(*dmartbl);
+	ptrend = (char *)dmartbl + dmartbl->Header.Length;
+	for (;;) {
+		if (ptr >= ptrend)
+			break;
+		dmarh = (ACPI_DMAR_HEADER *)ptr;
+		if (dmarh->Length <= 0) {
+			printf("dmar_identify: corrupted DMAR table, l %d\n",
+			    dmarh->Length);
+			break;
+		}
+		ptr += dmarh->Length;
+		if (!iter(dmarh, arg))
+			break;
+	}
+}
+
+struct find_iter_args {
+	int i;
+	ACPI_DMAR_HARDWARE_UNIT *res;
+};
+
+static int
+dmar_find_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
+{
+	struct find_iter_args *fia;
+
+	if (dmarh->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT)
+		return (1);
+
+	fia = arg;
+	if (fia->i == 0) {
+		fia->res = (ACPI_DMAR_HARDWARE_UNIT *)dmarh;
+		return (0);
+	}
+	fia->i--;
+	return (1);
+}
+
+static ACPI_DMAR_HARDWARE_UNIT *
+dmar_find_by_index(int idx)
+{
+	struct find_iter_args fia;
+
+	fia.i = idx;
+	fia.res = NULL;
+	dmar_iterate_tbl(dmar_find_iter, &fia);
+	return (fia.res);
+}
+
+static int
+dmar_count_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
+{
+
+	if (dmarh->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT)
+		dmar_devcnt++;
+	return (1);
+}
+
+static int dmar_enable = 0;
+static void
+dmar_identify(driver_t *driver, device_t parent)
+{
+	ACPI_TABLE_DMAR *dmartbl;
+	ACPI_DMAR_HARDWARE_UNIT *dmarh;
+	ACPI_STATUS status;
+	int i, error;
+
+	if (acpi_disabled("dmar"))
+		return;
+	TUNABLE_INT_FETCH("hw.dmar.enable", &dmar_enable);
+	if (!dmar_enable)
+		return;
+#ifdef INVARIANTS
+	TUNABLE_INT_FETCH("hw.dmar.check_free", &dmar_check_free);
+#endif
+	TUNABLE_INT_FETCH("hw.dmar.match_verbose", &dmar_match_verbose);
+	status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl);
+	if (ACPI_FAILURE(status))
+		return;
+	haw = dmartbl->Width + 1;
+	if ((1ULL << (haw + 1)) > BUS_SPACE_MAXADDR)
+		dmar_high = BUS_SPACE_MAXADDR;
+	else
+		dmar_high = 1ULL << (haw + 1);
+	if (bootverbose) {
+		printf("DMAR HAW=%d flags=<%b>\n", dmartbl->Width,
+		    (unsigned)dmartbl->Flags,
+		    "\020\001INTR_REMAP\002X2APIC_OPT_OUT");
+	}
+
+	dmar_iterate_tbl(dmar_count_iter, NULL);
+	if (dmar_devcnt == 0)
+		return;
+	dmar_devs = malloc(sizeof(device_t) * dmar_devcnt, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	for (i = 0; i < dmar_devcnt; i++) {
+		dmarh = dmar_find_by_index(i);
+		if (dmarh == NULL) {
+			printf("dmar_identify: cannot find HWUNIT %d\n", i);
+			continue;
+		}
+		dmar_devs[i] = BUS_ADD_CHILD(parent, 1, "dmar", i);
+		if (dmar_devs[i] == NULL) {
+			printf("dmar_identify: cannot create instance %d\n", i);
+			continue;
+		}
+		error = bus_set_resource(dmar_devs[i], SYS_RES_MEMORY,
+		    DMAR_REG_RID, dmarh->Address, PAGE_SIZE);
+		if (error != 0) {
+			printf(
+	"dmar%d: unable to alloc register window at 0x%08jx: error %d\n",
+			    i, (uintmax_t)dmarh->Address, error);
+			device_delete_child(parent, dmar_devs[i]);
+			dmar_devs[i] = NULL;
+		}
+	}
+}
+
+static int
+dmar_probe(device_t dev)
+{
+
+	if (acpi_get_handle(dev) != NULL)
+		return (ENXIO);
+	device_set_desc(dev, "DMA remap");
+	return (BUS_PROBE_NOWILDCARD);
+}
+
+static void
+dmar_release_intr(device_t dev, struct dmar_unit *unit, int idx)
+{
+	struct dmar_msi_data *dmd;
+
+	dmd = &unit->intrs[idx];
+	if (dmd->irq == -1)
+		return;
+	bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle);
+	bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res);
+	bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid);
+	PCIB_RELEASE_MSIX(device_get_parent(device_get_parent(dev)),
+	    dev, dmd->irq);
+	dmd->irq = -1;
+}
+
+static void
+dmar_release_resources(device_t dev, struct dmar_unit *unit)
+{
+	int i;
+
+	dmar_fini_busdma(unit);
+	dmar_fini_qi(unit);
+	dmar_fini_fault_log(unit);
+	for (i = 0; i < DMAR_INTR_TOTAL; i++)
+		dmar_release_intr(dev, unit, i);
+	if (unit->regs != NULL) {
+		bus_deactivate_resource(dev, SYS_RES_MEMORY, unit->reg_rid,
+		    unit->regs);
+		bus_release_resource(dev, SYS_RES_MEMORY, unit->reg_rid,
+		    unit->regs);
+		unit->regs = NULL;
+	}
+	if (unit->domids != NULL) {
+		delete_unrhdr(unit->domids);
+		unit->domids = NULL;
+	}
+	if (unit->ctx_obj != NULL) {
+		vm_object_deallocate(unit->ctx_obj);
+		unit->ctx_obj = NULL;
+	}
+}
+
+static int
+dmar_alloc_irq(device_t dev, struct dmar_unit *unit, int idx)
+{
+	device_t pcib;
+	struct dmar_msi_data *dmd;
+	uint64_t msi_addr;
+	uint32_t msi_data;
+	int error;
+
+	dmd = &unit->intrs[idx];
+	pcib = device_get_parent(device_get_parent(dev)); /* Really not pcib */
+	error = PCIB_ALLOC_MSIX(pcib, dev, &dmd->irq);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate %s interrupt, %d\n",
+		    dmd->name, error);
+		goto err1;
+	}
+	error = bus_set_resource(dev, SYS_RES_IRQ, dmd->irq_rid,
+	    dmd->irq, 1);
+	if (error != 0) {
+		device_printf(dev, "cannot set %s interrupt resource, %d\n",
+		    dmd->name, error);
+		goto err2;
+	}
+	dmd->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &dmd->irq_rid, RF_ACTIVE);
+	if (dmd->irq_res == NULL) {
+		device_printf(dev,
+		    "cannot allocate resource for %s interrupt\n", dmd->name);
+		error = ENXIO;
+		goto err3;
+	}
+	error = bus_setup_intr(dev, dmd->irq_res, INTR_TYPE_MISC,
+	    dmd->handler, NULL, unit, &dmd->intr_handle);
+	if (error != 0) {
+		device_printf(dev, "cannot setup %s interrupt, %d\n",
+		    dmd->name, error);
+		goto err4;
+	}
+	bus_describe_intr(dev, dmd->irq_res, dmd->intr_handle, dmd->name);
+	error = PCIB_MAP_MSI(pcib, dev, dmd->irq, &msi_addr, &msi_data);
+	if (error != 0) {
+		device_printf(dev, "cannot map %s interrupt, %d\n",
+		    dmd->name, error);
+		goto err5;
+	}
+	dmar_write4(unit, dmd->msi_data_reg, msi_data);
+	dmar_write4(unit, dmd->msi_addr_reg, msi_addr);
+	/* Only for xAPIC mode */
+	dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32);
+	return (0);
+
+err5:
+	bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle);
+err4:
+	bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res);
+err3:
+	bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid);
+err2:
+	PCIB_RELEASE_MSIX(pcib, dev, dmd->irq);
+	dmd->irq = -1;
+err1:
+	return (error);
+}
+
+#ifdef DEV_APIC
+static int
+dmar_remap_intr(device_t dev, device_t child, u_int irq)
+{
+	struct dmar_unit *unit;
+	struct dmar_msi_data *dmd;
+	uint64_t msi_addr;
+	uint32_t msi_data;
+	int i, error;
+
+	unit = device_get_softc(dev);
+	for (i = 0; i < DMAR_INTR_TOTAL; i++) {
+		dmd = &unit->intrs[i];
+		if (irq == dmd->irq) {
+			error = PCIB_MAP_MSI(device_get_parent(
+			    device_get_parent(dev)),
+			    dev, irq, &msi_addr, &msi_data);
+			if (error != 0)
+				return (error);
+			DMAR_LOCK(unit);
+			(dmd->disable_intr)(unit);
+			dmar_write4(unit, dmd->msi_data_reg, msi_data);
+			dmar_write4(unit, dmd->msi_addr_reg, msi_addr);
+			dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32);
+			(dmd->enable_intr)(unit);
+			DMAR_UNLOCK(unit);
+			return (0);
+		}
+	}
+	return (ENOENT);
+}
+#endif
+
+static void
+dmar_print_caps(device_t dev, struct dmar_unit *unit,
+    ACPI_DMAR_HARDWARE_UNIT *dmaru)
+{
+	uint32_t caphi, ecaphi;
+
+	device_printf(dev, "regs at 0x%08jx, ver=%d.%d, seg=%d, flags=<%b>\n",
+	    (uintmax_t)dmaru->Address, DMAR_MAJOR_VER(unit->hw_ver),
+	    DMAR_MINOR_VER(unit->hw_ver), dmaru->Segment,
+	    dmaru->Flags, "\020\001INCLUDE_ALL_PCI");
+	caphi = unit->hw_cap >> 32;
+	device_printf(dev, "cap=%b,", (u_int)unit->hw_cap,
+	    "\020\004AFL\005WBF\006PLMR\007PHMR\010CM\027ZLR\030ISOCH");
+	printf("%b, ", caphi, "\020\010PSI\027DWD\030DRD\031FL1GP\034PSI");
+	printf("ndoms=%d, sagaw=%d, mgaw=%d, fro=%d, nfr=%d, superp=%d",
+	    DMAR_CAP_ND(unit->hw_cap), DMAR_CAP_SAGAW(unit->hw_cap),
+	    DMAR_CAP_MGAW(unit->hw_cap), DMAR_CAP_FRO(unit->hw_cap),
+	    DMAR_CAP_NFR(unit->hw_cap), DMAR_CAP_SPS(unit->hw_cap));
+	if ((unit->hw_cap & DMAR_CAP_PSI) != 0)
+		printf(", mamv=%d", DMAR_CAP_MAMV(unit->hw_cap));
+	printf("\n");
+	ecaphi = unit->hw_ecap >> 32;
+	device_printf(dev, "ecap=%b,", (u_int)unit->hw_ecap,
+	    "\020\001C\002QI\003DI\004IR\005EIM\007PT\010SC\031ECS\032MTS"
+	    "\033NEST\034DIS\035PASID\036PRS\037ERS\040SRS");
+	printf("%b, ", ecaphi, "\020\002NWFS\003EAFS");
+	printf("mhmw=%d, iro=%d\n", DMAR_ECAP_MHMV(unit->hw_ecap),
+	    DMAR_ECAP_IRO(unit->hw_ecap));
+}
+
+static int
+dmar_attach(device_t dev)
+{
+	struct dmar_unit *unit;
+	ACPI_DMAR_HARDWARE_UNIT *dmaru;
+	int i, error;
+
+	unit = device_get_softc(dev);
+	unit->dev = dev;
+	unit->unit = device_get_unit(dev);
+	dmaru = dmar_find_by_index(unit->unit);
+	if (dmaru == NULL)
+		return (EINVAL);
+	unit->segment = dmaru->Segment;
+	unit->base = dmaru->Address;
+	unit->reg_rid = DMAR_REG_RID;
+	unit->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &unit->reg_rid, RF_ACTIVE);
+	if (unit->regs == NULL) {
+		device_printf(dev, "cannot allocate register window\n");
+		return (ENOMEM);
+	}
+	unit->hw_ver = dmar_read4(unit, DMAR_VER_REG);
+	unit->hw_cap = dmar_read8(unit, DMAR_CAP_REG);
+	unit->hw_ecap = dmar_read8(unit, DMAR_ECAP_REG);
+	if (bootverbose)
+		dmar_print_caps(dev, unit, dmaru);
+	dmar_quirks_post_ident(unit);
+
+	for (i = 0; i < DMAR_INTR_TOTAL; i++)
+		unit->intrs[i].irq = -1;
+
+	unit->intrs[DMAR_INTR_FAULT].name = "fault";
+	unit->intrs[DMAR_INTR_FAULT].irq_rid = DMAR_FAULT_IRQ_RID;
+	unit->intrs[DMAR_INTR_FAULT].handler = dmar_fault_intr;
+	unit->intrs[DMAR_INTR_FAULT].msi_data_reg = DMAR_FEDATA_REG;
+	unit->intrs[DMAR_INTR_FAULT].msi_addr_reg = DMAR_FEADDR_REG;
+	unit->intrs[DMAR_INTR_FAULT].msi_uaddr_reg = DMAR_FEUADDR_REG;
+	unit->intrs[DMAR_INTR_FAULT].enable_intr = dmar_enable_fault_intr;
+	unit->intrs[DMAR_INTR_FAULT].disable_intr = dmar_disable_fault_intr;
+	error = dmar_alloc_irq(dev, unit, DMAR_INTR_FAULT);
+	if (error != 0) {
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	if (DMAR_HAS_QI(unit)) {
+		unit->intrs[DMAR_INTR_QI].name = "qi";
+		unit->intrs[DMAR_INTR_QI].irq_rid = DMAR_QI_IRQ_RID;
+		unit->intrs[DMAR_INTR_QI].handler = dmar_qi_intr;
+		unit->intrs[DMAR_INTR_QI].msi_data_reg = DMAR_IEDATA_REG;
+		unit->intrs[DMAR_INTR_QI].msi_addr_reg = DMAR_IEADDR_REG;
+		unit->intrs[DMAR_INTR_QI].msi_uaddr_reg = DMAR_IEUADDR_REG;
+		unit->intrs[DMAR_INTR_QI].enable_intr = dmar_enable_qi_intr;
+		unit->intrs[DMAR_INTR_QI].disable_intr = dmar_disable_qi_intr;
+		error = dmar_alloc_irq(dev, unit, DMAR_INTR_QI);
+		if (error != 0) {
+			dmar_release_resources(dev, unit);
+			return (error);
+		}
+	}
+
+	mtx_init(&unit->lock, "dmarhw", NULL, MTX_DEF);
+	unit->domids = new_unrhdr(0, dmar_nd2mask(DMAR_CAP_ND(unit->hw_cap)),
+	    &unit->lock);
+
+	/*
+	 * 9.2 "Context Entry":
+	 * When Caching Mode (CM) field is reported as Set, the
+	 * domain-id value of zero is architecturally reserved.
+	 * Software must not use domain-id value of zero
+	 * when CM is Set.
+	 */
+	if ((unit->hw_cap & DMAR_CAP_CM) != 0)
+		alloc_unr_specific(unit->domids, 0);
+
+	unit->ctx_obj = vm_pager_allocate(OBJT_PHYS, NULL, IDX_TO_OFF(1 +
+	    DMAR_CTX_CNT), 0, 0, NULL);
+
+	/*
+	 * Allocate and load the root entry table pointer.  Enable the
+	 * address translation after the required invalidations are
+	 * done.
+	 */
+	dmar_pgalloc(unit->ctx_obj, 0, DMAR_PGF_WAITOK | DMAR_PGF_ZERO);
+	DMAR_LOCK(unit);
+	error = dmar_load_root_entry_ptr(unit);
+	if (error != 0) {
+		DMAR_UNLOCK(unit);
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	error = dmar_inv_ctx_glob(unit);
+	if (error != 0) {
+		DMAR_UNLOCK(unit);
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	if ((unit->hw_ecap & DMAR_ECAP_DI) != 0) {
+		error = dmar_inv_iotlb_glob(unit);
+		if (error != 0) {
+			DMAR_UNLOCK(unit);
+			dmar_release_resources(dev, unit);
+			return (error);
+		}
+	}
+
+	DMAR_UNLOCK(unit);
+	error = dmar_init_fault_log(unit);
+	if (error != 0) {
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	error = dmar_init_qi(unit);
+	if (error != 0) {
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	error = dmar_init_busdma(unit);
+	if (error != 0) {
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+
+#ifdef NOTYET
+	DMAR_LOCK(unit);
+	error = dmar_enable_translation(unit);
+	if (error != 0) {
+		DMAR_UNLOCK(unit);
+		dmar_release_resources(dev, unit);
+		return (error);
+	}
+	DMAR_UNLOCK(unit);
+#endif
+
+	return (0);
+}
+
+static int
+dmar_detach(device_t dev)
+{
+
+	return (EBUSY);
+}
+
+static int
+dmar_suspend(device_t dev)
+{
+
+	return (0);
+}
+
+static int
+dmar_resume(device_t dev)
+{
+
+	/* XXXKIB */
+	return (0);
+}
+
+static device_method_t dmar_methods[] = {
+	DEVMETHOD(device_identify, dmar_identify),
+	DEVMETHOD(device_probe, dmar_probe),
+	DEVMETHOD(device_attach, dmar_attach),
+	DEVMETHOD(device_detach, dmar_detach),
+	DEVMETHOD(device_suspend, dmar_suspend),
+	DEVMETHOD(device_resume, dmar_resume),
+#ifdef DEV_APIC
+	DEVMETHOD(bus_remap_intr, dmar_remap_intr),
+#endif
+	DEVMETHOD_END
+};
+
+static driver_t	dmar_driver = {
+	"dmar",
+	dmar_methods,
+	sizeof(struct dmar_unit),
+};
+
+DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 0, 0);
+MODULE_DEPEND(dmar, acpi, 1, 1, 1);
+
+static void
+dmar_print_path(device_t dev, const char *banner, int busno, int depth,
+    const ACPI_DMAR_PCI_PATH *path)
+{
+	int i;
+
+	device_printf(dev, "%s [%d, ", banner, busno);
+	for (i = 0; i < depth; i++) {
+		if (i != 0)
+			printf(", ");
+		printf("(%d, %d)", path[i].Device, path[i].Function);
+	}
+	printf("]\n");
+}
+
+static int
+dmar_dev_depth(device_t child)
+{
+	devclass_t pci_class;
+	device_t bus, pcib;
+	int depth;
+
+	pci_class = devclass_find("pci");
+	for (depth = 1; ; depth++) {
+		bus = device_get_parent(child);
+		pcib = device_get_parent(bus);
+		if (device_get_devclass(device_get_parent(pcib)) !=
+		    pci_class)
+			return (depth);
+		child = pcib;
+	}
+}
+
+static void
+dmar_dev_path(device_t child, int *busno, ACPI_DMAR_PCI_PATH *path, int depth)
+{
+	devclass_t pci_class;
+	device_t bus, pcib;
+
+	pci_class = devclass_find("pci");
+	for (depth--; depth != -1; depth--) {
+		path[depth].Device = pci_get_slot(child);
+		path[depth].Function = pci_get_function(child);
+		bus = device_get_parent(child);
+		pcib = device_get_parent(bus);
+		if (device_get_devclass(device_get_parent(pcib)) !=
+		    pci_class) {
+			/* reached a host bridge */
+			*busno = pcib_get_bus(bus);
+			return;
+		}
+		child = pcib;
+	}
+	panic("wrong depth");
+}
+
+static int
+dmar_match_pathes(int busno1, const ACPI_DMAR_PCI_PATH *path1, int depth1,
+    int busno2, const ACPI_DMAR_PCI_PATH *path2, int depth2,
+    enum AcpiDmarScopeType scope_type)
+{
+	int i, depth;
+
+	if (busno1 != busno2)
+		return (0);
+	if (scope_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && depth1 != depth2)
+		return (0);
+	depth = depth1;
+	if (depth2 < depth)
+		depth = depth2;
+	for (i = 0; i < depth; i++) {
+		if (path1[i].Device != path2[i].Device ||
+		    path1[i].Function != path2[i].Function)
+			return (0);
+	}
+	return (1);
+}
+
+static int
+dmar_match_devscope(ACPI_DMAR_DEVICE_SCOPE *devscope, device_t dev,
+    int dev_busno, const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len)
+{
+	ACPI_DMAR_PCI_PATH *path;
+	int path_len;
+
+	if (devscope->Length < sizeof(*devscope)) {
+		printf("dmar_find: corrupted DMAR table, dl %d\n",
+		    devscope->Length);
+		return (-1);
+	}
+	if (devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_ENDPOINT &&
+	    devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_BRIDGE)
+		return (0);
+	path_len = devscope->Length - sizeof(*devscope);
+	if (path_len % 2 != 0) {
+		printf("dmar_find_bsf: corrupted DMAR table, dl %d\n",
+		    devscope->Length);
+		return (-1);
+	}
+	path_len /= 2;
+	path = (ACPI_DMAR_PCI_PATH *)(devscope + 1);
+	if (path_len == 0) {
+		printf("dmar_find: corrupted DMAR table, dl %d\n",
+		    devscope->Length);
+		return (-1);
+	}
+	if (dmar_match_verbose)
+		dmar_print_path(dev, "DMAR", devscope->Bus, path_len, path);
+
+	return (dmar_match_pathes(devscope->Bus, path, path_len, dev_busno,
+	    dev_path, dev_path_len, devscope->EntryType));
+}
+
+struct dmar_unit *
+dmar_find(device_t dev)
+{
+	device_t dmar_dev;
+	ACPI_DMAR_HARDWARE_UNIT *dmarh;
+	ACPI_DMAR_DEVICE_SCOPE *devscope;
+	char *ptr, *ptrend;
+	int i, match, dev_domain, dev_busno, dev_path_len;
+
+	dmar_dev = NULL;
+	dev_domain = pci_get_domain(dev);
+	dev_path_len = dmar_dev_depth(dev);
+	ACPI_DMAR_PCI_PATH dev_path[dev_path_len];
+	dmar_dev_path(dev, &dev_busno, dev_path, dev_path_len);
+	if (dmar_match_verbose)
+		dmar_print_path(dev, "PCI", dev_busno, dev_path_len, dev_path);
+
+	for (i = 0; i < dmar_devcnt; i++) {
+		if (dmar_devs[i] == NULL)
+			continue;
+		dmarh = dmar_find_by_index(i);
+		if (dmarh == NULL)
+			continue;
+		if (dmarh->Segment != dev_domain)
+			continue;
+		if ((dmarh->Flags & ACPI_DMAR_INCLUDE_ALL) != 0) {
+			dmar_dev = dmar_devs[i];
+			if (dmar_match_verbose) {
+				device_printf(dev,
+				    "pci%d:%d:%d:%d matched dmar%d INCLUDE_ALL\n",
+				    dev_domain, pci_get_bus(dev),
+				    pci_get_slot(dev),
+				    pci_get_function(dev),
+				    ((struct dmar_unit *)device_get_softc(
+				    dmar_dev))->unit);
+			}
+			goto found;
+		}
+		ptr = (char *)dmarh + sizeof(*dmarh);
+		ptrend = (char *)dmarh + dmarh->Header.Length;
+		for (;;) {
+			if (ptr >= ptrend)
+				break;
+			devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
+			ptr += devscope->Length;
+			if (dmar_match_verbose) {
+				device_printf(dev,
+				    "pci%d:%d:%d:%d matching dmar%d\n",
+				    dev_domain, pci_get_bus(dev),
+				    pci_get_slot(dev),
+				    pci_get_function(dev),
+				    ((struct dmar_unit *)device_get_softc(
+				    dmar_devs[i]))->unit);
+			}
+			match = dmar_match_devscope(devscope, dev, dev_busno,
+			    dev_path, dev_path_len);
+			if (dmar_match_verbose) {
+				if (match == -1)
+					printf("table error\n");
+				else if (match == 0)
+					printf("not matched\n");
+				else
+					printf("matched\n");
+			}
+			if (match == -1)
+				return (NULL);
+			else if (match == 1) {
+				dmar_dev = dmar_devs[i];
+				goto found;
+			}
+		}
+	}
+	return (NULL);
+found:
+	return (device_get_softc(dmar_dev));
+}
+
+struct rmrr_iter_args {
+	struct dmar_ctx *ctx;
+	device_t dev;
+	int dev_domain;
+	int dev_busno;
+	ACPI_DMAR_PCI_PATH *dev_path;
+	int dev_path_len;
+	struct dmar_map_entries_tailq *rmrr_entries;
+};
+
+static int
+dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
+{
+	struct rmrr_iter_args *ria;
+	ACPI_DMAR_RESERVED_MEMORY *resmem;
+	ACPI_DMAR_DEVICE_SCOPE *devscope;
+	struct dmar_map_entry *entry;
+	char *ptr, *ptrend;
+	int match;
+
+	if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY)
+		return (1);
+
+	ria = arg;
+	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
+	if (dmar_match_verbose) {
+		printf("RMRR [%jx,%jx] segment %d\n",
+		    (uintmax_t)resmem->BaseAddress,
+		    (uintmax_t)resmem->EndAddress,
+		    resmem->Segment);
+	}
+	if (resmem->Segment != ria->dev_domain)
+		return (1);
+
+	ptr = (char *)resmem + sizeof(*resmem);
+	ptrend = (char *)resmem + resmem->Header.Length;
+	for (;;) {
+		if (ptr >= ptrend)
+			break;
+		devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
+		ptr += devscope->Length;
+		match = dmar_match_devscope(devscope, ria->dev, ria->dev_busno,
+		    ria->dev_path, ria->dev_path_len);
+		if (match == 1) {
+			if (dmar_match_verbose)
+				printf("matched\n");
+			entry = dmar_gas_alloc_entry(ria->ctx, DMAR_PGF_WAITOK);
+			entry->start = resmem->BaseAddress;
+			/* The RMRR entry end address is inclusive. */
+			entry->end = resmem->EndAddress;
+			TAILQ_INSERT_TAIL(ria->rmrr_entries, entry,
+			    unroll_link);
+		} else if (dmar_match_verbose) {
+			printf("not matched, err %d\n", match);
+		}
+	}
+
+	return (1);
+}
+
+void
+dmar_ctx_parse_rmrr(struct dmar_ctx *ctx, device_t dev,
+    struct dmar_map_entries_tailq *rmrr_entries)
+{
+	struct rmrr_iter_args ria;
+
+	ria.dev_domain = pci_get_domain(dev);
+	ria.dev_path_len = dmar_dev_depth(dev);
+	ACPI_DMAR_PCI_PATH dev_path[ria.dev_path_len];
+	dmar_dev_path(dev, &ria.dev_busno, dev_path, ria.dev_path_len);
+
+	if (dmar_match_verbose) {
+		device_printf(dev, "parsing RMRR entries for ");
+		dmar_print_path(dev, "PCI", ria.dev_busno, ria.dev_path_len,
+		    dev_path);
+	}
+
+	ria.ctx = ctx;
+	ria.dev = dev;
+	ria.dev_path = dev_path;
+	ria.rmrr_entries = rmrr_entries;
+	dmar_iterate_tbl(dmar_rmrr_iter, &ria);
+}
+
+struct inst_rmrr_iter_args {
+	struct dmar_unit *dmar;
+};
+
+static device_t
+dmar_path_dev(int segment, int path_len, int busno,
+    const ACPI_DMAR_PCI_PATH *path)
+{
+	devclass_t pci_class;
+	device_t bus, pcib, dev;
+	int i;
+
+	pci_class = devclass_find("pci");
+	dev = NULL;
+	for (i = 0; i < path_len; i++, path++) {
+		dev = pci_find_dbsf(segment, busno, path->Device,
+		    path->Function);
+		if (dev == NULL)
+			break;
+		if (i != path_len - 1) {
+			bus = device_get_parent(dev);
+			pcib = device_get_parent(bus);
+			if (device_get_devclass(device_get_parent(pcib)) !=
+			    pci_class)
+				return (NULL);
+		}
+		busno = pcib_get_bus(dev);
+	}
+	return (dev);
+}
+
+static int
+dmar_inst_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
+{
+	const ACPI_DMAR_RESERVED_MEMORY *resmem;
+	const ACPI_DMAR_DEVICE_SCOPE *devscope;
+	struct inst_rmrr_iter_args *iria;
+	const char *ptr, *ptrend;
+	struct dmar_unit *dev_dmar;
+	device_t dev;
+
+	if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY)
+		return (1);
+
+	iria = arg;
+	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
+	if (resmem->Segment != iria->dmar->segment)
+		return (1);
+	if (dmar_match_verbose) {
+		printf("dmar%d: RMRR [%jx,%jx]\n", iria->dmar->unit,
+		    (uintmax_t)resmem->BaseAddress,
+		    (uintmax_t)resmem->EndAddress);
+	}
+
+	ptr = (const char *)resmem + sizeof(*resmem);
+	ptrend = (const char *)resmem + resmem->Header.Length;
+	for (;;) {
+		if (ptr >= ptrend)
+			break;
+		devscope = (const ACPI_DMAR_DEVICE_SCOPE *)ptr;
+		ptr += devscope->Length;
+		/* XXXKIB bridge */
+		if (devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_ENDPOINT)
+			continue;
+		if (dmar_match_verbose) {
+			dmar_print_path(iria->dmar->dev, "RMRR scope",
+			    devscope->Bus, (devscope->Length -
+			    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2,
+			    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
+		}
+		dev = dmar_path_dev(resmem->Segment, (devscope->Length -
+		    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2, devscope->Bus,
+		    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
+		if (dev == NULL) {
+			if (dmar_match_verbose)
+				printf("null dev\n");
+			continue;
+		}
+		dev_dmar = dmar_find(dev);
+		if (dev_dmar != iria->dmar) {
+			if (dmar_match_verbose) {
+				printf("dmar%d matched, skipping\n",
+				    dev_dmar->unit);
+			}
+			continue;
+		}
+		if (dmar_match_verbose)
+			printf("matched, instantiating RMRR context\n");
+		dmar_instantiate_ctx(iria->dmar, dev, true);
+	}
+
+	return (1);
+
+}
+
+/*
+ * Pre-create all contexts for the DMAR which have RMRR entries.
+ */
+int
+dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar)
+{
+	struct inst_rmrr_iter_args iria;
+	int error;
+
+	if (!dmar_barrier_enter(dmar, DMAR_BARRIER_RMRR))
+		return (0);
+
+	error = 0;
+	iria.dmar = dmar;
+	if (dmar_match_verbose)
+		printf("dmar%d: instantiating RMRR contexts\n", dmar->unit);
+	dmar_iterate_tbl(dmar_inst_rmrr_iter, &iria);
+	DMAR_LOCK(dmar);
+	if (!LIST_EMPTY(&dmar->contexts)) {
+		KASSERT((dmar->hw_gcmd & DMAR_GCMD_TE) == 0,
+	    ("dmar%d: RMRR not handled but translation is already enabled",
+		    dmar->unit));
+		error = dmar_enable_translation(dmar);
+	}
+	dmar_barrier_exit(dmar, DMAR_BARRIER_RMRR);
+	return (error);
+}
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_lex.h>
+
+static void
+dmar_print_ctx_entry(const struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *l, *r;
+
+	db_printf(
+	    "    start %jx end %jx free_after %jx free_down %jx flags %x ",
+	    entry->start, entry->end, entry->free_after, entry->free_down,
+	    entry->flags);
+	db_printf("left ");
+	l = RB_LEFT(entry, rb_entry);
+	if (l == NULL)
+		db_printf("NULL ");
+	else
+		db_printf("%jx ", l->start);
+	db_printf("right ");
+	r = RB_RIGHT(entry, rb_entry);
+	if (r == NULL)
+		db_printf("NULL");
+	else
+		db_printf("%jx", r->start);
+	db_printf("\n");
+}
+
+static void
+dmar_print_ctx(struct dmar_ctx *ctx, bool show_mappings)
+{
+	struct dmar_map_entry *entry;
+
+	db_printf(
+	    "  @%p pci%d:%d:%d dom %d mgaw %d agaw %d pglvl %d end %jx\n"
+	    "    refs %d flags %x pgobj %p map_ents %u loads %lu unloads %lu\n",
+	    ctx, pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner), ctx->domain, ctx->mgaw,
+	    ctx->agaw, ctx->pglvl, (uintmax_t)ctx->end, ctx->refs,
+	    ctx->flags, ctx->pgtbl_obj, ctx->entries_cnt, ctx->loads,
+	    ctx->unloads);
+	if (!show_mappings)
+		return;
+	db_printf("    mapped:\n");
+	RB_FOREACH(entry, dmar_gas_entries_tree, &ctx->rb_root) {
+		dmar_print_ctx_entry(entry);
+		if (db_pager_quit)
+			break;
+	}
+	if (db_pager_quit)
+		return;
+	db_printf("    unloading:\n");
+	TAILQ_FOREACH(entry, &ctx->unload_entries, dmamap_link) {
+		dmar_print_ctx_entry(entry);
+		if (db_pager_quit)
+			break;
+	}
+}
+
+DB_FUNC(dmar_ctx, db_dmar_print_ctx, db_show_table, CS_OWN, NULL)
+{
+	struct dmar_unit *unit;
+	struct dmar_ctx *ctx;
+	bool show_mappings, valid;
+	int domain, bus, device, function, i, t;
+	db_expr_t radix;
+
+	valid = false;
+	radix = db_radix;
+	db_radix = 10;
+	t = db_read_token();
+	if (t == tSLASH) {
+		t = db_read_token();
+		if (t != tIDENT) {
+			db_printf("Bad modifier\n");
+			db_radix = radix;
+			db_skip_to_eol();
+			return;
+		}
+		show_mappings = strchr(db_tok_string, 'm') != NULL;
+		t = db_read_token();
+	} else {
+		show_mappings = false;
+	}
+	if (t == tNUMBER) {
+		domain = db_tok_number;
+		t = db_read_token();
+		if (t == tNUMBER) {
+			bus = db_tok_number;
+			t = db_read_token();
+			if (t == tNUMBER) {
+				device = db_tok_number;
+				t = db_read_token();
+				if (t == tNUMBER) {
+					function = db_tok_number;
+					valid = true;
+				}
+			}
+		}
+	}
+			db_radix = radix;
+	db_skip_to_eol();
+	if (!valid) {
+		db_printf("usage: show dmar_ctx [/m] "
+		    "<domain> <bus> <device> <func>\n");
+		return;
+	}
+	for (i = 0; i < dmar_devcnt; i++) {
+		unit = device_get_softc(dmar_devs[i]);
+		LIST_FOREACH(ctx, &unit->contexts, link) {
+			if (domain == unit->segment && 
+			    bus == pci_get_bus(ctx->ctx_tag.owner) &&
+			    device == pci_get_slot(ctx->ctx_tag.owner) && 
+			    function == pci_get_function(ctx->ctx_tag.owner)) {
+				dmar_print_ctx(ctx, show_mappings);
+				goto out;
+			}
+		}
+	}
+out:;
+}
+
+static void
+dmar_print_one(int idx, bool show_ctxs, bool show_mappings)
+{
+	struct dmar_unit *unit;
+	struct dmar_ctx *ctx;
+	int i, frir;
+
+	unit = device_get_softc(dmar_devs[idx]);
+	db_printf("dmar%d at %p, root at 0x%jx, ver 0x%x\n", unit->unit, unit,
+	    dmar_read8(unit, DMAR_RTADDR_REG), dmar_read4(unit, DMAR_VER_REG));
+	db_printf("cap 0x%jx ecap 0x%jx gsts 0x%x fsts 0x%x fectl 0x%x\n",
+	    (uintmax_t)dmar_read8(unit, DMAR_CAP_REG),
+	    (uintmax_t)dmar_read8(unit, DMAR_ECAP_REG),
+	    dmar_read4(unit, DMAR_GSTS_REG),
+	    dmar_read4(unit, DMAR_FSTS_REG),
+	    dmar_read4(unit, DMAR_FECTL_REG));
+	db_printf("fed 0x%x fea 0x%x feua 0x%x\n",
+	    dmar_read4(unit, DMAR_FEDATA_REG),
+	    dmar_read4(unit, DMAR_FEADDR_REG),
+	    dmar_read4(unit, DMAR_FEUADDR_REG));
+	db_printf("primary fault log:\n");
+	for (i = 0; i < DMAR_CAP_NFR(unit->hw_cap); i++) {
+		frir = (DMAR_CAP_FRO(unit->hw_cap) + i) * 16;
+		db_printf("  %d at 0x%x: %jx %jx\n", i, frir,
+		    (uintmax_t)dmar_read8(unit, frir),
+		    (uintmax_t)dmar_read8(unit, frir + 8));
+	}
+	if (DMAR_HAS_QI(unit)) {
+		db_printf("ied 0x%x iea 0x%x ieua 0x%x\n",
+		    dmar_read4(unit, DMAR_IEDATA_REG),
+		    dmar_read4(unit, DMAR_IEADDR_REG),
+		    dmar_read4(unit, DMAR_IEUADDR_REG));
+		if (unit->qi_enabled) {
+			db_printf("qi is enabled: queue @0x%jx (IQA 0x%jx) "
+			    "size 0x%jx\n"
+		    "  head 0x%x tail 0x%x avail 0x%x status 0x%x ctrl 0x%x\n"
+		    "  hw compl 0x%x@%p/phys@%jx next seq 0x%x gen 0x%x\n",
+			    (uintmax_t)unit->inv_queue,
+			    (uintmax_t)dmar_read8(unit, DMAR_IQA_REG),
+			    (uintmax_t)unit->inv_queue_size,
+			    dmar_read4(unit, DMAR_IQH_REG),
+			    dmar_read4(unit, DMAR_IQT_REG),
+			    unit->inv_queue_avail,
+			    dmar_read4(unit, DMAR_ICS_REG),
+			    dmar_read4(unit, DMAR_IECTL_REG),
+			    unit->inv_waitd_seq_hw,
+			    &unit->inv_waitd_seq_hw,
+			    (uintmax_t)unit->inv_waitd_seq_hw_phys,
+			    unit->inv_waitd_seq,
+			    unit->inv_waitd_gen);
+		} else {
+			db_printf("qi is disabled\n");
+		}
+	}
+	if (show_ctxs) {
+		db_printf("contexts:\n");
+		LIST_FOREACH(ctx, &unit->contexts, link) {
+			dmar_print_ctx(ctx, show_mappings);
+			if (db_pager_quit)
+				break;
+		}
+	}
+}
+
+DB_SHOW_COMMAND(dmar, db_dmar_print)
+{
+	bool show_ctxs, show_mappings;
+
+	show_ctxs = strchr(modif, 'c') != NULL;
+	show_mappings = strchr(modif, 'm') != NULL;
+	if (!have_addr) {
+		db_printf("usage: show dmar [/c] [/m] index\n");
+		return;
+	}
+	dmar_print_one((int)addr, show_ctxs, show_mappings);
+}
+
+DB_SHOW_ALL_COMMAND(dmars, db_show_all_dmars)
+{
+	int i;
+	bool show_ctxs, show_mappings;
+
+	show_ctxs = strchr(modif, 'c') != NULL;
+	show_mappings = strchr(modif, 'm') != NULL;
+
+	for (i = 0; i < dmar_devcnt; i++) {
+		dmar_print_one(i, show_ctxs, show_mappings);
+		if (db_pager_quit)
+			break;
+	}
+}
+#endif


Property changes on: trunk/sys/x86/iommu/intel_drv.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_fault.c
===================================================================
--- trunk/sys/x86/iommu/intel_fault.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_fault.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,328 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_fault.c 279485 2015-03-01 10:35:54Z kib $");
+
+#include "opt_acpi.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/memdesc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <machine/bus.h>
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+/*
+ * Fault interrupt handling for DMARs.  If advanced fault logging is
+ * not implemented by hardware, the code emulates it.  Fast interrupt
+ * handler flushes the fault registers into circular buffer at
+ * unit->fault_log, and schedules a task.
+ *
+ * The fast handler is used since faults usually come in bursts, and
+ * number of fault log registers is limited, e.g. down to one for 5400
+ * MCH.  We are trying to reduce the latency for clearing the fault
+ * register file.  The task is usually long-running, since printf() is
+ * slow, but this is not problematic because bursts are rare.
+ *
+ * For the same reason, each translation unit task is executed in its
+ * own thread.
+ *
+ * XXXKIB It seems there is no hardware available which implements
+ * advanced fault logging, so the code to handle AFL is not written.
+ */
+
+static int
+dmar_fault_next(struct dmar_unit *unit, int faultp)
+{
+
+	faultp += 2;
+	if (faultp == unit->fault_log_size)
+		faultp = 0;
+	return (faultp);
+}
+
+static void
+dmar_fault_intr_clear(struct dmar_unit *unit, uint32_t fsts)
+{
+	uint32_t clear;
+
+	clear = 0;
+	if ((fsts & DMAR_FSTS_ITE) != 0) {
+		printf("DMAR%d: Invalidation timed out\n", unit->unit);
+		clear |= DMAR_FSTS_ITE;
+	}
+	if ((fsts & DMAR_FSTS_ICE) != 0) {
+		printf("DMAR%d: Invalidation completion error\n",
+		    unit->unit);
+		clear |= DMAR_FSTS_ICE;
+	}
+	if ((fsts & DMAR_FSTS_IQE) != 0) {
+		printf("DMAR%d: Invalidation queue error\n",
+		    unit->unit);
+		clear |= DMAR_FSTS_IQE;
+	}
+	if ((fsts & DMAR_FSTS_APF) != 0) {
+		printf("DMAR%d: Advanced pending fault\n", unit->unit);
+		clear |= DMAR_FSTS_APF;
+	}
+	if ((fsts & DMAR_FSTS_AFO) != 0) {
+		printf("DMAR%d: Advanced fault overflow\n", unit->unit);
+		clear |= DMAR_FSTS_AFO;
+	}
+	if (clear != 0)
+		dmar_write4(unit, DMAR_FSTS_REG, clear);
+}
+
+int
+dmar_fault_intr(void *arg)
+{
+	struct dmar_unit *unit;
+	uint64_t fault_rec[2];
+	uint32_t fsts;
+	int fri, frir, faultp;
+	bool enqueue;
+
+	unit = arg;
+	enqueue = false;
+	fsts = dmar_read4(unit, DMAR_FSTS_REG);
+	dmar_fault_intr_clear(unit, fsts);
+
+	if ((fsts & DMAR_FSTS_PPF) == 0)
+		goto done;
+
+	fri = DMAR_FSTS_FRI(fsts);
+	for (;;) {
+		frir = (DMAR_CAP_FRO(unit->hw_cap) + fri) * 16;
+		fault_rec[1] = dmar_read8(unit, frir + 8);
+		if ((fault_rec[1] & DMAR_FRCD2_F) == 0)
+			break;
+		fault_rec[0] = dmar_read8(unit, frir);
+		dmar_write4(unit, frir + 12, DMAR_FRCD2_F32);
+		DMAR_FAULT_LOCK(unit);
+		faultp = unit->fault_log_head;
+		if (dmar_fault_next(unit, faultp) == unit->fault_log_tail) {
+			/* XXXKIB log overflow */
+		} else {
+			unit->fault_log[faultp] = fault_rec[0];
+			unit->fault_log[faultp + 1] = fault_rec[1];
+			unit->fault_log_head = dmar_fault_next(unit, faultp);
+			enqueue = true;
+		}
+		DMAR_FAULT_UNLOCK(unit);
+		fri += 1;
+		if (fri >= DMAR_CAP_NFR(unit->hw_cap))
+			fri = 0;
+	}
+
+done:
+	/*
+	 * On SandyBridge, due to errata BJ124, IvyBridge errata
+	 * BV100, and Haswell errata HSD40, "Spurious Intel VT-d
+	 * Interrupts May Occur When the PFO Bit is Set".  Handle the
+	 * cases by clearing overflow bit even if no fault is
+	 * reported.
+	 *
+	 * On IvyBridge, errata BV30 states that clearing clear
+	 * DMAR_FRCD2_F bit in the fault register causes spurious
+	 * interrupt.  Do nothing.
+	 *
+	 */
+	if ((fsts & DMAR_FSTS_PFO) != 0) {
+		printf("DMAR%d: Fault Overflow\n", unit->unit);
+		dmar_write4(unit, DMAR_FSTS_REG, DMAR_FSTS_PFO);
+	}
+
+	if (enqueue) {
+		taskqueue_enqueue_fast(unit->fault_taskqueue,
+		    &unit->fault_task);
+	}
+	return (FILTER_HANDLED);
+}
+
+static void
+dmar_fault_task(void *arg, int pending __unused)
+{
+	struct dmar_unit *unit;
+	struct dmar_ctx *ctx;
+	uint64_t fault_rec[2];
+	int sid, bus, slot, func, faultp;
+
+	unit = arg;
+	DMAR_FAULT_LOCK(unit);
+	for (;;) {
+		faultp = unit->fault_log_tail;
+		if (faultp == unit->fault_log_head)
+			break;
+
+		fault_rec[0] = unit->fault_log[faultp];
+		fault_rec[1] = unit->fault_log[faultp + 1];
+		unit->fault_log_tail = dmar_fault_next(unit, faultp);
+		DMAR_FAULT_UNLOCK(unit);
+
+		sid = DMAR_FRCD2_SID(fault_rec[1]);
+		printf("DMAR%d: ", unit->unit);
+		DMAR_LOCK(unit);
+		ctx = dmar_find_ctx_locked(unit, sid);
+		if (ctx == NULL) {
+			printf("<unknown dev>:");
+
+			/*
+			 * Note that the slot and function will not be correct
+			 * if ARI is in use, but without a ctx entry we have
+			 * no way of knowing whether ARI is in use or not.
+			 */
+			bus = PCI_RID2BUS(sid);
+			slot = PCI_RID2SLOT(sid);
+			func = PCI_RID2FUNC(sid);
+		} else {
+			ctx->flags |= DMAR_CTX_FAULTED;
+			ctx->last_fault_rec[0] = fault_rec[0];
+			ctx->last_fault_rec[1] = fault_rec[1];
+			device_print_prettyname(ctx->ctx_tag.owner);
+			bus = pci_get_bus(ctx->ctx_tag.owner);
+			slot = pci_get_slot(ctx->ctx_tag.owner);
+			func = pci_get_function(ctx->ctx_tag.owner);
+		}
+		DMAR_UNLOCK(unit);
+		printf(
+		    "pci%d:%d:%d sid %x fault acc %x adt 0x%x reason 0x%x "
+		    "addr %jx\n",
+		    bus, slot, func, sid, DMAR_FRCD2_T(fault_rec[1]),
+		    DMAR_FRCD2_AT(fault_rec[1]), DMAR_FRCD2_FR(fault_rec[1]),
+		    (uintmax_t)fault_rec[0]);
+		DMAR_FAULT_LOCK(unit);
+	}
+	DMAR_FAULT_UNLOCK(unit);
+}
+
+static void
+dmar_clear_faults(struct dmar_unit *unit)
+{
+	uint32_t frec, frir, fsts;
+	int i;
+
+	for (i = 0; i < DMAR_CAP_NFR(unit->hw_cap); i++) {
+		frir = (DMAR_CAP_FRO(unit->hw_cap) + i) * 16;
+		frec = dmar_read4(unit, frir + 12);
+		if ((frec & DMAR_FRCD2_F32) == 0)
+			continue;
+		dmar_write4(unit, frir + 12, DMAR_FRCD2_F32);
+	}
+	fsts = dmar_read4(unit, DMAR_FSTS_REG);
+	dmar_write4(unit, DMAR_FSTS_REG, fsts);
+}
+
+int
+dmar_init_fault_log(struct dmar_unit *unit)
+{
+
+	mtx_init(&unit->fault_lock, "dmarflt", NULL, MTX_SPIN);
+	unit->fault_log_size = 256; /* 128 fault log entries */
+	TUNABLE_INT_FETCH("hw.dmar.fault_log_size", &unit->fault_log_size);
+	if (unit->fault_log_size % 2 != 0)
+		panic("hw.dmar_fault_log_size must be even");
+	unit->fault_log = malloc(sizeof(uint64_t) * unit->fault_log_size,
+	    M_DEVBUF, M_WAITOK | M_ZERO);
+
+	TASK_INIT(&unit->fault_task, 0, dmar_fault_task, unit);
+	unit->fault_taskqueue = taskqueue_create_fast("dmar", M_WAITOK,
+	    taskqueue_thread_enqueue, &unit->fault_taskqueue);
+	taskqueue_start_threads(&unit->fault_taskqueue, 1, PI_AV,
+	    "dmar%d fault taskq", unit->unit);
+
+	DMAR_LOCK(unit);
+	dmar_disable_fault_intr(unit);
+	dmar_clear_faults(unit);
+	dmar_enable_fault_intr(unit);
+	DMAR_UNLOCK(unit);
+
+	return (0);
+}
+
+void
+dmar_fini_fault_log(struct dmar_unit *unit)
+{
+
+	DMAR_LOCK(unit);
+	dmar_disable_fault_intr(unit);
+	DMAR_UNLOCK(unit);
+
+	if (unit->fault_taskqueue == NULL)
+		return;
+
+	taskqueue_drain(unit->fault_taskqueue, &unit->fault_task);
+	taskqueue_free(unit->fault_taskqueue);
+	unit->fault_taskqueue = NULL;
+	mtx_destroy(&unit->fault_lock);
+
+	free(unit->fault_log, M_DEVBUF);
+	unit->fault_log = NULL;
+	unit->fault_log_head = unit->fault_log_tail = 0;
+}
+
+void
+dmar_enable_fault_intr(struct dmar_unit *unit)
+{
+	uint32_t fectl;
+
+	DMAR_ASSERT_LOCKED(unit);
+	fectl = dmar_read4(unit, DMAR_FECTL_REG);
+	fectl &= ~DMAR_FECTL_IM;
+	dmar_write4(unit, DMAR_FECTL_REG, fectl);
+}
+
+void
+dmar_disable_fault_intr(struct dmar_unit *unit)
+{
+	uint32_t fectl;
+
+	DMAR_ASSERT_LOCKED(unit);
+	fectl = dmar_read4(unit, DMAR_FECTL_REG);
+	dmar_write4(unit, DMAR_FECTL_REG, fectl | DMAR_FECTL_IM);
+}


Property changes on: trunk/sys/x86/iommu/intel_fault.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_gas.c
===================================================================
--- trunk/sys/x86/iommu/intel_gas.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_gas.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,733 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_gas.c 281545 2015-04-15 06:56:51Z kib $");
+
+#define	RB_AUGMENT(entry) dmar_gas_augment_entry(entry)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/rman.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <dev/pci/pcivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/uma.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+/*
+ * Guest Address Space management.
+ */
+
+static uma_zone_t dmar_map_entry_zone;
+
+static void
+intel_gas_init(void)
+{
+
+	dmar_map_entry_zone = uma_zcreate("DMAR_MAP_ENTRY",
+	    sizeof(struct dmar_map_entry), NULL, NULL,
+	    NULL, NULL, UMA_ALIGN_PTR, 0);
+}
+SYSINIT(intel_gas, SI_SUB_DRIVERS, SI_ORDER_FIRST, intel_gas_init, NULL);
+
+struct dmar_map_entry *
+dmar_gas_alloc_entry(struct dmar_ctx *ctx, u_int flags)
+{
+	struct dmar_map_entry *res;
+
+	KASSERT((flags & ~(DMAR_PGF_WAITOK)) == 0,
+	    ("unsupported flags %x", flags));
+
+	res = uma_zalloc(dmar_map_entry_zone, ((flags & DMAR_PGF_WAITOK) !=
+	    0 ? M_WAITOK : M_NOWAIT) | M_ZERO);
+	if (res != NULL) {
+		res->ctx = ctx;
+		atomic_add_int(&ctx->entries_cnt, 1);
+	}
+	return (res);
+}
+
+void
+dmar_gas_free_entry(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+
+	KASSERT(ctx == entry->ctx,
+	    ("mismatched free ctx %p entry %p entry->ctx %p", ctx,
+	    entry, entry->ctx));
+	atomic_subtract_int(&ctx->entries_cnt, 1);
+	uma_zfree(dmar_map_entry_zone, entry);
+}
+
+static int
+dmar_gas_cmp_entries(struct dmar_map_entry *a, struct dmar_map_entry *b)
+{
+
+	/* Last entry have zero size, so <= */
+	KASSERT(a->start <= a->end, ("inverted entry %p (%jx, %jx)",
+	    a, (uintmax_t)a->start, (uintmax_t)a->end));
+	KASSERT(b->start <= b->end, ("inverted entry %p (%jx, %jx)",
+	    b, (uintmax_t)b->start, (uintmax_t)b->end));
+	KASSERT(a->end <= b->start || b->end <= a->start ||
+	    a->end == a->start || b->end == b->start,
+	    ("overlapping entries %p (%jx, %jx) %p (%jx, %jx)",
+	    a, (uintmax_t)a->start, (uintmax_t)a->end,
+	    b, (uintmax_t)b->start, (uintmax_t)b->end));
+
+	if (a->end < b->end)
+		return (-1);
+	else if (b->end < a->end)
+		return (1);
+	return (0);
+}
+
+static void
+dmar_gas_augment_entry(struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *l, *r;
+
+	for (; entry != NULL; entry = RB_PARENT(entry, rb_entry)) {
+		l = RB_LEFT(entry, rb_entry);
+		r = RB_RIGHT(entry, rb_entry);
+		if (l == NULL && r == NULL) {
+			entry->free_down = entry->free_after;
+		} else if (l == NULL && r != NULL) {
+			entry->free_down = MAX(entry->free_after, r->free_down);
+		} else if (/*l != NULL && */ r == NULL) {
+			entry->free_down = MAX(entry->free_after, l->free_down);
+		} else /* if (l != NULL && r != NULL) */ {
+			entry->free_down = MAX(entry->free_after, l->free_down);
+			entry->free_down = MAX(entry->free_down, r->free_down);
+		}
+	}
+}
+
+RB_GENERATE(dmar_gas_entries_tree, dmar_map_entry, rb_entry,
+    dmar_gas_cmp_entries);
+
+static void
+dmar_gas_fix_free(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *next;
+
+	next = RB_NEXT(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	entry->free_after = (next != NULL ? next->start : ctx->end) -
+	    entry->end;
+	dmar_gas_augment_entry(entry);
+}
+
+#ifdef INVARIANTS
+static void
+dmar_gas_check_free(struct dmar_ctx *ctx)
+{
+	struct dmar_map_entry *entry, *next, *l, *r;
+	dmar_gaddr_t v;
+
+	RB_FOREACH(entry, dmar_gas_entries_tree, &ctx->rb_root) {
+		KASSERT(ctx == entry->ctx,
+		    ("mismatched free ctx %p entry %p entry->ctx %p", ctx,
+		    entry, entry->ctx));
+		next = RB_NEXT(dmar_gas_entries_tree, &ctx->rb_root, entry);
+		if (next == NULL) {
+			MPASS(entry->free_after == ctx->end - entry->end);
+		} else {
+			MPASS(entry->free_after = next->start - entry->end);
+			MPASS(entry->end <= next->start);
+		}
+		l = RB_LEFT(entry, rb_entry);
+		r = RB_RIGHT(entry, rb_entry);
+		if (l == NULL && r == NULL) {
+			MPASS(entry->free_down == entry->free_after);
+		} else if (l == NULL && r != NULL) {
+			MPASS(entry->free_down = MAX(entry->free_after,
+			    r->free_down));
+		} else if (r == NULL) {
+			MPASS(entry->free_down = MAX(entry->free_after,
+			    l->free_down));
+		} else {
+			v = MAX(entry->free_after, l->free_down);
+			v = MAX(entry->free_down, r->free_down);
+			MPASS(entry->free_down == v);
+		}
+	}
+}
+#endif
+
+static bool
+dmar_gas_rb_insert(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *prev, *found;
+
+	found = RB_INSERT(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	dmar_gas_fix_free(ctx, entry);
+	prev = RB_PREV(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	if (prev != NULL)
+		dmar_gas_fix_free(ctx, prev);
+	return (found == NULL);
+}
+
+static void
+dmar_gas_rb_remove(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *prev;
+
+	prev = RB_PREV(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	RB_REMOVE(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	if (prev != NULL)
+		dmar_gas_fix_free(ctx, prev);
+}
+
+void
+dmar_gas_init_ctx(struct dmar_ctx *ctx)
+{
+	struct dmar_map_entry *begin, *end;
+
+	begin = dmar_gas_alloc_entry(ctx, DMAR_PGF_WAITOK);
+	end = dmar_gas_alloc_entry(ctx, DMAR_PGF_WAITOK);
+
+	DMAR_CTX_LOCK(ctx);
+	KASSERT(ctx->entries_cnt == 2, ("dirty ctx %p", ctx));
+	KASSERT(RB_EMPTY(&ctx->rb_root), ("non-empty entries %p", ctx));
+
+	begin->start = 0;
+	begin->end = DMAR_PAGE_SIZE;
+	begin->free_after = ctx->end - begin->end;
+	begin->flags = DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_UNMAPPED;
+	dmar_gas_rb_insert(ctx, begin);
+
+	end->start = ctx->end;
+	end->end = ctx->end;
+	end->free_after = 0;
+	end->flags = DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_UNMAPPED;
+	dmar_gas_rb_insert(ctx, end);
+
+	ctx->first_place = begin;
+	ctx->last_place = end;
+	DMAR_CTX_UNLOCK(ctx);
+}
+
+void
+dmar_gas_fini_ctx(struct dmar_ctx *ctx)
+{
+	struct dmar_map_entry *entry, *entry1;
+
+	DMAR_CTX_ASSERT_LOCKED(ctx);
+	KASSERT(ctx->entries_cnt == 2, ("ctx still in use %p", ctx));
+
+	entry = RB_MIN(dmar_gas_entries_tree, &ctx->rb_root);
+	KASSERT(entry->start == 0, ("start entry start %p", ctx));
+	KASSERT(entry->end == DMAR_PAGE_SIZE, ("start entry end %p", ctx));
+	KASSERT(entry->flags == DMAR_MAP_ENTRY_PLACE,
+	    ("start entry flags %p", ctx));
+	RB_REMOVE(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	dmar_gas_free_entry(ctx, entry);
+
+	entry = RB_MAX(dmar_gas_entries_tree, &ctx->rb_root);
+	KASSERT(entry->start == ctx->end, ("end entry start %p", ctx));
+	KASSERT(entry->end == ctx->end, ("end entry end %p", ctx));
+	KASSERT(entry->free_after == 0, ("end entry free_after%p", ctx));
+	KASSERT(entry->flags == DMAR_MAP_ENTRY_PLACE,
+	    ("end entry flags %p", ctx));
+	RB_REMOVE(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	dmar_gas_free_entry(ctx, entry);
+
+	RB_FOREACH_SAFE(entry, dmar_gas_entries_tree, &ctx->rb_root, entry1) {
+		KASSERT((entry->flags & DMAR_MAP_ENTRY_RMRR) != 0,
+		    ("non-RMRR entry left %p", ctx));
+		RB_REMOVE(dmar_gas_entries_tree, &ctx->rb_root, entry);
+		dmar_gas_free_entry(ctx, entry);
+	}
+}
+
+struct dmar_gas_match_args {
+	struct dmar_ctx *ctx;
+	dmar_gaddr_t size;
+	int offset;
+	const struct bus_dma_tag_common *common;
+	u_int gas_flags;
+	struct dmar_map_entry *entry;
+};
+
+static bool
+dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev,
+    dmar_gaddr_t end)
+{
+	dmar_gaddr_t bs, start;
+
+	if (a->entry->start + a->size > end)
+		return (false);
+
+	/* DMAR_PAGE_SIZE to create gap after new entry. */
+	if (a->entry->start < prev->end + DMAR_PAGE_SIZE ||
+	    a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE >
+	    prev->end + prev->free_after)
+		return (false);
+
+	/* No boundary crossing. */
+	if (dmar_test_boundary(a->entry->start + a->offset, a->size,
+	    a->common->boundary))
+		return (true);
+
+	/*
+	 * The start + offset to start + offset + size region crosses
+	 * the boundary.  Check if there is enough space after the
+	 * next boundary after the prev->end.
+	 */
+	bs = (a->entry->start + a->offset + a->common->boundary) &
+	    ~(a->common->boundary - 1);
+	start = roundup2(bs, a->common->alignment);
+	/* DMAR_PAGE_SIZE to create gap after new entry. */
+	if (start + a->offset + a->size + DMAR_PAGE_SIZE <=
+	    prev->end + prev->free_after &&
+	    start + a->offset + a->size <= end &&
+	    dmar_test_boundary(start + a->offset, a->size,
+	    a->common->boundary)) {
+		a->entry->start = start;
+		return (true);
+	}
+
+	/*
+	 * Not enough space to align at the requested boundary, or
+	 * boundary is smaller than the size, but allowed to split.
+	 * We already checked that start + size does not overlap end.
+	 *
+	 * XXXKIB. It is possible that bs is exactly at the start of
+	 * the next entry, then we do not have gap.  Ignore for now.
+	 */
+	if ((a->gas_flags & DMAR_GM_CANSPLIT) != 0) {
+		a->size = bs - a->entry->start;
+		return (true);
+	}
+
+	return (false);
+}
+
+static void
+dmar_gas_match_insert(struct dmar_gas_match_args *a,
+    struct dmar_map_entry *prev)
+{
+	struct dmar_map_entry *next;
+	bool found;
+
+	/*
+	 * The prev->end is always aligned on the page size, which
+	 * causes page alignment for the entry->start too.  The size
+	 * is checked to be multiple of the page size.
+	 *
+	 * The page sized gap is created between consequent
+	 * allocations to ensure that out-of-bounds accesses fault.
+	 */
+	a->entry->end = a->entry->start + a->size;
+
+	next = RB_NEXT(dmar_gas_entries_tree, &a->ctx->rb_root, prev);
+	KASSERT(next->start >= a->entry->end &&
+	    next->start - a->entry->start >= a->size &&
+	    prev->end <= a->entry->end,
+	    ("dmar_gas_match_insert hole failed %p prev (%jx, %jx) "
+	    "free_after %jx next (%jx, %jx) entry (%jx, %jx)", a->ctx,
+	    (uintmax_t)prev->start, (uintmax_t)prev->end,
+	    (uintmax_t)prev->free_after,
+	    (uintmax_t)next->start, (uintmax_t)next->end,
+	    (uintmax_t)a->entry->start, (uintmax_t)a->entry->end));
+
+	prev->free_after = a->entry->start - prev->end;
+	a->entry->free_after = next->start - a->entry->end;
+
+	found = dmar_gas_rb_insert(a->ctx, a->entry);
+	KASSERT(found, ("found dup %p start %jx size %jx",
+	    a->ctx, (uintmax_t)a->entry->start, (uintmax_t)a->size));
+	a->entry->flags = DMAR_MAP_ENTRY_MAP;
+
+	KASSERT(RB_PREV(dmar_gas_entries_tree, &a->ctx->rb_root,
+	    a->entry) == prev,
+	    ("entry %p prev %p inserted prev %p", a->entry, prev,
+	    RB_PREV(dmar_gas_entries_tree, &a->ctx->rb_root, a->entry)));
+	KASSERT(RB_NEXT(dmar_gas_entries_tree, &a->ctx->rb_root,
+	    a->entry) == next,
+	    ("entry %p next %p inserted next %p", a->entry, next,
+	    RB_NEXT(dmar_gas_entries_tree, &a->ctx->rb_root, a->entry)));
+}
+
+static int
+dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *prev)
+{
+	struct dmar_map_entry *l;
+	int ret;
+
+	if (prev->end < a->common->lowaddr) {
+		a->entry->start = roundup2(prev->end + DMAR_PAGE_SIZE,
+		    a->common->alignment);
+		if (dmar_gas_match_one(a, prev, a->common->lowaddr)) {
+			dmar_gas_match_insert(a, prev);
+			return (0);
+		}
+	}
+	if (prev->free_down < a->size + a->offset + DMAR_PAGE_SIZE)
+		return (ENOMEM);
+	l = RB_LEFT(prev, rb_entry);
+	if (l != NULL) {
+		ret = dmar_gas_lowermatch(a, l);
+		if (ret == 0)
+			return (0);
+	}
+	l = RB_RIGHT(prev, rb_entry);
+	if (l != NULL)
+		return (dmar_gas_lowermatch(a, l));
+	return (ENOMEM);
+}
+
+static int
+dmar_gas_uppermatch(struct dmar_gas_match_args *a)
+{
+	struct dmar_map_entry *next, *prev, find_entry;
+
+	find_entry.start = a->common->highaddr;
+	next = RB_NFIND(dmar_gas_entries_tree, &a->ctx->rb_root, &find_entry);
+	if (next == NULL)
+		return (ENOMEM);
+	prev = RB_PREV(dmar_gas_entries_tree, &a->ctx->rb_root, next);
+	KASSERT(prev != NULL, ("no prev %p %jx", a->ctx,
+	    (uintmax_t)find_entry.start));
+	for (;;) {
+		a->entry->start = prev->start + DMAR_PAGE_SIZE;
+		if (a->entry->start < a->common->highaddr)
+			a->entry->start = a->common->highaddr;
+		a->entry->start = roundup2(a->entry->start,
+		    a->common->alignment);
+		if (dmar_gas_match_one(a, prev, a->ctx->end)) {
+			dmar_gas_match_insert(a, prev);
+			return (0);
+		}
+
+		/*
+		 * XXXKIB.  This falls back to linear iteration over
+		 * the free space in the high region.  But high
+		 * regions are almost unused, the code should be
+		 * enough to cover the case, although in the
+		 * non-optimal way.
+		 */
+		prev = next;
+		next = RB_NEXT(dmar_gas_entries_tree, &a->ctx->rb_root, prev);
+		KASSERT(next != NULL, ("no next %p %jx", a->ctx,
+		    (uintmax_t)find_entry.start));
+		if (next->end >= a->ctx->end)
+			return (ENOMEM);
+	}
+}
+
+static int
+dmar_gas_find_space(struct dmar_ctx *ctx,
+    const struct bus_dma_tag_common *common, dmar_gaddr_t size,
+    int offset, u_int flags, struct dmar_map_entry *entry)
+{
+	struct dmar_gas_match_args a;
+	int error;
+
+	DMAR_CTX_ASSERT_LOCKED(ctx);
+	KASSERT(entry->flags == 0, ("dirty entry %p %p", ctx, entry));
+	KASSERT((size & DMAR_PAGE_MASK) == 0, ("size %jx", (uintmax_t)size));
+
+	a.ctx = ctx;
+	a.size = size;
+	a.offset = offset;
+	a.common = common;
+	a.gas_flags = flags;
+	a.entry = entry;
+
+	/* Handle lower region. */
+	if (common->lowaddr > 0) {
+		error = dmar_gas_lowermatch(&a, RB_ROOT(&ctx->rb_root));
+		if (error == 0)
+			return (0);
+		KASSERT(error == ENOMEM,
+		    ("error %d from dmar_gas_lowermatch", error));
+	}
+	/* Handle upper region. */
+	if (common->highaddr >= ctx->end)
+		return (ENOMEM);
+	error = dmar_gas_uppermatch(&a);
+	KASSERT(error == ENOMEM,
+	    ("error %d from dmar_gas_uppermatch", error));
+	return (error);
+}
+
+static int
+dmar_gas_alloc_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry,
+    u_int flags)
+{
+	struct dmar_map_entry *next, *prev;
+	bool found;
+
+	DMAR_CTX_ASSERT_LOCKED(ctx);
+
+	if ((entry->start & DMAR_PAGE_MASK) != 0 ||
+	    (entry->end & DMAR_PAGE_MASK) != 0)
+		return (EINVAL);
+	if (entry->start >= entry->end)
+		return (EINVAL);
+	if (entry->end >= ctx->end)
+		return (EINVAL);
+
+	next = RB_NFIND(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	KASSERT(next != NULL, ("next must be non-null %p %jx", ctx,
+	    (uintmax_t)entry->start));
+	prev = RB_PREV(dmar_gas_entries_tree, &ctx->rb_root, next);
+	/* prev could be NULL */
+
+	/*
+	 * Adapt to broken BIOSes which specify overlapping RMRR
+	 * entries.
+	 *
+	 * XXXKIB: this does not handle a case when prev or next
+	 * entries are completely covered by the current one, which
+	 * extends both ways.
+	 */
+	if (prev != NULL && prev->end > entry->start &&
+	    (prev->flags & DMAR_MAP_ENTRY_PLACE) == 0) {
+		if ((prev->flags & DMAR_MAP_ENTRY_RMRR) == 0)
+			return (EBUSY);
+		entry->start = prev->end;
+	}
+	if (next != NULL && next->start < entry->end &&
+	    (next->flags & DMAR_MAP_ENTRY_PLACE) == 0) {
+		if ((next->flags & DMAR_MAP_ENTRY_RMRR) == 0)
+			return (EBUSY);
+		entry->end = next->start;
+	}
+	if (entry->end == entry->start)
+		return (0);
+
+	if (prev != NULL && prev->end > entry->start) {
+		/* This assumes that prev is the placeholder entry. */
+		dmar_gas_rb_remove(ctx, prev);
+		prev = NULL;
+	}
+	if (next != NULL && next->start < entry->end) {
+		dmar_gas_rb_remove(ctx, next);
+		next = NULL;
+	}
+
+	found = dmar_gas_rb_insert(ctx, entry);
+	KASSERT(found, ("found RMRR dup %p start %jx end %jx",
+	    ctx, (uintmax_t)entry->start, (uintmax_t)entry->end));
+	entry->flags = DMAR_MAP_ENTRY_RMRR;
+
+#ifdef INVARIANTS
+	struct dmar_map_entry *ip, *in;
+	ip = RB_PREV(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	in = RB_NEXT(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	KASSERT(prev == NULL || ip == prev,
+	    ("RMRR %p (%jx %jx) prev %p (%jx %jx) ins prev %p (%jx %jx)",
+	    entry, entry->start, entry->end, prev,
+	    prev == NULL ? 0 : prev->start, prev == NULL ? 0 : prev->end,
+	    ip, ip == NULL ? 0 : ip->start, ip == NULL ? 0 : ip->end));
+	KASSERT(next == NULL || in == next,
+	    ("RMRR %p (%jx %jx) next %p (%jx %jx) ins next %p (%jx %jx)",
+	    entry, entry->start, entry->end, next,
+	    next == NULL ? 0 : next->start, next == NULL ? 0 : next->end,
+	    in, in == NULL ? 0 : in->start, in == NULL ? 0 : in->end));
+#endif
+
+	return (0);
+}
+
+void
+dmar_gas_free_space(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+
+	DMAR_CTX_ASSERT_LOCKED(ctx);
+	KASSERT((entry->flags & (DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_RMRR |
+	    DMAR_MAP_ENTRY_MAP)) == DMAR_MAP_ENTRY_MAP,
+	    ("permanent entry %p %p", ctx, entry));
+
+	dmar_gas_rb_remove(ctx, entry);
+	entry->flags &= ~DMAR_MAP_ENTRY_MAP;
+#ifdef INVARIANTS
+	if (dmar_check_free)
+		dmar_gas_check_free(ctx);
+#endif
+}
+
+void
+dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
+{
+	struct dmar_map_entry *next, *prev;
+
+	DMAR_CTX_ASSERT_LOCKED(ctx);
+	KASSERT((entry->flags & (DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_RMRR |
+	    DMAR_MAP_ENTRY_MAP)) == DMAR_MAP_ENTRY_RMRR,
+	    ("non-RMRR entry %p %p", ctx, entry));
+
+	prev = RB_PREV(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	next = RB_NEXT(dmar_gas_entries_tree, &ctx->rb_root, entry);
+	dmar_gas_rb_remove(ctx, entry);
+	entry->flags &= ~DMAR_MAP_ENTRY_RMRR;
+
+	if (prev == NULL)
+		dmar_gas_rb_insert(ctx, ctx->first_place);
+	if (next == NULL)
+		dmar_gas_rb_insert(ctx, ctx->last_place);
+}
+
+int
+dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
+    dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
+    struct dmar_map_entry **res)
+{
+	struct dmar_map_entry *entry;
+	int error;
+
+	KASSERT((flags & ~(DMAR_GM_CANWAIT | DMAR_GM_CANSPLIT)) == 0,
+	    ("invalid flags 0x%x", flags));
+
+	entry = dmar_gas_alloc_entry(ctx, (flags & DMAR_GM_CANWAIT) != 0 ?
+	    DMAR_PGF_WAITOK : 0);
+	if (entry == NULL)
+		return (ENOMEM);
+	DMAR_CTX_LOCK(ctx);
+	error = dmar_gas_find_space(ctx, common, size, offset, flags, entry);
+	if (error == ENOMEM) {
+		DMAR_CTX_UNLOCK(ctx);
+		dmar_gas_free_entry(ctx, entry);
+		return (error);
+	}
+#ifdef INVARIANTS
+	if (dmar_check_free)
+		dmar_gas_check_free(ctx);
+#endif
+	KASSERT(error == 0,
+	    ("unexpected error %d from dmar_gas_find_entry", error));
+	KASSERT(entry->end < ctx->end, ("allocated GPA %jx, max GPA %jx",
+	    (uintmax_t)entry->end, (uintmax_t)ctx->end));
+	entry->flags |= eflags;
+	DMAR_CTX_UNLOCK(ctx);
+
+	error = ctx_map_buf(ctx, entry->start, entry->end - entry->start, ma,
+	    ((eflags & DMAR_MAP_ENTRY_READ) != 0 ? DMAR_PTE_R : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_WRITE) != 0 ? DMAR_PTE_W : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_SNOOP) != 0 ? DMAR_PTE_SNP : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_TM) != 0 ? DMAR_PTE_TM : 0),
+	    (flags & DMAR_GM_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0);
+	if (error == ENOMEM) {
+		dmar_ctx_unload_entry(entry, true);
+		return (error);
+	}
+	KASSERT(error == 0,
+	    ("unexpected error %d from ctx_map_buf", error));
+
+	*res = entry;
+	return (0);
+}
+
+int
+dmar_gas_map_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry,
+    u_int eflags, u_int flags, vm_page_t *ma)
+{
+	dmar_gaddr_t start;
+	int error;
+
+	KASSERT(entry->flags == 0, ("used RMRR entry %p %p %x", ctx,
+	    entry, entry->flags));
+	KASSERT((flags & ~(DMAR_GM_CANWAIT)) == 0,
+	    ("invalid flags 0x%x", flags));
+
+	start = entry->start;
+	DMAR_CTX_LOCK(ctx);
+	error = dmar_gas_alloc_region(ctx, entry, flags);
+	if (error != 0) {
+		DMAR_CTX_UNLOCK(ctx);
+		return (error);
+	}
+	entry->flags |= eflags;
+	DMAR_CTX_UNLOCK(ctx);
+	if (entry->end == entry->start)
+		return (0);
+
+	error = ctx_map_buf(ctx, entry->start, entry->end - entry->start,
+	    ma + OFF_TO_IDX(start - entry->start),
+	    ((eflags & DMAR_MAP_ENTRY_READ) != 0 ? DMAR_PTE_R : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_WRITE) != 0 ? DMAR_PTE_W : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_SNOOP) != 0 ? DMAR_PTE_SNP : 0) |
+	    ((eflags & DMAR_MAP_ENTRY_TM) != 0 ? DMAR_PTE_TM : 0),
+	    (flags & DMAR_GM_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0);
+	if (error == ENOMEM) {
+		dmar_ctx_unload_entry(entry, false);
+		return (error);
+	}
+	KASSERT(error == 0,
+	    ("unexpected error %d from ctx_map_buf", error));
+
+	return (0);
+}
+
+int
+dmar_gas_reserve_region(struct dmar_ctx *ctx, dmar_gaddr_t start,
+    dmar_gaddr_t end)
+{
+	struct dmar_map_entry *entry;
+	int error;
+
+	entry = dmar_gas_alloc_entry(ctx, DMAR_PGF_WAITOK);
+	entry->start = start;
+	entry->end = end;
+	DMAR_CTX_LOCK(ctx);
+	error = dmar_gas_alloc_region(ctx, entry, DMAR_GM_CANWAIT);
+	if (error == 0)
+		entry->flags |= DMAR_MAP_ENTRY_UNMAPPED;
+	DMAR_CTX_UNLOCK(ctx);
+	if (error != 0)
+		dmar_gas_free_entry(ctx, entry);
+	return (error);
+}


Property changes on: trunk/sys/x86/iommu/intel_gas.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_idpgtbl.c
===================================================================
--- trunk/sys/x86/iommu/intel_idpgtbl.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_idpgtbl.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,785 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_idpgtbl.c 286854 2015-08-17 18:36:16Z kib $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/rman.h>
+#include <sys/sf_buf.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+static int ctx_unmap_buf_locked(struct dmar_ctx *ctx, dmar_gaddr_t base,
+    dmar_gaddr_t size, int flags);
+
+/*
+ * The cache of the identity mapping page tables for the DMARs.  Using
+ * the cache saves significant amount of memory for page tables by
+ * reusing the page tables, since usually DMARs are identical and have
+ * the same capabilities.  Still, cache records the information needed
+ * to match DMAR capabilities and page table format, to correctly
+ * handle different DMARs.
+ */
+
+struct idpgtbl {
+	dmar_gaddr_t maxaddr;	/* Page table covers the guest address
+				   range [0..maxaddr) */
+	int pglvl;		/* Total page table levels ignoring
+				   superpages */
+	int leaf;		/* The last materialized page table
+				   level, it is non-zero if superpages
+				   are supported */
+	vm_object_t pgtbl_obj;	/* The page table pages */
+	LIST_ENTRY(idpgtbl) link;
+};
+
+static struct sx idpgtbl_lock;
+SX_SYSINIT(idpgtbl, &idpgtbl_lock, "idpgtbl");
+static LIST_HEAD(, idpgtbl) idpgtbls = LIST_HEAD_INITIALIZER(idpgtbls);
+static MALLOC_DEFINE(M_DMAR_IDPGTBL, "dmar_idpgtbl",
+    "Intel DMAR Identity mappings cache elements");
+
+/*
+ * Build the next level of the page tables for the identity mapping.
+ * - lvl is the level to build;
+ * - idx is the index of the page table page in the pgtbl_obj, which is
+ *   being allocated filled now;
+ * - addr is the starting address in the bus address space which is
+ *   mapped by the page table page.
+ */
+static void
+ctx_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx,
+    dmar_gaddr_t addr)
+{
+	vm_page_t m1;
+	dmar_pte_t *pte;
+	struct sf_buf *sf;
+	dmar_gaddr_t f, pg_sz;
+	vm_pindex_t base;
+	int i;
+
+	VM_OBJECT_ASSERT_LOCKED(tbl->pgtbl_obj);
+	if (addr >= tbl->maxaddr)
+		return;
+	(void)dmar_pgalloc(tbl->pgtbl_obj, idx, DMAR_PGF_OBJL | DMAR_PGF_WAITOK |
+	    DMAR_PGF_ZERO);
+	base = idx * DMAR_NPTEPG + 1; /* Index of the first child page of idx */
+	pg_sz = pglvl_page_size(tbl->pglvl, lvl);
+	if (lvl != tbl->leaf) {
+		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz)
+			ctx_idmap_nextlvl(tbl, lvl + 1, base + i, f);
+	}
+	VM_OBJECT_WUNLOCK(tbl->pgtbl_obj);
+	pte = dmar_map_pgtbl(tbl->pgtbl_obj, idx, DMAR_PGF_WAITOK, &sf);
+	if (lvl == tbl->leaf) {
+		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz) {
+			if (f >= tbl->maxaddr)
+				break;
+			pte[i].pte = (DMAR_PTE_ADDR_MASK & f) |
+			    DMAR_PTE_R | DMAR_PTE_W;
+		}
+	} else {
+		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz) {
+			if (f >= tbl->maxaddr)
+				break;
+			m1 = dmar_pgalloc(tbl->pgtbl_obj, base + i,
+			    DMAR_PGF_NOALLOC);
+			KASSERT(m1 != NULL, ("lost page table page"));
+			pte[i].pte = (DMAR_PTE_ADDR_MASK &
+			    VM_PAGE_TO_PHYS(m1)) | DMAR_PTE_R | DMAR_PTE_W;
+		}
+	}
+	/* ctx_get_idmap_pgtbl flushes CPU cache if needed. */
+	dmar_unmap_pgtbl(sf);
+	VM_OBJECT_WLOCK(tbl->pgtbl_obj);
+}
+
+/*
+ * Find a ready and compatible identity-mapping page table in the
+ * cache. If not found, populate the identity-mapping page table for
+ * the context, up to the maxaddr. The maxaddr byte is allowed to be
+ * not mapped, which is aligned with the definition of Maxmem as the
+ * highest usable physical address + 1.  If superpages are used, the
+ * maxaddr is typically mapped.
+ */
+vm_object_t
+ctx_get_idmap_pgtbl(struct dmar_ctx *ctx, dmar_gaddr_t maxaddr)
+{
+	struct dmar_unit *unit;
+	struct idpgtbl *tbl;
+	vm_object_t res;
+	vm_page_t m;
+	int leaf, i;
+
+	leaf = 0; /* silence gcc */
+
+	/*
+	 * First, determine where to stop the paging structures.
+	 */
+	for (i = 0; i < ctx->pglvl; i++) {
+		if (i == ctx->pglvl - 1 || ctx_is_sp_lvl(ctx, i)) {
+			leaf = i;
+			break;
+		}
+	}
+
+	/*
+	 * Search the cache for a compatible page table.  Qualified
+	 * page table must map up to maxaddr, its level must be
+	 * supported by the DMAR and leaf should be equal to the
+	 * calculated value.  The later restriction could be lifted
+	 * but I believe it is currently impossible to have any
+	 * deviations for existing hardware.
+	 */
+	sx_slock(&idpgtbl_lock);
+	LIST_FOREACH(tbl, &idpgtbls, link) {
+		if (tbl->maxaddr >= maxaddr &&
+		    dmar_pglvl_supported(ctx->dmar, tbl->pglvl) &&
+		    tbl->leaf == leaf) {
+			res = tbl->pgtbl_obj;
+			vm_object_reference(res);
+			sx_sunlock(&idpgtbl_lock);
+			ctx->pglvl = tbl->pglvl; /* XXXKIB ? */
+			goto end;
+		}
+	}
+
+	/*
+	 * Not found in cache, relock the cache into exclusive mode to
+	 * be able to add element, and recheck cache again after the
+	 * relock.
+	 */
+	sx_sunlock(&idpgtbl_lock);
+	sx_xlock(&idpgtbl_lock);
+	LIST_FOREACH(tbl, &idpgtbls, link) {
+		if (tbl->maxaddr >= maxaddr &&
+		    dmar_pglvl_supported(ctx->dmar, tbl->pglvl) &&
+		    tbl->leaf == leaf) {
+			res = tbl->pgtbl_obj;
+			vm_object_reference(res);
+			sx_xunlock(&idpgtbl_lock);
+			ctx->pglvl = tbl->pglvl; /* XXXKIB ? */
+			return (res);
+		}
+	}
+
+	/*
+	 * Still not found, create new page table.
+	 */
+	tbl = malloc(sizeof(*tbl), M_DMAR_IDPGTBL, M_WAITOK);
+	tbl->pglvl = ctx->pglvl;
+	tbl->leaf = leaf;
+	tbl->maxaddr = maxaddr;
+	tbl->pgtbl_obj = vm_pager_allocate(OBJT_PHYS, NULL,
+	    IDX_TO_OFF(pglvl_max_pages(tbl->pglvl)), 0, 0, NULL);
+	VM_OBJECT_WLOCK(tbl->pgtbl_obj);
+	ctx_idmap_nextlvl(tbl, 0, 0, 0);
+	VM_OBJECT_WUNLOCK(tbl->pgtbl_obj);
+	LIST_INSERT_HEAD(&idpgtbls, tbl, link);
+	res = tbl->pgtbl_obj;
+	vm_object_reference(res);
+	sx_xunlock(&idpgtbl_lock);
+
+end:
+	/*
+	 * Table was found or created.
+	 *
+	 * If DMAR does not snoop paging structures accesses, flush
+	 * CPU cache to memory.  Note that dmar_unmap_pgtbl() coherent
+	 * argument was possibly invalid at the time of the identity
+	 * page table creation, since DMAR which was passed at the
+	 * time of creation could be coherent, while current DMAR is
+	 * not.
+	 *
+	 * If DMAR cannot look into the chipset write buffer, flush it
+	 * as well.
+	 */
+	unit = ctx->dmar;
+	if (!DMAR_IS_COHERENT(unit)) {
+		VM_OBJECT_WLOCK(res);
+		for (m = vm_page_lookup(res, 0); m != NULL;
+		     m = vm_page_next(m))
+			pmap_invalidate_cache_pages(&m, 1);
+		VM_OBJECT_WUNLOCK(res);
+	}
+	if ((unit->hw_cap & DMAR_CAP_RWBF) != 0) {
+		DMAR_LOCK(unit);
+		dmar_flush_write_bufs(unit);
+		DMAR_UNLOCK(unit);
+	}
+	
+	return (res);
+}
+
+/*
+ * Return a reference to the identity mapping page table to the cache.
+ */
+void
+put_idmap_pgtbl(vm_object_t obj)
+{
+	struct idpgtbl *tbl, *tbl1;
+	vm_object_t rmobj;
+
+	sx_slock(&idpgtbl_lock);
+	KASSERT(obj->ref_count >= 2, ("lost cache reference"));
+	vm_object_deallocate(obj);
+
+	/*
+	 * Cache always owns one last reference on the page table object.
+	 * If there is an additional reference, object must stay.
+	 */
+	if (obj->ref_count > 1) {
+		sx_sunlock(&idpgtbl_lock);
+		return;
+	}
+
+	/*
+	 * Cache reference is the last, remove cache element and free
+	 * page table object, returning the page table pages to the
+	 * system.
+	 */
+	sx_sunlock(&idpgtbl_lock);
+	sx_xlock(&idpgtbl_lock);
+	LIST_FOREACH_SAFE(tbl, &idpgtbls, link, tbl1) {
+		rmobj = tbl->pgtbl_obj;
+		if (rmobj->ref_count == 1) {
+			LIST_REMOVE(tbl, link);
+			atomic_subtract_int(&dmar_tbl_pagecnt,
+			    rmobj->resident_page_count);
+			vm_object_deallocate(rmobj);
+			free(tbl, M_DMAR_IDPGTBL);
+		}
+	}
+	sx_xunlock(&idpgtbl_lock);
+}
+
+/*
+ * The core routines to map and unmap host pages at the given guest
+ * address.  Support superpages.
+ */
+
+/*
+ * Index of the pte for the guest address base in the page table at
+ * the level lvl.
+ */
+static int
+ctx_pgtbl_pte_off(struct dmar_ctx *ctx, dmar_gaddr_t base, int lvl)
+{
+
+	base >>= DMAR_PAGE_SHIFT + (ctx->pglvl - lvl - 1) * DMAR_NPTEPGSHIFT;
+	return (base & DMAR_PTEMASK);
+}
+
+/*
+ * Returns the page index of the page table page in the page table
+ * object, which maps the given address base at the page table level
+ * lvl.
+ */
+static vm_pindex_t
+ctx_pgtbl_get_pindex(struct dmar_ctx *ctx, dmar_gaddr_t base, int lvl)
+{
+	vm_pindex_t idx, pidx;
+	int i;
+
+	KASSERT(lvl >= 0 && lvl < ctx->pglvl, ("wrong lvl %p %d", ctx, lvl));
+
+	for (pidx = idx = 0, i = 0; i < lvl; i++, pidx = idx)
+		idx = ctx_pgtbl_pte_off(ctx, base, i) + pidx * DMAR_NPTEPG + 1;
+	return (idx);
+}
+
+static dmar_pte_t *
+ctx_pgtbl_map_pte(struct dmar_ctx *ctx, dmar_gaddr_t base, int lvl, int flags,
+    vm_pindex_t *idxp, struct sf_buf **sf)
+{
+	vm_page_t m;
+	struct sf_buf *sfp;
+	dmar_pte_t *pte, *ptep;
+	vm_pindex_t idx, idx1;
+
+	DMAR_CTX_ASSERT_PGLOCKED(ctx);
+	KASSERT((flags & DMAR_PGF_OBJL) != 0, ("lost PGF_OBJL"));
+
+	idx = ctx_pgtbl_get_pindex(ctx, base, lvl);
+	if (*sf != NULL && idx == *idxp) {
+		pte = (dmar_pte_t *)sf_buf_kva(*sf);
+	} else {
+		if (*sf != NULL)
+			dmar_unmap_pgtbl(*sf);
+		*idxp = idx;
+retry:
+		pte = dmar_map_pgtbl(ctx->pgtbl_obj, idx, flags, sf);
+		if (pte == NULL) {
+			KASSERT(lvl > 0, ("lost root page table page %p", ctx));
+			/*
+			 * Page table page does not exist, allocate
+			 * it and create a pte in the preceeding page level
+			 * to reference the allocated page table page.
+			 */
+			m = dmar_pgalloc(ctx->pgtbl_obj, idx, flags |
+			    DMAR_PGF_ZERO);
+			if (m == NULL)
+				return (NULL);
+
+			/*
+			 * Prevent potential free while pgtbl_obj is
+			 * unlocked in the recursive call to
+			 * ctx_pgtbl_map_pte(), if other thread did
+			 * pte write and clean while the lock if
+			 * dropped.
+			 */
+			m->wire_count++;
+
+			sfp = NULL;
+			ptep = ctx_pgtbl_map_pte(ctx, base, lvl - 1, flags,
+			    &idx1, &sfp);
+			if (ptep == NULL) {
+				KASSERT(m->pindex != 0,
+				    ("loosing root page %p", ctx));
+				m->wire_count--;
+				dmar_pgfree(ctx->pgtbl_obj, m->pindex, flags);
+				return (NULL);
+			}
+			dmar_pte_store(&ptep->pte, DMAR_PTE_R | DMAR_PTE_W |
+			    VM_PAGE_TO_PHYS(m));
+			dmar_flush_pte_to_ram(ctx->dmar, ptep);
+			sf_buf_page(sfp)->wire_count += 1;
+			m->wire_count--;
+			dmar_unmap_pgtbl(sfp);
+			/* Only executed once. */
+			goto retry;
+		}
+	}
+	pte += ctx_pgtbl_pte_off(ctx, base, lvl);
+	return (pte);
+}
+
+static int
+ctx_map_buf_locked(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size,
+    vm_page_t *ma, uint64_t pflags, int flags)
+{
+	dmar_pte_t *pte;
+	struct sf_buf *sf;
+	dmar_gaddr_t pg_sz, base1, size1;
+	vm_pindex_t pi, c, idx, run_sz;
+	int lvl;
+	bool superpage;
+
+	DMAR_CTX_ASSERT_PGLOCKED(ctx);
+
+	base1 = base;
+	size1 = size;
+	flags |= DMAR_PGF_OBJL;
+	TD_PREP_PINNED_ASSERT;
+
+	for (sf = NULL, pi = 0; size > 0; base += pg_sz, size -= pg_sz,
+	    pi += run_sz) {
+		for (lvl = 0, c = 0, superpage = false;; lvl++) {
+			pg_sz = ctx_page_size(ctx, lvl);
+			run_sz = pg_sz >> DMAR_PAGE_SHIFT;
+			if (lvl == ctx->pglvl - 1)
+				break;
+			/*
+			 * Check if the current base suitable for the
+			 * superpage mapping.  First, verify the level.
+			 */
+			if (!ctx_is_sp_lvl(ctx, lvl))
+				continue;
+			/*
+			 * Next, look at the size of the mapping and
+			 * alignment of both guest and host addresses.
+			 */
+			if (size < pg_sz || (base & (pg_sz - 1)) != 0 ||
+			    (VM_PAGE_TO_PHYS(ma[pi]) & (pg_sz - 1)) != 0)
+				continue;
+			/* All passed, check host pages contiguouty. */
+			if (c == 0) {
+				for (c = 1; c < run_sz; c++) {
+					if (VM_PAGE_TO_PHYS(ma[pi + c]) !=
+					    VM_PAGE_TO_PHYS(ma[pi + c - 1]) +
+					    PAGE_SIZE)
+						break;
+				}
+			}
+			if (c >= run_sz) {
+				superpage = true;
+				break;
+			}
+		}
+		KASSERT(size >= pg_sz,
+		    ("mapping loop overflow %p %jx %jx %jx", ctx,
+		    (uintmax_t)base, (uintmax_t)size, (uintmax_t)pg_sz));
+		KASSERT(pg_sz > 0, ("pg_sz 0 lvl %d", lvl));
+		pte = ctx_pgtbl_map_pte(ctx, base, lvl, flags, &idx, &sf);
+		if (pte == NULL) {
+			KASSERT((flags & DMAR_PGF_WAITOK) == 0,
+			    ("failed waitable pte alloc %p", ctx));
+			if (sf != NULL)
+				dmar_unmap_pgtbl(sf);
+			ctx_unmap_buf_locked(ctx, base1, base - base1, flags);
+			TD_PINNED_ASSERT;
+			return (ENOMEM);
+		}
+		dmar_pte_store(&pte->pte, VM_PAGE_TO_PHYS(ma[pi]) | pflags |
+		    (superpage ? DMAR_PTE_SP : 0));
+		dmar_flush_pte_to_ram(ctx->dmar, pte);
+		sf_buf_page(sf)->wire_count += 1;
+	}
+	if (sf != NULL)
+		dmar_unmap_pgtbl(sf);
+	TD_PINNED_ASSERT;
+	return (0);
+}
+
+int
+ctx_map_buf(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size,
+    vm_page_t *ma, uint64_t pflags, int flags)
+{
+	struct dmar_unit *unit;
+	int error;
+
+	unit = ctx->dmar;
+
+	KASSERT((ctx->flags & DMAR_CTX_IDMAP) == 0,
+	    ("modifying idmap pagetable ctx %p", ctx));
+	KASSERT((base & DMAR_PAGE_MASK) == 0,
+	    ("non-aligned base %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT((size & DMAR_PAGE_MASK) == 0,
+	    ("non-aligned size %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT(size > 0, ("zero size %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT(base < (1ULL << ctx->agaw),
+	    ("base too high %p %jx %jx agaw %d", ctx, (uintmax_t)base,
+	    (uintmax_t)size, ctx->agaw));
+	KASSERT(base + size < (1ULL << ctx->agaw),
+	    ("end too high %p %jx %jx agaw %d", ctx, (uintmax_t)base,
+	    (uintmax_t)size, ctx->agaw));
+	KASSERT(base + size > base,
+	    ("size overflow %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT((pflags & (DMAR_PTE_R | DMAR_PTE_W)) != 0,
+	    ("neither read nor write %jx", (uintmax_t)pflags));
+	KASSERT((pflags & ~(DMAR_PTE_R | DMAR_PTE_W | DMAR_PTE_SNP |
+	    DMAR_PTE_TM)) == 0,
+	    ("invalid pte flags %jx", (uintmax_t)pflags));
+	KASSERT((pflags & DMAR_PTE_SNP) == 0 ||
+	    (unit->hw_ecap & DMAR_ECAP_SC) != 0,
+	    ("PTE_SNP for dmar without snoop control %p %jx",
+	    ctx, (uintmax_t)pflags));
+	KASSERT((pflags & DMAR_PTE_TM) == 0 ||
+	    (unit->hw_ecap & DMAR_ECAP_DI) != 0,
+	    ("PTE_TM for dmar without DIOTLB %p %jx",
+	    ctx, (uintmax_t)pflags));
+	KASSERT((flags & ~DMAR_PGF_WAITOK) == 0, ("invalid flags %x", flags));
+
+	DMAR_CTX_PGLOCK(ctx);
+	error = ctx_map_buf_locked(ctx, base, size, ma, pflags, flags);
+	DMAR_CTX_PGUNLOCK(ctx);
+	if (error != 0)
+		return (error);
+
+	if ((unit->hw_cap & DMAR_CAP_CM) != 0)
+		ctx_flush_iotlb_sync(ctx, base, size);
+	else if ((unit->hw_cap & DMAR_CAP_RWBF) != 0) {
+		/* See 11.1 Write Buffer Flushing. */
+		DMAR_LOCK(unit);
+		dmar_flush_write_bufs(unit);
+		DMAR_UNLOCK(unit);
+	}
+	return (0);
+}
+
+static void ctx_unmap_clear_pte(struct dmar_ctx *ctx, dmar_gaddr_t base,
+    int lvl, int flags, dmar_pte_t *pte, struct sf_buf **sf, bool free_fs);
+
+static void
+ctx_free_pgtbl_pde(struct dmar_ctx *ctx, dmar_gaddr_t base, int lvl, int flags)
+{
+	struct sf_buf *sf;
+	dmar_pte_t *pde;
+	vm_pindex_t idx;
+
+	sf = NULL;
+	pde = ctx_pgtbl_map_pte(ctx, base, lvl, flags, &idx, &sf);
+	ctx_unmap_clear_pte(ctx, base, lvl, flags, pde, &sf, true);
+}
+
+static void
+ctx_unmap_clear_pte(struct dmar_ctx *ctx, dmar_gaddr_t base, int lvl,
+    int flags, dmar_pte_t *pte, struct sf_buf **sf, bool free_sf)
+{
+	vm_page_t m;
+
+	dmar_pte_clear(&pte->pte);
+	dmar_flush_pte_to_ram(ctx->dmar, pte);
+	m = sf_buf_page(*sf);
+	if (free_sf) {
+		dmar_unmap_pgtbl(*sf);
+		*sf = NULL;
+	}
+	m->wire_count--;
+	if (m->wire_count != 0)
+		return;
+	KASSERT(lvl != 0,
+	    ("lost reference (lvl) on root pg ctx %p base %jx lvl %d",
+	    ctx, (uintmax_t)base, lvl));
+	KASSERT(m->pindex != 0,
+	    ("lost reference (idx) on root pg ctx %p base %jx lvl %d",
+	    ctx, (uintmax_t)base, lvl));
+	dmar_pgfree(ctx->pgtbl_obj, m->pindex, flags);
+	ctx_free_pgtbl_pde(ctx, base, lvl - 1, flags);
+}
+
+/*
+ * Assumes that the unmap is never partial.
+ */
+static int
+ctx_unmap_buf_locked(struct dmar_ctx *ctx, dmar_gaddr_t base,
+    dmar_gaddr_t size, int flags)
+{
+	dmar_pte_t *pte;
+	struct sf_buf *sf;
+	vm_pindex_t idx;
+	dmar_gaddr_t pg_sz;
+	int lvl;
+
+	DMAR_CTX_ASSERT_PGLOCKED(ctx);
+	if (size == 0)
+		return (0);
+
+	KASSERT((ctx->flags & DMAR_CTX_IDMAP) == 0,
+	    ("modifying idmap pagetable ctx %p", ctx));
+	KASSERT((base & DMAR_PAGE_MASK) == 0,
+	    ("non-aligned base %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT((size & DMAR_PAGE_MASK) == 0,
+	    ("non-aligned size %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT(base < (1ULL << ctx->agaw),
+	    ("base too high %p %jx %jx agaw %d", ctx, (uintmax_t)base,
+	    (uintmax_t)size, ctx->agaw));
+	KASSERT(base + size < (1ULL << ctx->agaw),
+	    ("end too high %p %jx %jx agaw %d", ctx, (uintmax_t)base,
+	    (uintmax_t)size, ctx->agaw));
+	KASSERT(base + size > base,
+	    ("size overflow %p %jx %jx", ctx, (uintmax_t)base,
+	    (uintmax_t)size));
+	KASSERT((flags & ~DMAR_PGF_WAITOK) == 0, ("invalid flags %x", flags));
+
+	pg_sz = 0; /* silence gcc */
+	flags |= DMAR_PGF_OBJL;
+	TD_PREP_PINNED_ASSERT;
+
+	for (sf = NULL; size > 0; base += pg_sz, size -= pg_sz) {
+		for (lvl = 0; lvl < ctx->pglvl; lvl++) {
+			if (lvl != ctx->pglvl - 1 && !ctx_is_sp_lvl(ctx, lvl))
+				continue;
+			pg_sz = ctx_page_size(ctx, lvl);
+			if (pg_sz > size)
+				continue;
+			pte = ctx_pgtbl_map_pte(ctx, base, lvl, flags,
+			    &idx, &sf);
+			KASSERT(pte != NULL,
+			    ("sleeping or page missed %p %jx %d 0x%x",
+			    ctx, (uintmax_t)base, lvl, flags));
+			if ((pte->pte & DMAR_PTE_SP) != 0 ||
+			    lvl == ctx->pglvl - 1) {
+				ctx_unmap_clear_pte(ctx, base, lvl, flags,
+				    pte, &sf, false);
+				break;
+			}
+		}
+		KASSERT(size >= pg_sz,
+		    ("unmapping loop overflow %p %jx %jx %jx", ctx,
+		    (uintmax_t)base, (uintmax_t)size, (uintmax_t)pg_sz));
+	}
+	if (sf != NULL)
+		dmar_unmap_pgtbl(sf);
+	/*
+	 * See 11.1 Write Buffer Flushing for an explanation why RWBF
+	 * can be ignored there.
+	 */
+
+	TD_PINNED_ASSERT;
+	return (0);
+}
+
+int
+ctx_unmap_buf(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size,
+    int flags)
+{
+	int error;
+
+	DMAR_CTX_PGLOCK(ctx);
+	error = ctx_unmap_buf_locked(ctx, base, size, flags);
+	DMAR_CTX_PGUNLOCK(ctx);
+	return (error);
+}
+
+int
+ctx_alloc_pgtbl(struct dmar_ctx *ctx)
+{
+	vm_page_t m;
+
+	KASSERT(ctx->pgtbl_obj == NULL, ("already initialized %p", ctx));
+
+	ctx->pgtbl_obj = vm_pager_allocate(OBJT_PHYS, NULL,
+	    IDX_TO_OFF(pglvl_max_pages(ctx->pglvl)), 0, 0, NULL);
+	DMAR_CTX_PGLOCK(ctx);
+	m = dmar_pgalloc(ctx->pgtbl_obj, 0, DMAR_PGF_WAITOK |
+	    DMAR_PGF_ZERO | DMAR_PGF_OBJL);
+	/* No implicit free of the top level page table page. */
+	m->wire_count = 1;
+	DMAR_CTX_PGUNLOCK(ctx);
+	return (0);
+}
+
+void
+ctx_free_pgtbl(struct dmar_ctx *ctx)
+{
+	vm_object_t obj;
+	vm_page_t m;
+
+	obj = ctx->pgtbl_obj;
+	if (obj == NULL) {
+		KASSERT((ctx->dmar->hw_ecap & DMAR_ECAP_PT) != 0 &&
+		    (ctx->flags & DMAR_CTX_IDMAP) != 0,
+		    ("lost pagetable object ctx %p", ctx));
+		return;
+	}
+	DMAR_CTX_ASSERT_PGLOCKED(ctx);
+	ctx->pgtbl_obj = NULL;
+
+	if ((ctx->flags & DMAR_CTX_IDMAP) != 0) {
+		put_idmap_pgtbl(obj);
+		ctx->flags &= ~DMAR_CTX_IDMAP;
+		return;
+	}
+
+	/* Obliterate wire_counts */
+	VM_OBJECT_ASSERT_WLOCKED(obj);
+	for (m = vm_page_lookup(obj, 0); m != NULL; m = vm_page_next(m))
+		m->wire_count = 0;
+	VM_OBJECT_WUNLOCK(obj);
+	vm_object_deallocate(obj);
+}
+
+static inline uint64_t
+ctx_wait_iotlb_flush(struct dmar_unit *unit, uint64_t wt, int iro)
+{
+	uint64_t iotlbr;
+
+	dmar_write8(unit, iro + DMAR_IOTLB_REG_OFF, DMAR_IOTLB_IVT |
+	    DMAR_IOTLB_DR | DMAR_IOTLB_DW | wt);
+	for (;;) {
+		iotlbr = dmar_read8(unit, iro + DMAR_IOTLB_REG_OFF);
+		if ((iotlbr & DMAR_IOTLB_IVT) == 0)
+			break;
+		cpu_spinwait();
+	}
+	return (iotlbr);
+}
+
+void
+ctx_flush_iotlb_sync(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_gaddr_t size)
+{
+	struct dmar_unit *unit;
+	dmar_gaddr_t isize;
+	uint64_t iotlbr;
+	int am, iro;
+
+	unit = ctx->dmar;
+	KASSERT(!unit->qi_enabled, ("dmar%d: sync iotlb flush call",
+	    unit->unit));
+	iro = DMAR_ECAP_IRO(unit->hw_ecap) * 16;
+	DMAR_LOCK(unit);
+	if ((unit->hw_cap & DMAR_CAP_PSI) == 0 || size > 2 * 1024 * 1024) {
+		iotlbr = ctx_wait_iotlb_flush(unit, DMAR_IOTLB_IIRG_DOM |
+		    DMAR_IOTLB_DID(ctx->domain), iro);
+		KASSERT((iotlbr & DMAR_IOTLB_IAIG_MASK) !=
+		    DMAR_IOTLB_IAIG_INVLD,
+		    ("dmar%d: invalidation failed %jx", unit->unit,
+		    (uintmax_t)iotlbr));
+	} else {
+		for (; size > 0; base += isize, size -= isize) {
+			am = calc_am(unit, base, size, &isize);
+			dmar_write8(unit, iro, base | am);
+			iotlbr = ctx_wait_iotlb_flush(unit,
+			    DMAR_IOTLB_IIRG_PAGE | DMAR_IOTLB_DID(ctx->domain),
+			    iro);
+			KASSERT((iotlbr & DMAR_IOTLB_IAIG_MASK) !=
+			    DMAR_IOTLB_IAIG_INVLD,
+			    ("dmar%d: PSI invalidation failed "
+			    "iotlbr 0x%jx base 0x%jx size 0x%jx am %d",
+			    unit->unit, (uintmax_t)iotlbr,
+			    (uintmax_t)base, (uintmax_t)size, am));
+			/*
+			 * Any non-page granularity covers whole guest
+			 * address space for the domain.
+			 */
+			if ((iotlbr & DMAR_IOTLB_IAIG_MASK) !=
+			    DMAR_IOTLB_IAIG_PAGE)
+				break;
+		}
+	}
+	DMAR_UNLOCK(unit);
+}


Property changes on: trunk/sys/x86/iommu/intel_idpgtbl.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_qi.c
===================================================================
--- trunk/sys/x86/iommu/intel_qi.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_qi.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,417 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_qi.c 284019 2015-06-05 08:23:33Z kib $");
+
+#include "opt_acpi.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/memdesc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <machine/bus.h>
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <machine/cpu.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+static bool
+dmar_qi_seq_processed(const struct dmar_unit *unit,
+    const struct dmar_qi_genseq *pseq)
+{
+
+	return (pseq->gen < unit->inv_waitd_gen ||
+	    (pseq->gen == unit->inv_waitd_gen &&
+	     pseq->seq <= unit->inv_waitd_seq_hw));
+}
+
+static int
+dmar_enable_qi(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	unit->hw_gcmd |= DMAR_GCMD_QIE;
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES) == 0)
+		cpu_spinwait();
+	return (0);
+}
+
+static int
+dmar_disable_qi(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	unit->hw_gcmd &= ~DMAR_GCMD_QIE;
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES) != 0)
+		cpu_spinwait();
+	return (0);
+}
+
+static void
+dmar_qi_advance_tail(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	dmar_write4(unit, DMAR_IQT_REG, unit->inv_queue_tail);
+}
+
+static void
+dmar_qi_ensure(struct dmar_unit *unit, int descr_count)
+{
+	uint32_t head;
+	int bytes;
+
+	DMAR_ASSERT_LOCKED(unit);
+	bytes = descr_count << DMAR_IQ_DESCR_SZ_SHIFT;
+	for (;;) {
+		if (bytes <= unit->inv_queue_avail)
+			break;
+		/* refill */
+		head = dmar_read4(unit, DMAR_IQH_REG);
+		head &= DMAR_IQH_MASK;
+		unit->inv_queue_avail = head - unit->inv_queue_tail -
+		    DMAR_IQ_DESCR_SZ;
+		if (head <= unit->inv_queue_tail)
+			unit->inv_queue_avail += unit->inv_queue_size;
+		if (bytes <= unit->inv_queue_avail)
+			break;
+
+		/*
+		 * No space in the queue, do busy wait.  Hardware must
+		 * make a progress.  But first advance the tail to
+		 * inform the descriptor streamer about entries we
+		 * might have already filled, otherwise they could
+		 * clog the whole queue..
+		 */
+		dmar_qi_advance_tail(unit);
+		unit->inv_queue_full++;
+		cpu_spinwait();
+	}
+	unit->inv_queue_avail -= bytes;
+}
+
+static void
+dmar_qi_emit(struct dmar_unit *unit, uint64_t data1, uint64_t data2)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	*(volatile uint64_t *)(unit->inv_queue + unit->inv_queue_tail) = data1;
+	unit->inv_queue_tail += DMAR_IQ_DESCR_SZ / 2;
+	KASSERT(unit->inv_queue_tail <= unit->inv_queue_size,
+	    ("tail overflow 0x%x 0x%jx", unit->inv_queue_tail,
+	    (uintmax_t)unit->inv_queue_size));
+	unit->inv_queue_tail &= unit->inv_queue_size - 1;
+	*(volatile uint64_t *)(unit->inv_queue + unit->inv_queue_tail) = data2;
+	unit->inv_queue_tail += DMAR_IQ_DESCR_SZ / 2;
+	KASSERT(unit->inv_queue_tail <= unit->inv_queue_size,
+	    ("tail overflow 0x%x 0x%jx", unit->inv_queue_tail,
+	    (uintmax_t)unit->inv_queue_size));
+	unit->inv_queue_tail &= unit->inv_queue_size - 1;
+}
+
+static void
+dmar_qi_emit_wait_descr(struct dmar_unit *unit, uint32_t seq, bool intr,
+    bool memw, bool fence)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	dmar_qi_emit(unit, DMAR_IQ_DESCR_WAIT_ID |
+	    (intr ? DMAR_IQ_DESCR_WAIT_IF : 0) |
+	    (memw ? DMAR_IQ_DESCR_WAIT_SW : 0) |
+	    (fence ? DMAR_IQ_DESCR_WAIT_FN : 0) |
+	    (memw ? DMAR_IQ_DESCR_WAIT_SD(seq) : 0),
+	    memw ? unit->inv_waitd_seq_hw_phys : 0);
+}
+
+static void
+dmar_qi_emit_wait_seq(struct dmar_unit *unit, struct dmar_qi_genseq *pseq)
+{
+	struct dmar_qi_genseq gsec;
+	uint32_t seq;
+
+	KASSERT(pseq != NULL, ("wait descriptor with no place for seq"));
+	DMAR_ASSERT_LOCKED(unit);
+	if (unit->inv_waitd_seq == 0xffffffff) {
+		gsec.gen = unit->inv_waitd_gen;
+		gsec.seq = unit->inv_waitd_seq;
+		dmar_qi_ensure(unit, 1);
+		dmar_qi_emit_wait_descr(unit, gsec.seq, false, true, false);
+		dmar_qi_advance_tail(unit);
+		while (!dmar_qi_seq_processed(unit, &gsec))
+			cpu_spinwait();
+		unit->inv_waitd_gen++;
+		unit->inv_waitd_seq = 1;
+	}
+	seq = unit->inv_waitd_seq++;
+	pseq->gen = unit->inv_waitd_gen;
+	pseq->seq = seq;
+	dmar_qi_emit_wait_descr(unit, seq, true, true, false);
+}
+
+static void
+dmar_qi_wait_for_seq(struct dmar_unit *unit, const struct dmar_qi_genseq *gseq)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	unit->inv_seq_waiters++;
+	while (!dmar_qi_seq_processed(unit, gseq)) {
+		if (cold) {
+			cpu_spinwait();
+		} else {
+			msleep(&unit->inv_seq_waiters, &unit->lock, 0,
+			    "dmarse", hz);
+		}
+	}
+	unit->inv_seq_waiters--;
+}
+
+void
+dmar_qi_invalidate_locked(struct dmar_ctx *ctx, dmar_gaddr_t base,
+    dmar_gaddr_t size, struct dmar_qi_genseq *pseq)
+{
+	struct dmar_unit *unit;
+	dmar_gaddr_t isize;
+	int am;
+
+	unit = ctx->dmar;
+	DMAR_ASSERT_LOCKED(unit);
+	for (; size > 0; base += isize, size -= isize) {
+		am = calc_am(unit, base, size, &isize);
+		dmar_qi_ensure(unit, 1);
+		dmar_qi_emit(unit, DMAR_IQ_DESCR_IOTLB_INV |
+		    DMAR_IQ_DESCR_IOTLB_PAGE | DMAR_IQ_DESCR_IOTLB_DW |
+		    DMAR_IQ_DESCR_IOTLB_DR |
+		    DMAR_IQ_DESCR_IOTLB_DID(ctx->domain),
+		    base | am);
+	}
+	if (pseq != NULL) {
+		dmar_qi_ensure(unit, 1);
+		dmar_qi_emit_wait_seq(unit, pseq);
+	}
+	dmar_qi_advance_tail(unit);
+}
+
+void
+dmar_qi_invalidate_ctx_glob_locked(struct dmar_unit *unit)
+{
+	struct dmar_qi_genseq gseq;
+
+	DMAR_ASSERT_LOCKED(unit);
+	dmar_qi_ensure(unit, 2);
+	dmar_qi_emit(unit, DMAR_IQ_DESCR_CTX_INV | DMAR_IQ_DESCR_CTX_GLOB, 0);
+	dmar_qi_emit_wait_seq(unit, &gseq);
+	dmar_qi_advance_tail(unit);
+	dmar_qi_wait_for_seq(unit, &gseq);
+}
+
+void
+dmar_qi_invalidate_iotlb_glob_locked(struct dmar_unit *unit)
+{
+	struct dmar_qi_genseq gseq;
+
+	DMAR_ASSERT_LOCKED(unit);
+	dmar_qi_ensure(unit, 2);
+	dmar_qi_emit(unit, DMAR_IQ_DESCR_IOTLB_INV | DMAR_IQ_DESCR_IOTLB_GLOB |
+	    DMAR_IQ_DESCR_IOTLB_DW | DMAR_IQ_DESCR_IOTLB_DR, 0);
+	dmar_qi_emit_wait_seq(unit, &gseq);
+	dmar_qi_advance_tail(unit);
+	dmar_qi_wait_for_seq(unit, &gseq);
+}
+
+int
+dmar_qi_intr(void *arg)
+{
+	struct dmar_unit *unit;
+
+	unit = arg;
+	KASSERT(unit->qi_enabled, ("dmar%d: QI is not enabled", unit->unit));
+	taskqueue_enqueue_fast(unit->qi_taskqueue, &unit->qi_task);
+	return (FILTER_HANDLED);
+}
+
+static void
+dmar_qi_task(void *arg, int pending __unused)
+{
+	struct dmar_unit *unit;
+	struct dmar_map_entry *entry;
+	uint32_t ics;
+
+	unit = arg;
+
+	DMAR_LOCK(unit);
+	for (;;) {
+		entry = TAILQ_FIRST(&unit->tlb_flush_entries);
+		if (entry == NULL)
+			break;
+		if ((entry->gseq.gen == 0 && entry->gseq.seq == 0) ||
+		    !dmar_qi_seq_processed(unit, &entry->gseq))
+			break;
+		TAILQ_REMOVE(&unit->tlb_flush_entries, entry, dmamap_link);
+		DMAR_UNLOCK(unit);
+		dmar_ctx_free_entry(entry, (entry->flags &
+		    DMAR_MAP_ENTRY_QI_NF) == 0);
+		DMAR_LOCK(unit);
+	}
+	ics = dmar_read4(unit, DMAR_ICS_REG);
+	if ((ics & DMAR_ICS_IWC) != 0) {
+		ics = DMAR_ICS_IWC;
+		dmar_write4(unit, DMAR_ICS_REG, ics);
+	}
+	if (unit->inv_seq_waiters > 0)
+		wakeup(&unit->inv_seq_waiters);
+	DMAR_UNLOCK(unit);
+}
+
+int
+dmar_init_qi(struct dmar_unit *unit)
+{
+	uint64_t iqa;
+	uint32_t ics;
+	int qi_sz;
+
+	if (!DMAR_HAS_QI(unit) || (unit->hw_cap & DMAR_CAP_CM) != 0)
+		return (0);
+	unit->qi_enabled = 1;
+	TUNABLE_INT_FETCH("hw.dmar.qi", &unit->qi_enabled);
+	if (!unit->qi_enabled)
+		return (0);
+
+	TAILQ_INIT(&unit->tlb_flush_entries);
+	TASK_INIT(&unit->qi_task, 0, dmar_qi_task, unit);
+	unit->qi_taskqueue = taskqueue_create_fast("dmar", M_WAITOK,
+	    taskqueue_thread_enqueue, &unit->qi_taskqueue);
+	taskqueue_start_threads(&unit->qi_taskqueue, 1, PI_AV,
+	    "dmar%d qi taskq", unit->unit);
+
+	unit->inv_waitd_gen = 0;
+	unit->inv_waitd_seq = 1;
+
+	qi_sz = DMAR_IQA_QS_DEF;
+	TUNABLE_INT_FETCH("hw.dmar.qi_size", &qi_sz);
+	if (qi_sz > DMAR_IQA_QS_MAX)
+		qi_sz = DMAR_IQA_QS_MAX;
+	unit->inv_queue_size = (1ULL << qi_sz) * PAGE_SIZE;
+	/* Reserve one descriptor to prevent wraparound. */
+	unit->inv_queue_avail = unit->inv_queue_size - DMAR_IQ_DESCR_SZ;
+
+	/* The invalidation queue reads by DMARs are always coherent. */
+	unit->inv_queue = kmem_alloc_contig(kernel_arena, unit->inv_queue_size,
+	    M_WAITOK | M_ZERO, 0, dmar_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+	unit->inv_waitd_seq_hw_phys = pmap_kextract(
+	    (vm_offset_t)&unit->inv_waitd_seq_hw);
+
+	DMAR_LOCK(unit);
+	dmar_write8(unit, DMAR_IQT_REG, 0);
+	iqa = pmap_kextract(unit->inv_queue);
+	iqa |= qi_sz;
+	dmar_write8(unit, DMAR_IQA_REG, iqa);
+	dmar_enable_qi(unit);
+	ics = dmar_read4(unit, DMAR_ICS_REG);
+	if ((ics & DMAR_ICS_IWC) != 0) {
+		ics = DMAR_ICS_IWC;
+		dmar_write4(unit, DMAR_ICS_REG, ics);
+	}
+	dmar_enable_qi_intr(unit);
+	DMAR_UNLOCK(unit);
+
+	return (0);
+}
+
+void
+dmar_fini_qi(struct dmar_unit *unit)
+{
+	struct dmar_qi_genseq gseq;
+
+	if (unit->qi_enabled)
+		return;
+	taskqueue_drain(unit->qi_taskqueue, &unit->qi_task);
+	taskqueue_free(unit->qi_taskqueue);
+	unit->qi_taskqueue = NULL;
+
+	DMAR_LOCK(unit);
+	/* quisce */
+	dmar_qi_ensure(unit, 1);
+	dmar_qi_emit_wait_seq(unit, &gseq);
+	dmar_qi_advance_tail(unit);
+	dmar_qi_wait_for_seq(unit, &gseq);
+	/* only after the quisce, disable queue */
+	dmar_disable_qi_intr(unit);
+	dmar_disable_qi(unit);
+	KASSERT(unit->inv_seq_waiters == 0,
+	    ("dmar%d: waiters on disabled queue", unit->unit));
+	DMAR_UNLOCK(unit);
+
+	kmem_free(kernel_arena, unit->inv_queue, unit->inv_queue_size);
+	unit->inv_queue = 0;
+	unit->inv_queue_size = 0;
+	unit->qi_enabled = 0;
+}
+
+void
+dmar_enable_qi_intr(struct dmar_unit *unit)
+{
+	uint32_t iectl;
+
+	DMAR_ASSERT_LOCKED(unit);
+	KASSERT(DMAR_HAS_QI(unit), ("dmar%d: QI is not supported", unit->unit));
+	iectl = dmar_read4(unit, DMAR_IECTL_REG);
+	iectl &= ~DMAR_IECTL_IM;
+	dmar_write4(unit, DMAR_IECTL_REG, iectl);
+}
+
+void
+dmar_disable_qi_intr(struct dmar_unit *unit)
+{
+	uint32_t iectl;
+
+	DMAR_ASSERT_LOCKED(unit);
+	KASSERT(DMAR_HAS_QI(unit), ("dmar%d: QI is not supported", unit->unit));
+	iectl = dmar_read4(unit, DMAR_IECTL_REG);
+	dmar_write4(unit, DMAR_IECTL_REG, iectl | DMAR_IECTL_IM);
+}


Property changes on: trunk/sys/x86/iommu/intel_qi.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_quirks.c
===================================================================
--- trunk/sys/x86/iommu/intel_quirks.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_quirks.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,196 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_quirks.c 257251 2013-10-28 13:33:29Z kib $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/memdesc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/rwlock.h>
+#include <sys/smp.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <machine/bus.h>
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+#include <dev/pci/pcivar.h>
+
+typedef void (*dmar_quirk_fun)(struct dmar_unit *);
+
+struct intel_dmar_quirk_cpu {
+	u_int ext_family;
+	u_int ext_model;
+	u_int family_code;
+	u_int model;
+	u_int stepping;
+	dmar_quirk_fun quirk;
+	const char *descr;
+};
+
+struct intel_dmar_quirk_nb {
+	u_int dev_id;
+	u_int rev_no;
+	dmar_quirk_fun quirk;
+	const char *descr;
+};
+
+static void
+dmar_match_quirks(struct dmar_unit *dmar,
+    const struct intel_dmar_quirk_nb *nb_quirks, int nb_quirks_len,
+    const struct intel_dmar_quirk_cpu *cpu_quirks, int cpu_quirks_len)
+{
+	device_t nb;
+	const struct intel_dmar_quirk_nb *nb_quirk;
+	const struct intel_dmar_quirk_cpu *cpu_quirk;
+	u_int p[4];
+	u_int dev_id, rev_no;
+	u_int ext_family, ext_model, family_code, model, stepping;
+	int i;
+
+	if (nb_quirks != NULL) {
+		nb = pci_find_bsf(0, 0, 0);
+		if (nb != NULL) {
+			dev_id = pci_get_device(nb);
+			rev_no = pci_get_revid(nb);
+			for (i = 0; i < nb_quirks_len; i++) {
+				nb_quirk = &nb_quirks[i];
+				if (nb_quirk->dev_id == dev_id &&
+				    nb_quirk->rev_no == rev_no) {
+					if (bootverbose) {
+						device_printf(dmar->dev,
+						    "NB IOMMU quirk %s\n",
+						    nb_quirk->descr);
+					}
+					nb_quirk->quirk(dmar);
+				}
+			}
+		} else {
+			device_printf(dmar->dev, "cannot find northbridge\n");
+		}
+	}
+	if (cpu_quirks != NULL) {
+		do_cpuid(1, p);
+		ext_family = (p[0] & CPUID_EXT_FAMILY) >> 20;
+		ext_model = (p[0] & CPUID_EXT_MODEL) >> 16;
+		family_code = (p[0] & CPUID_FAMILY) >> 8;
+		model = (p[0] & CPUID_MODEL) >> 4;
+		stepping = p[0] & CPUID_STEPPING;
+		for (i = 0; i < cpu_quirks_len; i++) {
+			cpu_quirk = &cpu_quirks[i];
+			if (cpu_quirk->ext_family == ext_family &&
+			    cpu_quirk->ext_model == ext_model &&
+			    cpu_quirk->family_code == family_code &&
+			    cpu_quirk->model == model &&
+			    (cpu_quirk->stepping == -1 ||
+			    cpu_quirk->stepping == stepping)) {
+				if (bootverbose) {
+					device_printf(dmar->dev,
+					    "CPU IOMMU quirk %s\n",
+					    cpu_quirk->descr);
+				}
+				cpu_quirk->quirk(dmar);
+			}
+		}
+	}
+}
+
+static void
+nb_5400_no_low_high_prot_mem(struct dmar_unit *unit)
+{
+
+	unit->hw_cap &= ~(DMAR_CAP_PHMR | DMAR_CAP_PLMR);
+}
+
+static const struct intel_dmar_quirk_nb pre_use_nb[] = {
+	{
+	    .dev_id = 0x4001, .rev_no = 0x20,
+	    .quirk = nb_5400_no_low_high_prot_mem,
+	    .descr = "5400 E23" /* no low/high protected memory */
+	},
+	{
+	    .dev_id = 0x4003, .rev_no = 0x20,
+	    .quirk = nb_5400_no_low_high_prot_mem,
+	    .descr = "5400 E23" /* no low/high protected memory */
+	},
+};
+
+static void
+cpu_e5_am9(struct dmar_unit *unit)
+{
+
+	unit->hw_cap &= ~(0x3fULL << 48);
+	unit->hw_cap |= (9ULL << 48);
+}
+
+static const struct intel_dmar_quirk_cpu post_ident_cpu[] = {
+	{
+	    .ext_family = 0, .ext_model = 2, .family_code = 6, .model = 13,
+	    .stepping = 6, .quirk = cpu_e5_am9,
+	    .descr = "E5 BT176" /* AM should be at most 9 */
+	},
+};
+
+void
+dmar_quirks_pre_use(struct dmar_unit *dmar)
+{
+
+	if (!dmar_barrier_enter(dmar, DMAR_BARRIER_USEQ))
+		return;
+	DMAR_LOCK(dmar);
+	dmar_match_quirks(dmar, pre_use_nb, nitems(pre_use_nb),
+	    NULL, 0);
+	dmar_barrier_exit(dmar, DMAR_BARRIER_USEQ);
+}
+
+void
+dmar_quirks_post_ident(struct dmar_unit *dmar)
+{
+
+	dmar_match_quirks(dmar, NULL, 0, post_ident_cpu,
+	    nitems(post_ident_cpu));
+}


Property changes on: trunk/sys/x86/iommu/intel_quirks.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_reg.h
===================================================================
--- trunk/sys/x86/iommu/intel_reg.h	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_reg.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,412 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013-2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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: stable/10/sys/x86/iommu/intel_reg.h 306466 2016-09-30 00:31:17Z jhb $
+ */
+
+#ifndef __X86_IOMMU_INTEL_REG_H
+#define	__X86_IOMMU_INTEL_REG_H
+
+#define	DMAR_PAGE_SIZE	PAGE_SIZE
+#define	DMAR_PAGE_MASK	(DMAR_PAGE_SIZE - 1)
+#define	DMAR_PAGE_SHIFT	PAGE_SHIFT
+#define	DMAR_NPTEPG	(DMAR_PAGE_SIZE / sizeof(dmar_pte_t))
+#define	DMAR_NPTEPGSHIFT 9
+#define	DMAR_PTEMASK	(DMAR_NPTEPG - 1)
+
+typedef struct dmar_root_entry {
+	uint64_t r1;
+	uint64_t r2;
+} dmar_root_entry_t;
+#define	DMAR_ROOT_R1_P		1 		   /* Present */
+#define	DMAR_ROOT_R1_CTP_MASK	0xfffffffffffff000 /* Mask for Context-Entry
+						      Table Pointer */
+
+#define	DMAR_CTX_CNT		(DMAR_PAGE_SIZE / sizeof(dmar_root_entry_t))
+
+typedef	struct dmar_ctx_entry {
+	uint64_t ctx1;
+	uint64_t ctx2;
+} dmar_ctx_entry_t;
+#define	DMAR_CTX1_P		1		/* Present */
+#define	DMAR_CTX1_FPD		2		/* Fault Processing Disable */
+						/* Translation Type: */
+#define	DMAR_CTX1_T_UNTR	0		/* only Untranslated */
+#define	DMAR_CTX1_T_TR		4		/* both Untranslated
+						   and Translated */
+#define	DMAR_CTX1_T_PASS	8		/* Pass-Through */
+#define	DMAR_CTX1_ASR_MASK	0xfffffffffffff000 /* Mask for the Address
+						   Space Root */
+#define	DMAR_CTX2_AW_2LVL	0		/* 2-level page tables */
+#define	DMAR_CTX2_AW_3LVL	1		/* 3-level page tables */
+#define	DMAR_CTX2_AW_4LVL	2		/* 4-level page tables */
+#define	DMAR_CTX2_AW_5LVL	3		/* 5-level page tables */
+#define	DMAR_CTX2_AW_6LVL	4		/* 6-level page tables */
+#define	DMAR_CTX2_DID_MASK	0xffff0
+#define	DMAR_CTX2_DID(x)	((x) << 8)	/* Domain Identifier */
+#define	DMAR_CTX2_GET_DID(ctx2)	(((ctx2) & DMAR_CTX2_DID_MASK) >> 8)
+
+typedef struct dmar_pte {
+	uint64_t pte;
+} dmar_pte_t;
+#define	DMAR_PTE_R		1		/* Read */
+#define	DMAR_PTE_W		(1 << 1)	/* Write */
+#define	DMAR_PTE_SP		(1 << 7)	/* Super Page */
+#define	DMAR_PTE_SNP		(1 << 11)	/* Snoop Behaviour */
+#define	DMAR_PTE_ADDR_MASK	0xffffffffff000	/* Address Mask */
+#define	DMAR_PTE_TM		(1ULL << 62)	/* Transient Mapping */
+
+typedef struct dmar_irte {
+	uint64_t irte1;
+	uint64_t irte2;
+} dmar_irte_t;
+/* Source Validation Type */
+#define	DMAR_IRTE2_SVT_NONE	(0ULL << (82 - 64))
+#define	DMAR_IRTE2_SVT_RID	(1ULL << (82 - 64))
+#define	DMAR_IRTE2_SVT_BUS	(2ULL << (82 - 64))
+/* Source-id Qualifier */
+#define	DMAR_IRTE2_SQ_RID	(0ULL << (80 - 64))
+#define	DMAR_IRTE2_SQ_RID_N2	(1ULL << (80 - 64))
+#define	DMAR_IRTE2_SQ_RID_N21	(2ULL << (80 - 64))
+#define	DMAR_IRTE2_SQ_RID_N210	(3ULL << (80 - 64))
+/* Source Identifier */
+#define	DMAR_IRTE2_SID_RID(x)	((uint64_t)(x))
+#define	DMAR_IRTE2_SID_BUS(start, end)	((((uint64_t)(start)) << 8) | (end))
+/* Destination Id */
+#define	DMAR_IRTE1_DST_xAPIC(x)	(((uint64_t)(x)) << 40)
+#define	DMAR_IRTE1_DST_x2APIC(x) (((uint64_t)(x)) << 32)
+/* Vector */
+#define	DMAR_IRTE1_V(x)		(((uint64_t)x) << 16)
+#define	DMAR_IRTE1_IM_POSTED	(1ULL << 15)	/* Posted */
+/* Delivery Mode */
+#define	DMAR_IRTE1_DLM_FM	(0ULL << 5)
+#define	DMAR_IRTE1_DLM_LP	(1ULL << 5)
+#define	DMAR_IRTE1_DLM_SMI	(2ULL << 5)
+#define	DMAR_IRTE1_DLM_NMI	(4ULL << 5)
+#define	DMAR_IRTE1_DLM_INIT	(5ULL << 5)
+#define	DMAR_IRTE1_DLM_ExtINT	(7ULL << 5)
+/* Trigger Mode */
+#define	DMAR_IRTE1_TM_EDGE	(0ULL << 4)
+#define	DMAR_IRTE1_TM_LEVEL	(1ULL << 4)
+/* Redirection Hint */
+#define	DMAR_IRTE1_RH_DIRECT	(0ULL << 3)
+#define	DMAR_IRTE1_RH_SELECT	(1ULL << 3)
+/* Destination Mode */
+#define	DMAR_IRTE1_DM_PHYSICAL	(0ULL << 2)
+#define	DMAR_IRTE1_DM_LOGICAL	(1ULL << 2)
+#define	DMAR_IRTE1_FPD		(1ULL << 1)	/* Fault Processing Disable */
+#define	DMAR_IRTE1_P		(1ULL)		/* Present */
+
+/* Version register */
+#define	DMAR_VER_REG	0
+#define	DMAR_MAJOR_VER(x)	(((x) >> 4) & 0xf)
+#define	DMAR_MINOR_VER(x)	((x) & 0xf)
+
+/* Capabilities register */
+#define	DMAR_CAP_REG	0x8
+#define	DMAR_CAP_PI	(1ULL << 59)	/* Posted Interrupts */
+#define	DMAR_CAP_FL1GP	(1ULL << 56)	/* First Level 1GByte Page */
+#define	DMAR_CAP_DRD	(1ULL << 55)	/* DMA Read Draining */
+#define	DMAR_CAP_DWD	(1ULL << 54)	/* DMA Write Draining */
+#define	DMAR_CAP_MAMV(x) ((u_int)(((x) >> 48) & 0x3f))
+					/* Maximum Address Mask */
+#define	DMAR_CAP_NFR(x)	((u_int)(((x) >> 40) & 0xff) + 1)
+					/* Num of Fault-recording regs */
+#define	DMAR_CAP_PSI	(1ULL << 39)	/* Page Selective Invalidation */
+#define	DMAR_CAP_SPS(x)	((u_int)(((x) >> 34) & 0xf)) /* Super-Page Support */
+#define	DMAR_CAP_SPS_2M	0x1
+#define	DMAR_CAP_SPS_1G	0x2
+#define	DMAR_CAP_SPS_512G 0x4
+#define	DMAR_CAP_SPS_1T	0x8
+#define	DMAR_CAP_FRO(x)	((u_int)(((x) >> 24) & 0x1ff))
+					/* Fault-recording reg offset */
+#define	DMAR_CAP_ISOCH	(1 << 23)	/* Isochrony */
+#define	DMAR_CAP_ZLR	(1 << 22)	/* Zero-length reads */
+#define	DMAR_CAP_MGAW(x) ((u_int)(((x) >> 16) & 0x3f))
+					/* Max Guest Address Width */
+#define DMAR_CAP_SAGAW(x) ((u_int)(((x) >> 8) & 0x1f))
+					/* Adjusted Guest Address Width */
+#define	DMAR_CAP_SAGAW_2LVL	0x01
+#define	DMAR_CAP_SAGAW_3LVL	0x02
+#define	DMAR_CAP_SAGAW_4LVL	0x04
+#define	DMAR_CAP_SAGAW_5LVL	0x08
+#define	DMAR_CAP_SAGAW_6LVL	0x10
+#define	DMAR_CAP_CM	(1 << 7)	/* Caching mode */
+#define	DMAR_CAP_PHMR	(1 << 6)	/* Protected High-mem Region */
+#define	DMAR_CAP_PLMR	(1 << 5)	/* Protected Low-mem Region */
+#define	DMAR_CAP_RWBF	(1 << 4)	/* Required Write-Buffer Flushing */
+#define	DMAR_CAP_AFL	(1 << 3)	/* Advanced Fault Logging */
+#define	DMAR_CAP_ND(x)	((u_int)((x) & 0x3))	/* Number of domains */
+
+/* Extended Capabilities register */
+#define	DMAR_ECAP_REG	0x10
+#define	DMAR_ECAP_PSS(x) (((x) >> 35) & 0xf) /* PASID Size Supported */
+#define	DMAR_ECAP_EAFS	(1ULL << 34)	/* Extended Accessed Flag */
+#define	DMAR_ECAP_NWFS	(1ULL << 33)	/* No Write Flag */
+#define	DMAR_ECAP_SRS	(1ULL << 31)	/* Supervisor Request */
+#define	DMAR_ECAP_ERS	(1ULL << 30)	/* Execute Request */
+#define	DMAR_ECAP_PRS	(1ULL << 29)	/* Page Request */
+#define	DMAR_ECAP_PASID	(1ULL << 28)	/* Process Address Space Id */
+#define	DMAR_ECAP_DIS	(1ULL << 27)	/* Deferred Invalidate */
+#define	DMAR_ECAP_NEST	(1ULL << 26)	/* Nested Translation */
+#define	DMAR_ECAP_MTS	(1ULL << 25)	/* Memory Type */
+#define	DMAR_ECAP_ECS	(1ULL << 24)	/* Extended Context */
+#define	DMAR_ECAP_MHMV(x) ((u_int)(((x) >> 20) & 0xf))
+					/* Maximum Handle Mask Value */
+#define	DMAR_ECAP_IRO(x)  ((u_int)(((x) >> 8) & 0x3ff))
+					/* IOTLB Register Offset */
+#define	DMAR_ECAP_SC	(1 << 7)	/* Snoop Control */
+#define	DMAR_ECAP_PT	(1 << 6)	/* Pass Through */
+#define	DMAR_ECAP_EIM	(1 << 4)	/* Extended Interrupt Mode (x2APIC) */
+#define	DMAR_ECAP_IR	(1 << 3)	/* Interrupt Remapping */
+#define	DMAR_ECAP_DI	(1 << 2)	/* Device IOTLB */
+#define	DMAR_ECAP_QI	(1 << 1)	/* Queued Invalidation */
+#define	DMAR_ECAP_C	(1 << 0)	/* Coherency */
+
+/* Global Command register */
+#define	DMAR_GCMD_REG	0x18
+#define	DMAR_GCMD_TE	(1U << 31)	/* Translation Enable */
+#define	DMAR_GCMD_SRTP	(1 << 30)	/* Set Root Table Pointer */
+#define	DMAR_GCMD_SFL	(1 << 29)	/* Set Fault Log */
+#define	DMAR_GCMD_EAFL	(1 << 28)	/* Enable Advanced Fault Logging */
+#define	DMAR_GCMD_WBF	(1 << 27)	/* Write Buffer Flush */
+#define	DMAR_GCMD_QIE	(1 << 26)	/* Queued Invalidation Enable */
+#define DMAR_GCMD_IRE	(1 << 25)	/* Interrupt Remapping Enable */
+#define	DMAR_GCMD_SIRTP	(1 << 24)	/* Set Interrupt Remap Table Pointer */
+#define	DMAR_GCMD_CFI	(1 << 23)	/* Compatibility Format Interrupt */
+
+/* Global Status register */
+#define	DMAR_GSTS_REG	0x1c
+#define	DMAR_GSTS_TES	(1U << 31)	/* Translation Enable Status */
+#define	DMAR_GSTS_RTPS	(1 << 30)	/* Root Table Pointer Status */
+#define	DMAR_GSTS_FLS	(1 << 29)	/* Fault Log Status */
+#define	DMAR_GSTS_AFLS	(1 << 28)	/* Advanced Fault Logging Status */
+#define	DMAR_GSTS_WBFS	(1 << 27)	/* Write Buffer Flush Status */
+#define	DMAR_GSTS_QIES	(1 << 26)	/* Queued Invalidation Enable Status */
+#define	DMAR_GSTS_IRES	(1 << 25)	/* Interrupt Remapping Enable Status */
+#define	DMAR_GSTS_IRTPS	(1 << 24)	/* Interrupt Remapping Table
+					   Pointer Status */
+#define	DMAR_GSTS_CFIS	(1 << 23)	/* Compatibility Format
+					   Interrupt Status */
+
+/* Root-Entry Table Address register */
+#define	DMAR_RTADDR_REG	0x20
+#define	DMAR_RTADDR_RTT	(1 << 11)	/* Root Table Type */
+#define	DMAR_RTADDR_RTA_MASK	0xfffffffffffff000
+
+/* Context Command register */
+#define	DMAR_CCMD_REG	0x28
+#define	DMAR_CCMD_ICC	(1ULL << 63)	/* Invalidate Context-Cache */
+#define	DMAR_CCMD_ICC32	(1U << 31)
+#define	DMAR_CCMD_CIRG_MASK	(0x3ULL << 61)	/* Context Invalidation
+						   Request Granularity */
+#define	DMAR_CCMD_CIRG_GLOB	(0x1ULL << 61)	/* Global */
+#define	DMAR_CCMD_CIRG_DOM	(0x2ULL << 61)	/* Domain */
+#define	DMAR_CCMD_CIRG_DEV	(0x3ULL << 61)	/* Device */
+#define	DMAR_CCMD_CAIG(x)	(((x) >> 59) & 0x3) /* Context Actual
+						    Invalidation Granularity */
+#define	DMAR_CCMD_CAIG_GLOB	0x1		/* Global */
+#define	DMAR_CCMD_CAIG_DOM	0x2		/* Domain */
+#define	DMAR_CCMD_CAIG_DEV	0x3		/* Device */
+#define	DMAR_CCMD_FM		(0x3UUL << 32)	/* Function Mask */
+#define	DMAR_CCMD_SID(x)	(((x) & 0xffff) << 16) /* Source-ID */
+#define	DMAR_CCMD_DID(x)	((x) & 0xffff)	/* Domain-ID */
+
+/* Invalidate Address register */
+#define	DMAR_IVA_REG_OFF	0
+#define	DMAR_IVA_IH		(1 << 6)	/* Invalidation Hint */
+#define	DMAR_IVA_AM(x)		((x) & 0x1f)	/* Address Mask */
+#define	DMAR_IVA_ADDR(x)	((x) & ~0xfffULL) /* Address */
+
+/* IOTLB Invalidate register */
+#define	DMAR_IOTLB_REG_OFF	0x8
+#define	DMAR_IOTLB_IVT		(1ULL << 63)	/* Invalidate IOTLB */
+#define	DMAR_IOTLB_IVT32	(1U << 31)
+#define	DMAR_IOTLB_IIRG_MASK	(0x3ULL << 60)	/* Invalidation Request
+						   Granularity */
+#define	DMAR_IOTLB_IIRG_GLB	(0x1ULL << 60)	/* Global */
+#define	DMAR_IOTLB_IIRG_DOM	(0x2ULL << 60)	/* Domain-selective */
+#define	DMAR_IOTLB_IIRG_PAGE	(0x3ULL << 60)	/* Page-selective */
+#define	DMAR_IOTLB_IAIG_MASK	(0x3ULL << 57)	/* Actual Invalidation
+						   Granularity */
+#define	DMAR_IOTLB_IAIG_INVLD	0		/* Hw detected error */
+#define	DMAR_IOTLB_IAIG_GLB	(0x1ULL << 57)	/* Global */
+#define	DMAR_IOTLB_IAIG_DOM	(0x2ULL << 57)	/* Domain-selective */
+#define	DMAR_IOTLB_IAIG_PAGE	(0x3ULL << 57)	/* Page-selective */
+#define	DMAR_IOTLB_DR		(0x1ULL << 49)	/* Drain Reads */
+#define	DMAR_IOTLB_DW		(0x1ULL << 48)	/* Drain Writes */
+#define	DMAR_IOTLB_DID(x)	(((uint64_t)(x) & 0xffff) << 32) /* Domain Id */
+
+/* Fault Status register */
+#define	DMAR_FSTS_REG		0x34
+#define	DMAR_FSTS_FRI(x)	(((x) >> 8) & 0xff) /* Fault Record Index */
+#define	DMAR_FSTS_ITE		(1 << 6)	/* Invalidation Time-out */
+#define	DMAR_FSTS_ICE		(1 << 5)	/* Invalidation Completion */
+#define	DMAR_FSTS_IQE		(1 << 4)	/* Invalidation Queue */
+#define	DMAR_FSTS_APF		(1 << 3)	/* Advanced Pending Fault */
+#define	DMAR_FSTS_AFO		(1 << 2)	/* Advanced Fault Overflow */
+#define	DMAR_FSTS_PPF		(1 << 1)	/* Primary Pending Fault */
+#define	DMAR_FSTS_PFO		1		/* Fault Overflow */
+
+/* Fault Event Control register */
+#define	DMAR_FECTL_REG		0x38
+#define	DMAR_FECTL_IM		(1U << 31)	/* Interrupt Mask */
+#define	DMAR_FECTL_IP		(1 << 30)	/* Interrupt Pending */
+
+/* Fault Event Data register */
+#define	DMAR_FEDATA_REG		0x3c
+
+/* Fault Event Address register */
+#define	DMAR_FEADDR_REG		0x40
+
+/* Fault Event Upper Address register */
+#define	DMAR_FEUADDR_REG	0x44
+
+/* Advanced Fault Log register */
+#define	DMAR_AFLOG_REG		0x58
+
+/* Fault Recording Register, also usable for Advanced Fault Log records */
+#define	DMAR_FRCD2_F		(1ULL << 63)	/* Fault */
+#define	DMAR_FRCD2_F32		(1U << 31)
+#define	DMAR_FRCD2_T(x)		((int)((x >> 62) & 1))	/* Type */
+#define	DMAR_FRCD2_T_W		0		/* Write request */
+#define	DMAR_FRCD2_T_R		1		/* Read or AtomicOp */
+#define	DMAR_FRCD2_AT(x)	((int)((x >> 60) & 0x3)) /* Address Type */
+#define	DMAR_FRCD2_FR(x)	((int)((x >> 32) & 0xff)) /* Fault Reason */
+#define	DMAR_FRCD2_SID(x)	((int)(x & 0xffff))	/* Source Identifier */
+#define	DMAR_FRCS1_FI_MASK	0xffffffffff000	/* Fault Info, Address Mask */
+
+/* Protected Memory Enable register */
+#define	DMAR_PMEN_REG		0x64
+#define	DMAR_PMEN_EPM		(1U << 31)	/* Enable Protected Memory */
+#define	DMAR_PMEN_PRS		1		/* Protected Region Status */
+
+/* Protected Low-Memory Base register */
+#define	DMAR_PLMBASE_REG	0x68
+
+/* Protected Low-Memory Limit register */
+#define	DMAR_PLMLIMIT_REG	0x6c
+
+/* Protected High-Memory Base register */
+#define	DMAR_PHMBASE_REG	0x70
+
+/* Protected High-Memory Limit register */
+#define	DMAR_PHMLIMIT_REG	0x78
+
+/* Queued Invalidation Descriptors */
+#define	DMAR_IQ_DESCR_SZ_SHIFT	4	/* Shift for descriptor count
+					   to ring offset */
+#define	DMAR_IQ_DESCR_SZ	(1 << DMAR_IQ_DESCR_SZ_SHIFT)
+					/* Descriptor size */
+
+/* Context-cache Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_CTX_INV	0x1
+#define	DMAR_IQ_DESCR_CTX_GLOB	(0x1 << 4)	/* Granularity: Global */
+#define	DMAR_IQ_DESCR_CTX_DOM	(0x2 << 4)	/* Granularity: Domain */
+#define	DMAR_IQ_DESCR_CTX_DEV	(0x3 << 4)	/* Granularity: Device */
+#define	DMAR_IQ_DESCR_CTX_DID(x) (((uint32_t)(x)) << 16) /* Domain Id */
+#define	DMAR_IQ_DESCR_CTX_SRC(x) (((uint64_t)(x)) << 32) /* Source Id */
+#define	DMAR_IQ_DESCR_CTX_FM(x)  (((uint64_t)(x)) << 48) /* Function Mask */
+
+/* IOTLB Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_IOTLB_INV	0x2
+#define	DMAR_IQ_DESCR_IOTLB_GLOB (0x1 << 4)	/* Granularity: Global */
+#define	DMAR_IQ_DESCR_IOTLB_DOM	 (0x2 << 4)	/* Granularity: Domain */
+#define	DMAR_IQ_DESCR_IOTLB_PAGE (0x3 << 4)	/* Granularity: Page */
+#define	DMAR_IQ_DESCR_IOTLB_DW	(1 << 6)	/* Drain Writes */
+#define	DMAR_IQ_DESCR_IOTLB_DR	(1 << 7)	/* Drain Reads */
+#define	DMAR_IQ_DESCR_IOTLB_DID(x) (((uint32_t)(x)) << 16) /* Domain Id */
+
+/* Device-TLB Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_DTLB_INV	0x3
+
+/* Invalidate Interrupt Entry Cache */
+#define	DMAR_IQ_DESCR_IEC_INV	0x4
+#define	DMAR_IQ_DESCR_IEC_IDX	(1 << 4) /* Index-Selective Invalidation */
+#define	DMAR_IQ_DESCR_IEC_IIDX(x) (((uint64_t)x) << 32) /* Interrupt Index */
+#define	DMAR_IQ_DESCR_IEC_IM(x)	((x) << 27)	/* Index Mask */
+
+/* Invalidation Wait Descriptor */
+#define	DMAR_IQ_DESCR_WAIT_ID	0x5
+#define	DMAR_IQ_DESCR_WAIT_IF	(1 << 4)	/* Interrupt Flag */
+#define	DMAR_IQ_DESCR_WAIT_SW	(1 << 5)	/* Status Write */
+#define	DMAR_IQ_DESCR_WAIT_FN	(1 << 6)	/* Fence */
+#define	DMAR_IQ_DESCR_WAIT_SD(x) (((uint64_t)(x)) << 32) /* Status Data */
+
+/* Extended IOTLB Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_EIOTLB_INV 0x6
+
+/* PASID-Cache Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_PASIDC_INV 0x7
+
+/* Extended Device-TLB Invalidate Descriptor */
+#define	DMAR_IQ_DESCR_EDTLB_INV	0x8
+
+/* Invalidation Queue Head register */
+#define	DMAR_IQH_REG		0x80
+#define	DMAR_IQH_MASK		0x7fff0		/* Next cmd index mask */
+
+/* Invalidation Queue Tail register */
+#define	DMAR_IQT_REG		0x88
+#define	DMAR_IQT_MASK		0x7fff0
+
+/* Invalidation Queue Address register */
+#define	DMAR_IQA_REG		0x90
+#define	DMAR_IQA_IQA_MASK	0xfffffffffffff000 /* Invalidation Queue
+						      Base Address mask */
+#define	DMAR_IQA_QS_MASK	0x7		/* Queue Size in pages */
+#define	DMAR_IQA_QS_MAX		0x7		/* Max Queue size */
+#define	DMAR_IQA_QS_DEF		3
+
+ /* Invalidation Completion Status register */
+#define	DMAR_ICS_REG		0x9c
+#define	DMAR_ICS_IWC		1		/* Invalidation Wait
+						   Descriptor Complete */
+
+/* Invalidation Event Control register */
+#define	DMAR_IECTL_REG		0xa0
+#define	DMAR_IECTL_IM		(1U << 31)	/* Interrupt Mask */
+#define	DMAR_IECTL_IP		(1 << 30)	/* Interrupt Pending */
+
+/* Invalidation Event Data register */
+#define	DMAR_IEDATA_REG		0xa4
+
+/* Invalidation Event Address register */
+#define	DMAR_IEADDR_REG		0xa8
+
+/* Invalidation Event Upper Address register */
+#define	DMAR_IEUADDR_REG	0xac
+
+/* Interrupt Remapping Table Address register */
+#define	DMAR_IRTA_REG		0xb8
+#define	DMAR_IRTA_EIME		(1 << 11)	/* Extended Interrupt Mode
+						   Enable */
+#define	DMAR_IRTA_S_MASK	0xf		/* Size Mask */
+
+#endif


Property changes on: trunk/sys/x86/iommu/intel_reg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/iommu/intel_utils.c
===================================================================
--- trunk/sys/x86/iommu/intel_utils.c	                        (rev 0)
+++ trunk/sys/x86/iommu/intel_utils.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,591 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/iommu/intel_utils.c 279470 2015-03-01 04:22:06Z rstone $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/rman.h>
+#include <sys/rwlock.h>
+#include <sys/sched.h>
+#include <sys/sf_buf.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <dev/pci/pcivar.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_pageout.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <x86/include/busdma_impl.h>
+#include <x86/iommu/intel_reg.h>
+#include <x86/iommu/busdma_dmar.h>
+#include <x86/iommu/intel_dmar.h>
+
+u_int
+dmar_nd2mask(u_int nd)
+{
+	static const u_int masks[] = {
+		0x000f,	/* nd == 0 */
+		0x002f,	/* nd == 1 */
+		0x00ff,	/* nd == 2 */
+		0x02ff,	/* nd == 3 */
+		0x0fff,	/* nd == 4 */
+		0x2fff,	/* nd == 5 */
+		0xffff,	/* nd == 6 */
+		0x0000,	/* nd == 7 reserved */
+	};
+
+	KASSERT(nd <= 6, ("number of domains %d", nd));
+	return (masks[nd]);
+}
+
+static const struct sagaw_bits_tag {
+	int agaw;
+	int cap;
+	int awlvl;
+	int pglvl;
+} sagaw_bits[] = {
+	{.agaw = 30, .cap = DMAR_CAP_SAGAW_2LVL, .awlvl = DMAR_CTX2_AW_2LVL,
+	    .pglvl = 2},
+	{.agaw = 39, .cap = DMAR_CAP_SAGAW_3LVL, .awlvl = DMAR_CTX2_AW_3LVL,
+	    .pglvl = 3},
+	{.agaw = 48, .cap = DMAR_CAP_SAGAW_4LVL, .awlvl = DMAR_CTX2_AW_4LVL,
+	    .pglvl = 4},
+	{.agaw = 57, .cap = DMAR_CAP_SAGAW_5LVL, .awlvl = DMAR_CTX2_AW_5LVL,
+	    .pglvl = 5},
+	{.agaw = 64, .cap = DMAR_CAP_SAGAW_6LVL, .awlvl = DMAR_CTX2_AW_6LVL,
+	    .pglvl = 6}
+};
+#define SIZEOF_SAGAW_BITS (sizeof(sagaw_bits) / sizeof(sagaw_bits[0]))
+
+bool
+dmar_pglvl_supported(struct dmar_unit *unit, int pglvl)
+{
+	int i;
+
+	for (i = 0; i < SIZEOF_SAGAW_BITS; i++) {
+		if (sagaw_bits[i].pglvl != pglvl)
+			continue;
+		if ((DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap) != 0)
+			return (true);
+	}
+	return (false);
+}
+
+int
+ctx_set_agaw(struct dmar_ctx *ctx, int mgaw)
+{
+	int sagaw, i;
+
+	ctx->mgaw = mgaw;
+	sagaw = DMAR_CAP_SAGAW(ctx->dmar->hw_cap);
+	for (i = 0; i < SIZEOF_SAGAW_BITS; i++) {
+		if (sagaw_bits[i].agaw >= mgaw) {
+			ctx->agaw = sagaw_bits[i].agaw;
+			ctx->pglvl = sagaw_bits[i].pglvl;
+			ctx->awlvl = sagaw_bits[i].awlvl;
+			return (0);
+		}
+	}
+	device_printf(ctx->dmar->dev,
+	    "context request mgaw %d for pci%d:%d:%d:%d, "
+	    "no agaw found, sagaw %x\n", mgaw, ctx->dmar->segment, 
+	    pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner), sagaw);
+	return (EINVAL);
+}
+
+/*
+ * Find a best fit mgaw for the given maxaddr:
+ *   - if allow_less is false, must find sagaw which maps all requested
+ *     addresses (used by identity mappings);
+ *   - if allow_less is true, and no supported sagaw can map all requested
+ *     address space, accept the biggest sagaw, whatever is it.
+ */
+int
+dmar_maxaddr2mgaw(struct dmar_unit *unit, dmar_gaddr_t maxaddr, bool allow_less)
+{
+	int i;
+
+	for (i = 0; i < SIZEOF_SAGAW_BITS; i++) {
+		if ((1ULL << sagaw_bits[i].agaw) >= maxaddr &&
+		    (DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap) != 0)
+			break;
+	}
+	if (allow_less && i == SIZEOF_SAGAW_BITS) {
+		do {
+			i--;
+		} while ((DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap)
+		    == 0);
+	}
+	if (i < SIZEOF_SAGAW_BITS)
+		return (sagaw_bits[i].agaw);
+	KASSERT(0, ("no mgaw for maxaddr %jx allow_less %d",
+	    (uintmax_t) maxaddr, allow_less));
+	return (-1);
+}
+
+/*
+ * Calculate the total amount of page table pages needed to map the
+ * whole bus address space on the context with the selected agaw.
+ */
+vm_pindex_t
+pglvl_max_pages(int pglvl)
+{
+	vm_pindex_t res;
+	int i;
+
+	for (res = 0, i = pglvl; i > 0; i--) {
+		res *= DMAR_NPTEPG;
+		res++;
+	}
+	return (res);
+}
+
+/*
+ * Return true if the page table level lvl supports the superpage for
+ * the context ctx.
+ */
+int
+ctx_is_sp_lvl(struct dmar_ctx *ctx, int lvl)
+{
+	int alvl, cap_sps;
+	static const int sagaw_sp[] = {
+		DMAR_CAP_SPS_2M,
+		DMAR_CAP_SPS_1G,
+		DMAR_CAP_SPS_512G,
+		DMAR_CAP_SPS_1T
+	};
+
+	alvl = ctx->pglvl - lvl - 1;
+	cap_sps = DMAR_CAP_SPS(ctx->dmar->hw_cap);
+	return (alvl < sizeof(sagaw_sp) / sizeof(sagaw_sp[0]) &&
+	    (sagaw_sp[alvl] & cap_sps) != 0);
+}
+
+dmar_gaddr_t
+pglvl_page_size(int total_pglvl, int lvl)
+{
+	int rlvl;
+	static const dmar_gaddr_t pg_sz[] = {
+		(dmar_gaddr_t)DMAR_PAGE_SIZE,
+		(dmar_gaddr_t)DMAR_PAGE_SIZE << DMAR_NPTEPGSHIFT,
+		(dmar_gaddr_t)DMAR_PAGE_SIZE << (2 * DMAR_NPTEPGSHIFT),
+		(dmar_gaddr_t)DMAR_PAGE_SIZE << (3 * DMAR_NPTEPGSHIFT),
+		(dmar_gaddr_t)DMAR_PAGE_SIZE << (4 * DMAR_NPTEPGSHIFT),
+		(dmar_gaddr_t)DMAR_PAGE_SIZE << (5 * DMAR_NPTEPGSHIFT)
+	};
+
+	KASSERT(lvl >= 0 && lvl < total_pglvl,
+	    ("total %d lvl %d", total_pglvl, lvl));
+	rlvl = total_pglvl - lvl - 1;
+	KASSERT(rlvl < sizeof(pg_sz) / sizeof(pg_sz[0]),
+	    ("sizeof pg_sz lvl %d", lvl));
+	return (pg_sz[rlvl]);
+}
+
+dmar_gaddr_t
+ctx_page_size(struct dmar_ctx *ctx, int lvl)
+{
+
+	return (pglvl_page_size(ctx->pglvl, lvl));
+}
+
+int
+calc_am(struct dmar_unit *unit, dmar_gaddr_t base, dmar_gaddr_t size,
+    dmar_gaddr_t *isizep)
+{
+	dmar_gaddr_t isize;
+	int am;
+
+	for (am = DMAR_CAP_MAMV(unit->hw_cap);; am--) {
+		isize = 1ULL << (am + DMAR_PAGE_SHIFT);
+		if ((base & (isize - 1)) == 0 && size >= isize)
+			break;
+		if (am == 0)
+			break;
+	}
+	*isizep = isize;
+	return (am);
+}
+
+dmar_haddr_t dmar_high;
+int haw;
+int dmar_tbl_pagecnt;
+
+vm_page_t
+dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags)
+{
+	vm_page_t m;
+	int zeroed;
+
+	zeroed = (flags & DMAR_PGF_ZERO) != 0 ? VM_ALLOC_ZERO : 0;
+	for (;;) {
+		if ((flags & DMAR_PGF_OBJL) == 0)
+			VM_OBJECT_WLOCK(obj);
+		m = vm_page_lookup(obj, idx);
+		if ((flags & DMAR_PGF_NOALLOC) != 0 || m != NULL) {
+			if ((flags & DMAR_PGF_OBJL) == 0)
+				VM_OBJECT_WUNLOCK(obj);
+			break;
+		}
+		m = vm_page_alloc_contig(obj, idx, VM_ALLOC_NOBUSY |
+		    VM_ALLOC_SYSTEM | VM_ALLOC_NODUMP | zeroed, 1, 0,
+		    dmar_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+		if ((flags & DMAR_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		if (m != NULL) {
+			if (zeroed && (m->flags & PG_ZERO) == 0)
+				pmap_zero_page(m);
+			atomic_add_int(&dmar_tbl_pagecnt, 1);
+			break;
+		}
+		if ((flags & DMAR_PGF_WAITOK) == 0)
+			break;
+		if ((flags & DMAR_PGF_OBJL) != 0)
+			VM_OBJECT_WUNLOCK(obj);
+		VM_WAIT;
+		if ((flags & DMAR_PGF_OBJL) != 0)
+			VM_OBJECT_WLOCK(obj);
+	}
+	return (m);
+}
+
+void
+dmar_pgfree(vm_object_t obj, vm_pindex_t idx, int flags)
+{
+	vm_page_t m;
+
+	if ((flags & DMAR_PGF_OBJL) == 0)
+		VM_OBJECT_WLOCK(obj);
+	m = vm_page_lookup(obj, idx);
+	if (m != NULL) {
+		vm_page_free(m);
+		atomic_subtract_int(&dmar_tbl_pagecnt, 1);
+	}
+	if ((flags & DMAR_PGF_OBJL) == 0)
+		VM_OBJECT_WUNLOCK(obj);
+}
+
+void *
+dmar_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
+    struct sf_buf **sf)
+{
+	vm_page_t m;
+	bool allocated;
+
+	if ((flags & DMAR_PGF_OBJL) == 0)
+		VM_OBJECT_WLOCK(obj);
+	m = vm_page_lookup(obj, idx);
+	if (m == NULL && (flags & DMAR_PGF_ALLOC) != 0) {
+		m = dmar_pgalloc(obj, idx, flags | DMAR_PGF_OBJL);
+		allocated = true;
+	} else
+		allocated = false;
+	if (m == NULL) {
+		if ((flags & DMAR_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		return (NULL);
+	}
+	/* Sleepable allocations cannot fail. */
+	if ((flags & DMAR_PGF_WAITOK) != 0)
+		VM_OBJECT_WUNLOCK(obj);
+	sched_pin();
+	*sf = sf_buf_alloc(m, SFB_CPUPRIVATE | ((flags & DMAR_PGF_WAITOK)
+	    == 0 ? SFB_NOWAIT : 0));
+	if (*sf == NULL) {
+		sched_unpin();
+		if (allocated) {
+			VM_OBJECT_ASSERT_WLOCKED(obj);
+			dmar_pgfree(obj, m->pindex, flags | DMAR_PGF_OBJL);
+		}
+		if ((flags & DMAR_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		return (NULL);
+	}
+	if ((flags & (DMAR_PGF_WAITOK | DMAR_PGF_OBJL)) ==
+	    (DMAR_PGF_WAITOK | DMAR_PGF_OBJL))
+		VM_OBJECT_WLOCK(obj);
+	else if ((flags & (DMAR_PGF_WAITOK | DMAR_PGF_OBJL)) == 0)
+		VM_OBJECT_WUNLOCK(obj);
+	return ((void *)sf_buf_kva(*sf));
+}
+
+void
+dmar_unmap_pgtbl(struct sf_buf *sf)
+{
+
+	sf_buf_free(sf);
+	sched_unpin();
+}
+
+static void
+dmar_flush_transl_to_ram(struct dmar_unit *unit, void *dst, size_t sz)
+{
+
+	if (DMAR_IS_COHERENT(unit))
+		return;
+	/*
+	 * If DMAR does not snoop paging structures accesses, flush
+	 * CPU cache to memory.
+	 */
+	pmap_invalidate_cache_range((uintptr_t)dst, (uintptr_t)dst + sz,
+	    TRUE);
+}
+
+void
+dmar_flush_pte_to_ram(struct dmar_unit *unit, dmar_pte_t *dst)
+{
+
+	dmar_flush_transl_to_ram(unit, dst, sizeof(*dst));
+}
+
+void
+dmar_flush_ctx_to_ram(struct dmar_unit *unit, dmar_ctx_entry_t *dst)
+{
+
+	dmar_flush_transl_to_ram(unit, dst, sizeof(*dst));
+}
+
+void
+dmar_flush_root_to_ram(struct dmar_unit *unit, dmar_root_entry_t *dst)
+{
+
+	dmar_flush_transl_to_ram(unit, dst, sizeof(*dst));
+}
+
+/*
+ * Load the root entry pointer into the hardware, busily waiting for
+ * the completion.
+ */
+int
+dmar_load_root_entry_ptr(struct dmar_unit *unit)
+{
+	vm_page_t root_entry;
+
+	/*
+	 * Access to the GCMD register must be serialized while the
+	 * command is submitted.
+	 */
+	DMAR_ASSERT_LOCKED(unit);
+
+	VM_OBJECT_RLOCK(unit->ctx_obj);
+	root_entry = vm_page_lookup(unit->ctx_obj, 0);
+	VM_OBJECT_RUNLOCK(unit->ctx_obj);
+	dmar_write8(unit, DMAR_RTADDR_REG, VM_PAGE_TO_PHYS(root_entry));
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_SRTP);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_RTPS) == 0)
+		cpu_spinwait();
+	return (0);
+}
+
+/*
+ * Globally invalidate the context entries cache, busily waiting for
+ * the completion.
+ */
+int
+dmar_inv_ctx_glob(struct dmar_unit *unit)
+{
+
+	/*
+	 * Access to the CCMD register must be serialized while the
+	 * command is submitted.
+	 */
+	DMAR_ASSERT_LOCKED(unit);
+	KASSERT(!unit->qi_enabled, ("QI enabled"));
+
+	/*
+	 * The DMAR_CCMD_ICC bit in the upper dword should be written
+	 * after the low dword write is completed.  Amd64
+	 * dmar_write8() does not have this issue, i386 dmar_write8()
+	 * writes the upper dword last.
+	 */
+	dmar_write8(unit, DMAR_CCMD_REG, DMAR_CCMD_ICC | DMAR_CCMD_CIRG_GLOB);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_CCMD_REG + 4) & DMAR_CCMD_ICC32) != 0)
+		cpu_spinwait();
+	return (0);
+}
+
+/*
+ * Globally invalidate the IOTLB, busily waiting for the completion.
+ */
+int
+dmar_inv_iotlb_glob(struct dmar_unit *unit)
+{
+	int reg;
+
+	DMAR_ASSERT_LOCKED(unit);
+	KASSERT(!unit->qi_enabled, ("QI enabled"));
+
+	reg = 16 * DMAR_ECAP_IRO(unit->hw_ecap);
+	/* See a comment about DMAR_CCMD_ICC in dmar_inv_ctx_glob. */
+	dmar_write8(unit, reg + DMAR_IOTLB_REG_OFF, DMAR_IOTLB_IVT |
+	    DMAR_IOTLB_IIRG_GLB | DMAR_IOTLB_DR | DMAR_IOTLB_DW);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, reg + DMAR_IOTLB_REG_OFF + 4) &
+	    DMAR_IOTLB_IVT32) != 0)
+		cpu_spinwait();
+	return (0);
+}
+
+/*
+ * Flush the chipset write buffers.  See 11.1 "Write Buffer Flushing"
+ * in the architecture specification.
+ */
+int
+dmar_flush_write_bufs(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+
+	/*
+	 * DMAR_GCMD_WBF is only valid when CAP_RWBF is reported.
+	 */
+	KASSERT((unit->hw_cap & DMAR_CAP_RWBF) != 0,
+	    ("dmar%d: no RWBF", unit->unit));
+
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_WBF);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_WBFS) == 0)
+		cpu_spinwait();
+	return (0);
+}
+
+int
+dmar_enable_translation(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	unit->hw_gcmd |= DMAR_GCMD_TE;
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES) == 0)
+		cpu_spinwait();
+	return (0);
+}
+
+int
+dmar_disable_translation(struct dmar_unit *unit)
+{
+
+	DMAR_ASSERT_LOCKED(unit);
+	unit->hw_gcmd &= ~DMAR_GCMD_TE;
+	dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
+	/* XXXKIB should have a timeout */
+	while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES) != 0)
+		cpu_spinwait();
+	return (0);
+}
+
+#define BARRIER_F				\
+	u_int f_done, f_inproc, f_wakeup;	\
+						\
+	f_done = 1 << (barrier_id * 3);		\
+	f_inproc = 1 << (barrier_id * 3 + 1);	\
+	f_wakeup = 1 << (barrier_id * 3 + 2)
+
+bool
+dmar_barrier_enter(struct dmar_unit *dmar, u_int barrier_id)
+{
+	BARRIER_F;
+
+	DMAR_LOCK(dmar);
+	if ((dmar->barrier_flags & f_done) != 0) {
+		DMAR_UNLOCK(dmar);
+		return (false);
+	}
+
+	if ((dmar->barrier_flags & f_inproc) != 0) {
+		while ((dmar->barrier_flags & f_inproc) != 0) {
+			dmar->barrier_flags |= f_wakeup;
+			msleep(&dmar->barrier_flags, &dmar->lock, 0,
+			    "dmarb", 0);
+		}
+		KASSERT((dmar->barrier_flags & f_done) != 0,
+		    ("dmar%d barrier %d missing done", dmar->unit, barrier_id));
+		DMAR_UNLOCK(dmar);
+		return (false);
+	}
+
+	dmar->barrier_flags |= f_inproc;
+	DMAR_UNLOCK(dmar);
+	return (true);
+}
+
+void
+dmar_barrier_exit(struct dmar_unit *dmar, u_int barrier_id)
+{
+	BARRIER_F;
+
+	DMAR_ASSERT_LOCKED(dmar);
+	KASSERT((dmar->barrier_flags & (f_done | f_inproc)) == f_inproc,
+	    ("dmar%d barrier %d missed entry", dmar->unit, barrier_id));
+	dmar->barrier_flags |= f_done;
+	if ((dmar->barrier_flags & f_wakeup) != 0)
+		wakeup(&dmar->barrier_flags);
+	dmar->barrier_flags &= ~(f_inproc | f_wakeup);
+	DMAR_UNLOCK(dmar);
+}
+
+int dmar_match_verbose;
+
+static SYSCTL_NODE(_hw, OID_AUTO, dmar, CTLFLAG_RD, NULL,
+    "");
+SYSCTL_INT(_hw_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD | CTLFLAG_TUN,
+    &dmar_tbl_pagecnt, 0,
+    "Count of pages used for DMAR pagetables");
+SYSCTL_INT(_hw_dmar, OID_AUTO, match_verbose, CTLFLAG_RW | CTLFLAG_TUN,
+    &dmar_match_verbose, 0,
+    "Verbose matching of the PCI devices to DMAR paths");
+#ifdef INVARIANTS
+int dmar_check_free;
+SYSCTL_INT(_hw_dmar, OID_AUTO, check_free, CTLFLAG_RW | CTLFLAG_TUN,
+    &dmar_check_free, 0,
+    "Check the GPA RBtree for free_down and free_after validity");
+#endif
+


Property changes on: trunk/sys/x86/iommu/intel_utils.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/isa/atpic.c
===================================================================
--- trunk/sys/x86/isa/atpic.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/atpic.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -32,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/atpic.c 262192 2014-02-18 20:27:17Z jhb $");
 
 #include "opt_auto_eoi.h"
 #include "opt_isa.h"
@@ -123,7 +121,7 @@
 static void atpic_enable_intr(struct intsrc *isrc);
 static void atpic_disable_intr(struct intsrc *isrc);
 static int atpic_vector(struct intsrc *isrc);
-static void atpic_resume(struct pic *pic);
+static void atpic_resume(struct pic *pic, bool suspend_cancelled);
 static int atpic_source_pending(struct intsrc *isrc);
 static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
     enum intr_polarity pol);
@@ -276,7 +274,7 @@
 }
 
 static void
-atpic_resume(struct pic *pic)
+atpic_resume(struct pic *pic, bool suspend_cancelled)
 {
 	struct atpic *ap = (struct atpic *)pic;
 

Modified: trunk/sys/x86/isa/atrtc.c
===================================================================
--- trunk/sys/x86/isa/atrtc.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/atrtc.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2008 Poul-Henning Kamp
  * Copyright (c) 2010 Alexander Motin <mav at FreeBSD.org>
@@ -24,11 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/isa/atrtc.c 285446 2015-07-13 11:58:08Z brueffer $
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/atrtc.c 285446 2015-07-13 11:58:08Z brueffer $");
 
 #include "opt_isa.h"
 
@@ -38,6 +39,7 @@
 #include <sys/clock.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/kdb.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/proc.h>
@@ -52,8 +54,8 @@
 #include <machine/intr_machdep.h>
 #include "clock_if.h"
 
-#define	RTC_LOCK	mtx_lock_spin(&clock_lock)
-#define	RTC_UNLOCK	mtx_unlock_spin(&clock_lock)
+#define	RTC_LOCK	do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0)
+#define	RTC_UNLOCK	do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0)
 
 int	atrtcclock_disable = 0;
 
@@ -163,11 +165,10 @@
 };
 
 static int
-rtc_start(struct eventtimer *et,
-    struct bintime *first, struct bintime *period)
+rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
 {
 
-	atrtc_rate(max(fls((period->frac + (period->frac >> 1)) >> 32) - 17, 1));
+	atrtc_rate(max(fls(period + (period >> 1)) - 17, 1));
 	atrtc_enable_intr();
 	return (0);
 }
@@ -276,10 +277,8 @@
 		sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV;
 		sc->et.et_quality = 0;
 		sc->et.et_frequency = 32768;
-		sc->et.et_min_period.sec = 0;
-		sc->et.et_min_period.frac = 0x0008LLU << 48;
-		sc->et.et_max_period.sec = 0;
-		sc->et.et_max_period.frac = 0x8000LLU << 48;
+		sc->et.et_min_period = 0x00080000;
+		sc->et.et_max_period = 0x80000000;
 		sc->et.et_start = rtc_start;
 		sc->et.et_stop = rtc_stop;
 		sc->et.et_priv = dev;
@@ -328,7 +327,6 @@
 atrtc_gettime(device_t dev, struct timespec *ts)
 {
 	struct clocktime ct;
-	int s;
 
 	/* Look if we have a RTC present and the time is valid */
 	if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) {
@@ -336,13 +334,16 @@
 		return (EINVAL);
 	}
 
-	/* wait for time update to complete */
-	/* If RTCSA_TUP is zero, we have at least 244us before next update */
-	s = splhigh();
-	while (rtcin(RTC_STATUSA) & RTCSA_TUP) {
-		splx(s);
-		s = splhigh();
-	}
+	/*
+	 * wait for time update to complete
+	 * If RTCSA_TUP is zero, we have at least 244us before next update.
+	 * This is fast enough on most hardware, but a refinement would be
+	 * to make sure that no more than 240us pass after we start reading,
+	 * and try again if so.
+	 */
+	while (rtcin(RTC_STATUSA) & RTCSA_TUP)
+		continue;
+	critical_enter();
 	ct.nsec = 0;
 	ct.sec = readrtc(RTC_SEC);
 	ct.min = readrtc(RTC_MIN);
@@ -354,8 +355,9 @@
 #ifdef USE_RTC_CENTURY
 	ct.year += readrtc(RTC_CENTURY) * 100;
 #else
-	ct.year += 2000;
+	ct.year += (ct.year < 80 ? 2000 : 1900);
 #endif
+	critical_exit();
 	/* Set dow = -1 because some clocks don't set it correctly. */
 	ct.dow = -1;
 	return (clock_ct_to_ts(&ct, ts));

Modified: trunk/sys/x86/isa/clock.c
===================================================================
--- trunk/sys/x86/isa/clock.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/clock.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * Copyright (c) 2010 Alexander Motin <mav at FreeBSD.org>
@@ -34,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/clock.c 254373 2013-08-15 17:21:06Z brooks $");
 
 /*
  * Routines to handle clock hardware.
@@ -125,6 +126,8 @@
 static struct attimer_softc *attimer_sc = NULL;
 
 static int timer0_period = -2;
+static int timer0_mode = 0xffff;
+static int timer0_last = 0xffff;
 
 /* Values for timerX_state: */
 #define	RELEASED	0
@@ -404,7 +407,7 @@
 static void
 set_i8254_freq(int mode, uint32_t period)
 {
-	int new_count;
+	int new_count, new_mode;
 
 	mtx_lock_spin(&clock_lock);
 	if (mode == MODE_STOP) {
@@ -423,21 +426,36 @@
 	timer0_period = (mode == MODE_PERIODIC) ? new_count : -1;
 	switch (mode) {
 	case MODE_STOP:
-		outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT);
+		new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
+		outb(TIMER_MODE, new_mode);
 		outb(TIMER_CNTR0, 0);
 		outb(TIMER_CNTR0, 0);
 		break;
 	case MODE_PERIODIC:
-		outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+		new_mode = TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT;
+		outb(TIMER_MODE, new_mode);
 		outb(TIMER_CNTR0, new_count & 0xff);
 		outb(TIMER_CNTR0, new_count >> 8);
 		break;
 	case MODE_ONESHOT:
-		outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT);
+		if (new_count < 256 && timer0_last < 256) {
+			new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_LSB;
+			if (new_mode != timer0_mode)
+				outb(TIMER_MODE, new_mode);
+			outb(TIMER_CNTR0, new_count & 0xff);
+			break;
+		}
+		new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
+		if (new_mode != timer0_mode)
+			outb(TIMER_MODE, new_mode);
 		outb(TIMER_CNTR0, new_count & 0xff);
 		outb(TIMER_CNTR0, new_count >> 8);
 		break;
+	default:
+		panic("set_i8254_freq: unknown operational mode");
 	}
+	timer0_mode = new_mode;
+	timer0_last = new_count;
 out:
 	mtx_unlock_spin(&clock_lock);
 }
@@ -447,10 +465,12 @@
 {
 
 	timer0_period = -2;
+	timer0_mode = 0xffff;
+	timer0_last = 0xffff;
 	if (attimer_sc != NULL)
 		set_i8254_freq(attimer_sc->mode, attimer_sc->period);
 	else
-		set_i8254_freq(0, 0);
+		set_i8254_freq(MODE_STOP, 0);
 }
 
 #ifndef __amd64__
@@ -459,9 +479,10 @@
  *
  * This function is called from pmtimer_resume() to restore all the timers.
  * This should not be necessary, but there are broken laptops that do not
- * restore all the timers on resume.
- * As long as pmtimer is not part of amd64 suport, skip this for the amd64
- * case.
+ * restore all the timers on resume. The APM spec was at best vague on the
+ * subject.
+ * pmtimer is used only with the old APM power management, and not with
+ * acpi, which is required for amd64, so skip it in that case.
  */
 void
 timer_restore(void)
@@ -484,7 +505,7 @@
 	if (pc98_machine_type & M_8M)
 		i8254_freq = 1996800L; /* 1.9968 MHz */
 #endif
-	set_i8254_freq(0, 0);
+	set_i8254_freq(MODE_STOP, 0);
 }
 
 void
@@ -519,7 +540,7 @@
 			set_i8254_freq(attimer_sc->mode, attimer_sc->period);
 			attimer_sc->tc.tc_frequency = freq;
 		} else {
-			set_i8254_freq(0, 0);
+			set_i8254_freq(MODE_STOP, 0);
 		}
 	}
 	return (error);
@@ -569,18 +590,17 @@
 }
 
 static int
-attimer_start(struct eventtimer *et,
-    struct bintime *first, struct bintime *period)
+attimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
 {
 	device_t dev = (device_t)et->et_priv;
 	struct attimer_softc *sc = device_get_softc(dev);
 
-	if (period != NULL) {
+	if (period != 0) {
 		sc->mode = MODE_PERIODIC;
-		sc->period = period->frac >> 32;
+		sc->period = period;
 	} else {
 		sc->mode = MODE_ONESHOT;
-		sc->period = first->frac >> 32;
+		sc->period = first;
 	}
 	if (!sc->intr_en) {
 		i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc);
@@ -696,7 +716,7 @@
 		i8254_pending = i8254_intsrc->is_pic->pic_source_pending;
 	resource_int_value(device_get_name(dev), device_get_unit(dev),
 	    "timecounter", &i8254_timecounter);
-	set_i8254_freq(0, 0);
+	set_i8254_freq(MODE_STOP, 0);
 	if (i8254_timecounter) {
 		sc->tc.tc_get_timecount = i8254_get_timecount;
 		sc->tc.tc_counter_mask = 0xffff;
@@ -735,12 +755,8 @@
 			sc->et.et_flags |= ET_FLAGS_ONESHOT;
 		sc->et.et_quality = 100;
 		sc->et.et_frequency = i8254_freq;
-		sc->et.et_min_period.sec = 0;
-		sc->et.et_min_period.frac =
-		    ((0x0002LLU << 48) / i8254_freq) << 16;
-		sc->et.et_max_period.sec = 0xffff / i8254_freq;
-		sc->et.et_max_period.frac =
-		    ((0xfffeLLU << 48) / i8254_freq) << 16;
+		sc->et.et_min_period = (0x0002LLU << 32) / i8254_freq;
+		sc->et.et_max_period = (0xfffeLLU << 32) / i8254_freq;
 		sc->et.et_start = attimer_start;
 		sc->et.et_stop = attimer_stop;
 		sc->et.et_priv = dev;

Modified: trunk/sys/x86/isa/elcr.c
===================================================================
--- trunk/sys/x86/isa/elcr.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/elcr.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2004 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -28,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/elcr.c 262192 2014-02-18 20:27:17Z jhb $");
 
 /*
  * The ELCR is a register that controls the trigger mode and polarity of

Modified: trunk/sys/x86/isa/icu.h
===================================================================
--- trunk/sys/x86/isa/icu.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/icu.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)icu.h	5.6 (Berkeley) 5/9/91
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/isa/icu.h 233031 2012-03-16 12:13:44Z nyan $
  */
 
 /*

Modified: trunk/sys/x86/isa/isa.c
===================================================================
--- trunk/sys/x86/isa/isa.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/isa.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1998 Doug Rabson
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/isa.c 221526 2011-05-06 13:48:53Z jhb $");
 
 /*-
  * Modifications for Intel architecture by Garrett A. Wollman.

Modified: trunk/sys/x86/isa/isa.h
===================================================================
--- trunk/sys/x86/isa/isa.h	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/isa.h	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)isa.h	5.7 (Berkeley) 5/9/91
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/isa/isa.h 204309 2010-02-25 14:13:39Z attilio $
  */
 
 #ifdef PC98

Modified: trunk/sys/x86/isa/isa_dma.c
===================================================================
--- trunk/sys/x86/isa/isa_dma.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/isa_dma.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991 The Regents of the University of California.
  * All rights reserved.
@@ -33,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/isa_dma.c 233675 2012-03-29 18:58:02Z jhb $");
 
 /*
  * code to manage AT bus

Modified: trunk/sys/x86/isa/nmi.c
===================================================================
--- trunk/sys/x86/isa/nmi.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/nmi.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991 The Regents of the University of California.
  * All rights reserved.
@@ -33,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/nmi.c 204309 2010-02-25 14:13:39Z attilio $");
 
 #include "opt_mca.h"
 

Modified: trunk/sys/x86/isa/orm.c
===================================================================
--- trunk/sys/x86/isa/orm.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/isa/orm.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000 Nikolai Saoukh
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/isa/orm.c 204309 2010-02-25 14:13:39Z attilio $");
 
 /*
  * Driver to take care of holes in ISA I/O memory occupied

Modified: trunk/sys/x86/pci/pci_bus.c
===================================================================
--- trunk/sys/x86/pci/pci_bus.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/pci/pci_bus.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/pci/pci_bus.c 280970 2015-04-01 21:48:54Z jhb $");
 
 #include "opt_cpu.h"
 
@@ -45,7 +46,7 @@
 #ifdef CPU_ELAN
 #include <machine/md_var.h>
 #endif
-#include <machine/legacyvar.h>
+#include <x86/legacyvar.h>
 #include <machine/pci_cfgreg.h>
 #include <machine/resource.h>
 
@@ -92,7 +93,7 @@
 
 /* Pass MSI requests up to the nexus. */
 
-static int
+int
 legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount,
     int *irqs)
 {
@@ -103,7 +104,7 @@
 	    irqs));
 }
 
-static int
+int
 legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
 {
 	device_t bus;
@@ -133,7 +134,6 @@
 	    slot, func));
 	pci_ht_map_msi(hostb, *addr);
 	return (0);
-	
 }
 
 static const char *
@@ -598,11 +598,38 @@
     u_long start, u_long end, u_long count, u_int flags)
 {
 
-    start = hostb_alloc_start(type, start, end, count);
-    return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
-	count, flags));
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	if (type == PCI_RES_BUS)
+		return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+		    flags));
+#endif
+	start = hostb_alloc_start(type, start, end, count);
+	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
+	    count, flags));
 }
 
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+int
+legacy_pcib_adjust_resource(device_t dev, device_t child, int type,
+    struct resource *r, u_long start, u_long end)
+{
+
+	if (type == PCI_RES_BUS)
+		return (pci_domain_adjust_bus(0, child, r, start, end));
+	return (bus_generic_adjust_resource(dev, child, type, r, start, end));
+}
+
+int
+legacy_pcib_release_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+
+	if (type == PCI_RES_BUS)
+		return (pci_domain_release_bus(0, child, rid, r));
+	return (bus_generic_release_resource(dev, child, type, rid, r));
+}
+#endif
+
 static device_method_t legacy_pcib_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_identify,	legacy_pcib_identify),
@@ -616,8 +643,13 @@
 	DEVMETHOD(bus_read_ivar,	legacy_pcib_read_ivar),
 	DEVMETHOD(bus_write_ivar,	legacy_pcib_write_ivar),
 	DEVMETHOD(bus_alloc_resource,	legacy_pcib_alloc_resource),
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	DEVMETHOD(bus_adjust_resource,	legacy_pcib_adjust_resource),
+	DEVMETHOD(bus_release_resource,	legacy_pcib_release_resource),
+#else
 	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+#endif
 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),

Modified: trunk/sys/x86/pci/qpi.c
===================================================================
--- trunk/sys/x86/pci/qpi.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/pci/qpi.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2010 Advanced Computing Technologies LLC
+ * Copyright (c) 2010 Hudson River Trading LLC
  * Written by: John H. Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
  *
@@ -33,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/pci/qpi.c 283927 2015-06-02 19:20:39Z jhb $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -45,8 +46,9 @@
 
 #include <machine/cputypes.h>
 #include <machine/md_var.h>
-#include <machine/pci_cfgreg.h>
-#include <machine/specialreg.h>
+#include <x86/legacyvar.h>
+#include <x86/pci_cfgreg.h>
+#include <x86/specialreg.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -237,43 +239,21 @@
 	}
 }
 
-static uint32_t
-qpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
-    u_int reg, int bytes)
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static struct resource *
+qpi_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
 {
 
-	return (pci_cfgregread(bus, slot, func, reg, bytes));
+	if (type == PCI_RES_BUS)
+		return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+		    flags));
+	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
+	    count, flags));
 }
+#endif
 
-static void
-qpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
-    u_int reg, uint32_t data, int bytes)
-{
-
-	pci_cfgregwrite(bus, slot, func, reg, data, bytes);
-}
-
 static int
-qpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount,
-    int *irqs)
-{
-	device_t bus;
-
-	bus = device_get_parent(pcib);
-	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
-	    irqs));
-}
-
-static int
-qpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
-{
-	device_t bus;
-
-	bus = device_get_parent(pcib);
-	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
-}
-
-static int
 qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
     uint32_t *data)
 {
@@ -293,8 +273,14 @@
 
 	/* Bus interface */
 	DEVMETHOD(bus_read_ivar,	qpi_pcib_read_ivar),
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	DEVMETHOD(bus_alloc_resource,	qpi_pcib_alloc_resource),
+	DEVMETHOD(bus_adjust_resource,	legacy_pcib_adjust_resource),
+	DEVMETHOD(bus_release_resource,	legacy_pcib_release_resource),
+#else
 	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+#endif
 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
@@ -302,11 +288,11 @@
 
 	/* pcib interface */
 	DEVMETHOD(pcib_maxslots,	pcib_maxslots),
-	DEVMETHOD(pcib_read_config,	qpi_pcib_read_config),
-	DEVMETHOD(pcib_write_config,	qpi_pcib_write_config),
-	DEVMETHOD(pcib_alloc_msi,	qpi_pcib_alloc_msi),
+	DEVMETHOD(pcib_read_config,	legacy_pcib_read_config),
+	DEVMETHOD(pcib_write_config,	legacy_pcib_write_config),
+	DEVMETHOD(pcib_alloc_msi,	legacy_pcib_alloc_msi),
 	DEVMETHOD(pcib_release_msi,	pcib_release_msi),
-	DEVMETHOD(pcib_alloc_msix,	qpi_pcib_alloc_msix),
+	DEVMETHOD(pcib_alloc_msix,	legacy_pcib_alloc_msix),
 	DEVMETHOD(pcib_release_msix,	pcib_release_msix),
 	DEVMETHOD(pcib_map_msi,		qpi_pcib_map_msi),
 

Added: trunk/sys/x86/x86/bus_machdep.c
===================================================================
--- trunk/sys/x86/x86/bus_machdep.c	                        (rev 0)
+++ trunk/sys/x86/x86/bus_machdep.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,60 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Marcel Moolenaar
+ * 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 ``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: stable/10/sys/x86/x86/bus_machdep.c 287126 2015-08-25 14:39:40Z marcel $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <x86/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+/*
+ * Implementation of bus_space_map(), which effectively is a thin
+ * wrapper around pmap_mapdev() for memory mapped I/O space. It's
+ * implemented here and not in <x86/bus.h> to avoid pollution.
+ */
+int
+bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size,
+    int flags __unused, bus_space_handle_t *bshp)
+{
+
+	*bshp = (tag == X86_BUS_SPACE_MEM)
+	    ? (uintptr_t)pmap_mapdev(addr, size)
+	    : addr;
+	return (0);
+}
+
+void
+bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size)
+{
+
+	if (tag == X86_BUS_SPACE_MEM)
+		pmap_unmapdev(bsh, size);
+}


Property changes on: trunk/sys/x86/x86/bus_machdep.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/x86/busdma_bounce.c
===================================================================
--- trunk/sys/x86/x86/busdma_bounce.c	                        (rev 0)
+++ trunk/sys/x86/x86/busdma_bounce.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,1093 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/busdma_bounce.c 318977 2017-05-27 08:17:59Z hselasky $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
+
+#ifdef __i386__
+#define MAX_BPAGES 512
+#else
+#define MAX_BPAGES 8192
+#endif
+
+enum {
+	BUS_DMA_COULD_BOUNCE	= 0x01,
+	BUS_DMA_MIN_ALLOC_COMP	= 0x02,
+	BUS_DMA_KMEM_ALLOC	= 0x04,
+};
+
+struct bounce_zone;
+
+struct bus_dma_tag {
+	struct bus_dma_tag_common common;
+	int			map_count;
+	int			bounce_flags;
+	bus_dma_segment_t	*segments;
+	struct bounce_zone	*bounce_zone;
+};
+
+struct bounce_page {
+	vm_offset_t	vaddr;		/* kva of bounce buffer */
+	bus_addr_t	busaddr;	/* Physical address */
+	vm_offset_t	datavaddr;	/* kva of client data */
+	bus_addr_t	dataaddr;	/* client physical address */
+	bus_size_t	datacount;	/* client data count */
+	STAILQ_ENTRY(bounce_page) links;
+};
+
+int busdma_swi_pending;
+
+struct bounce_zone {
+	STAILQ_ENTRY(bounce_zone) links;
+	STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
+	int		total_bpages;
+	int		free_bpages;
+	int		reserved_bpages;
+	int		active_bpages;
+	int		total_bounced;
+	int		total_deferred;
+	int		map_count;
+	bus_size_t	alignment;
+	bus_addr_t	lowaddr;
+	char		zoneid[8];
+	char		lowaddrid[20];
+	struct sysctl_ctx_list sysctl_tree;
+	struct sysctl_oid *sysctl_tree_top;
+};
+
+static struct mtx bounce_lock;
+static int total_bpages;
+static int busdma_zonecount;
+static STAILQ_HEAD(, bounce_zone) bounce_zone_list;
+
+static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters");
+SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0,
+	   "Total bounce pages");
+
+struct bus_dmamap {
+	struct bp_list	       bpages;
+	int		       pagesneeded;
+	int		       pagesreserved;
+	bus_dma_tag_t	       dmat;
+	struct memdesc	       mem;
+	bus_dmamap_callback_t *callback;
+	void		      *callback_arg;
+	STAILQ_ENTRY(bus_dmamap) links;
+};
+
+static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
+static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
+static struct bus_dmamap nobounce_dmamap;
+
+static void init_bounce_pages(void *dummy);
+static int alloc_bounce_zone(bus_dma_tag_t dmat);
+static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages);
+static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+				int commit);
+static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map,
+				  vm_offset_t vaddr, bus_addr_t addr,
+				  bus_size_t size);
+static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
+int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr);
+static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+				    pmap_t pmap, void *buf, bus_size_t buflen,
+				    int flags);
+static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
+				   vm_paddr_t buf, bus_size_t buflen,
+				   int flags);
+static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+				     int flags);
+
+#ifdef XEN
+#undef pmap_kextract
+#define pmap_kextract pmap_kextract_ma
+#endif
+
+/*
+ * Allocate a device specific dma_tag.
+ */
+static int
+bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
+    bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
+    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
+    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+    void *lockfuncarg, bus_dma_tag_t *dmat)
+{
+	bus_dma_tag_t newtag;
+	int error;
+
+	*dmat = NULL;
+	error = common_bus_dma_tag_create(parent != NULL ? &parent->common :
+	    NULL, alignment, boundary, lowaddr, highaddr, filter, filterarg,
+	    maxsize, nsegments, maxsegsz, flags, lockfunc, lockfuncarg,
+	    sizeof (struct bus_dma_tag), (void **)&newtag);
+	if (error != 0)
+		return (error);
+
+	newtag->common.impl = &bus_dma_bounce_impl;
+	newtag->map_count = 0;
+	newtag->segments = NULL;
+
+	if (parent != NULL && ((newtag->common.filter != NULL) ||
+	    ((parent->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0)))
+		newtag->bounce_flags |= BUS_DMA_COULD_BOUNCE;
+
+	if (newtag->common.lowaddr < ptoa((vm_paddr_t)Maxmem) ||
+	    newtag->common.alignment > 1)
+		newtag->bounce_flags |= BUS_DMA_COULD_BOUNCE;
+
+	if (((newtag->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+	    (flags & BUS_DMA_ALLOCNOW) != 0) {
+		struct bounce_zone *bz;
+
+		/* Must bounce */
+		if ((error = alloc_bounce_zone(newtag)) != 0) {
+			free(newtag, M_DEVBUF);
+			return (error);
+		}
+		bz = newtag->bounce_zone;
+
+		if (ptoa(bz->total_bpages) < maxsize) {
+			int pages;
+
+			pages = atop(maxsize) - bz->total_bpages;
+
+			/* Add pages to our bounce pool */
+			if (alloc_bounce_pages(newtag, pages) < pages)
+				error = ENOMEM;
+		}
+		/* Performed initial allocation */
+		newtag->bounce_flags |= BUS_DMA_MIN_ALLOC_COMP;
+	} else
+		error = 0;
+	
+	if (error != 0)
+		free(newtag, M_DEVBUF);
+	else
+		*dmat = newtag;
+	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
+	    __func__, newtag, (newtag != NULL ? newtag->common.flags : 0),
+	    error);
+	return (error);
+}
+
+static int
+bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat)
+{
+	bus_dma_tag_t dmat_copy, parent;
+	int error;
+
+	error = 0;
+	dmat_copy = dmat;
+
+	if (dmat != NULL) {
+		if (dmat->map_count != 0) {
+			error = EBUSY;
+			goto out;
+		}
+		while (dmat != NULL) {
+			parent = (bus_dma_tag_t)dmat->common.parent;
+			atomic_subtract_int(&dmat->common.ref_count, 1);
+			if (dmat->common.ref_count == 0) {
+				if (dmat->segments != NULL)
+					free(dmat->segments, M_DEVBUF);
+				free(dmat, M_DEVBUF);
+				/*
+				 * Last reference count, so
+				 * release our reference
+				 * count on our parent.
+				 */
+				dmat = parent;
+			} else
+				dmat = NULL;
+		}
+	}
+out:
+	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error);
+	return (error);
+}
+
+/*
+ * Allocate a handle for mapping from kva/uva/physical
+ * address space into bus device space.
+ */
+static int
+bounce_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
+{
+	struct bounce_zone *bz;
+	int error, maxpages, pages;
+
+	error = 0;
+
+	if (dmat->segments == NULL) {
+		dmat->segments = (bus_dma_segment_t *)malloc(
+		    sizeof(bus_dma_segment_t) * dmat->common.nsegments,
+		    M_DEVBUF, M_NOWAIT);
+		if (dmat->segments == NULL) {
+			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+			    __func__, dmat, ENOMEM);
+			return (ENOMEM);
+		}
+	}
+
+	/*
+	 * Bouncing might be required if the driver asks for an active
+	 * exclusion region, a data alignment that is stricter than 1, and/or
+	 * an active address boundary.
+	 */
+	if (dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) {
+		/* Must bounce */
+		if (dmat->bounce_zone == NULL) {
+			if ((error = alloc_bounce_zone(dmat)) != 0)
+				return (error);
+		}
+		bz = dmat->bounce_zone;
+
+		*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
+		    M_NOWAIT | M_ZERO);
+		if (*mapp == NULL) {
+			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+			    __func__, dmat, ENOMEM);
+			return (ENOMEM);
+		}
+
+		/* Initialize the new map */
+		STAILQ_INIT(&((*mapp)->bpages));
+
+		/*
+		 * Attempt to add pages to our pool on a per-instance
+		 * basis up to a sane limit.
+		 */
+		if (dmat->common.alignment > 1)
+			maxpages = MAX_BPAGES;
+		else
+			maxpages = MIN(MAX_BPAGES, Maxmem -
+			    atop(dmat->common.lowaddr));
+		if ((dmat->bounce_flags & BUS_DMA_MIN_ALLOC_COMP) == 0 ||
+		    (bz->map_count > 0 && bz->total_bpages < maxpages)) {
+			pages = MAX(atop(dmat->common.maxsize), 1);
+			pages = MIN(maxpages - bz->total_bpages, pages);
+			pages = MAX(pages, 1);
+			if (alloc_bounce_pages(dmat, pages) < pages)
+				error = ENOMEM;
+			if ((dmat->bounce_flags & BUS_DMA_MIN_ALLOC_COMP)
+			    == 0) {
+				if (error == 0) {
+					dmat->bounce_flags |=
+					    BUS_DMA_MIN_ALLOC_COMP;
+				}
+			} else
+				error = 0;
+		}
+		bz->map_count++;
+	} else {
+		*mapp = NULL;
+	}
+	if (error == 0)
+		dmat->map_count++;
+	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+	    __func__, dmat, dmat->common.flags, error);
+	return (error);
+}
+
+/*
+ * Destroy a handle for mapping from kva/uva/physical
+ * address space into bus device space.
+ */
+static int
+bounce_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+
+	if (map != NULL && map != &nobounce_dmamap) {
+		if (STAILQ_FIRST(&map->bpages) != NULL) {
+			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+			    __func__, dmat, EBUSY);
+			return (EBUSY);
+		}
+		if (dmat->bounce_zone)
+			dmat->bounce_zone->map_count--;
+		free(map, M_DEVBUF);
+	}
+	dmat->map_count--;
+	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
+	return (0);
+}
+
+
+/*
+ * Allocate a piece of memory that can be efficiently mapped into
+ * bus device space based on the constraints lited in the dma tag.
+ * A dmamap to for use with dmamap_load is also allocated.
+ */
+static int
+bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
+    bus_dmamap_t *mapp)
+{
+	vm_memattr_t attr;
+	int mflags;
+
+	if (flags & BUS_DMA_NOWAIT)
+		mflags = M_NOWAIT;
+	else
+		mflags = M_WAITOK;
+
+	/* If we succeed, no mapping/bouncing will be required */
+	*mapp = NULL;
+
+	if (dmat->segments == NULL) {
+		dmat->segments = (bus_dma_segment_t *)malloc(
+		    sizeof(bus_dma_segment_t) * dmat->common.nsegments,
+		    M_DEVBUF, mflags);
+		if (dmat->segments == NULL) {
+			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+			    __func__, dmat, dmat->common.flags, ENOMEM);
+			return (ENOMEM);
+		}
+	}
+	if (flags & BUS_DMA_ZERO)
+		mflags |= M_ZERO;
+	if (flags & BUS_DMA_NOCACHE)
+		attr = VM_MEMATTR_UNCACHEABLE;
+	else
+		attr = VM_MEMATTR_DEFAULT;
+
+	/*
+	 * Allocate the buffer from the malloc(9) allocator if...
+	 *  - It's small enough to fit into a single power of two sized bucket.
+	 *  - The alignment is less than or equal to the maximum size
+	 *  - The low address requirement is fulfilled.
+	 * else allocate non-contiguous pages if...
+	 *  - The page count that could get allocated doesn't exceed
+	 *    nsegments also when the maximum segment size is less
+	 *    than PAGE_SIZE.
+	 *  - The alignment constraint isn't larger than a page boundary.
+	 *  - There are no boundary-crossing constraints.
+	 * else allocate a block of contiguous pages because one or more of the
+	 * constraints is something that only the contig allocator can fulfill.
+	 *
+	 * NOTE: The (dmat->common.alignment <= dmat->maxsize) check
+	 * below is just a quick hack. The exact alignment guarantees
+	 * of malloc(9) need to be nailed down, and the code below
+	 * should be rewritten to take that into account.
+	 *
+	 * In the meantime warn the user if malloc gets it wrong.
+	 */
+	if ((dmat->common.maxsize <= PAGE_SIZE) &&
+	   (dmat->common.alignment <= dmat->common.maxsize) &&
+	    dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) &&
+	    attr == VM_MEMATTR_DEFAULT) {
+		*vaddr = malloc(dmat->common.maxsize, M_DEVBUF, mflags);
+	} else if (dmat->common.nsegments >=
+	    howmany(dmat->common.maxsize, MIN(dmat->common.maxsegsz, PAGE_SIZE)) &&
+	    dmat->common.alignment <= PAGE_SIZE &&
+	    (dmat->common.boundary % PAGE_SIZE) == 0) {
+		/* Page-based multi-segment allocations allowed */
+		*vaddr = (void *)kmem_alloc_attr(kernel_arena,
+		    dmat->common.maxsize, mflags, 0ul, dmat->common.lowaddr,
+		    attr);
+		dmat->bounce_flags |= BUS_DMA_KMEM_ALLOC;
+	} else {
+		*vaddr = (void *)kmem_alloc_contig(kernel_arena,
+		    dmat->common.maxsize, mflags, 0ul, dmat->common.lowaddr,
+		    dmat->common.alignment != 0 ? dmat->common.alignment : 1ul,
+		    dmat->common.boundary, attr);
+		dmat->bounce_flags |= BUS_DMA_KMEM_ALLOC;
+	}
+	if (*vaddr == NULL) {
+		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+		    __func__, dmat, dmat->common.flags, ENOMEM);
+		return (ENOMEM);
+	} else if (vtophys(*vaddr) & (dmat->common.alignment - 1)) {
+		printf("bus_dmamem_alloc failed to align memory properly.\n");
+	}
+	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+	    __func__, dmat, dmat->common.flags, 0);
+	return (0);
+}
+
+/*
+ * Free a piece of memory and it's allociated dmamap, that was allocated
+ * via bus_dmamem_alloc.  Make the same choice for free/contigfree.
+ */
+static void
+bounce_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
+{
+	/*
+	 * dmamem does not need to be bounced, so the map should be
+	 * NULL and the BUS_DMA_KMEM_ALLOC flag cleared if malloc()
+	 * was used and set if kmem_alloc_contig() was used.
+	 */
+	if (map != NULL)
+		panic("bus_dmamem_free: Invalid map freed\n");
+	if ((dmat->bounce_flags & BUS_DMA_KMEM_ALLOC) == 0)
+		free(vaddr, M_DEVBUF);
+	else
+		kmem_free(kernel_arena, (vm_offset_t)vaddr,
+		    dmat->common.maxsize);
+	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat,
+	    dmat->bounce_flags);
+}
+
+static void
+_bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
+    bus_size_t buflen, int flags)
+{
+	bus_addr_t curaddr;
+	bus_size_t sgsize;
+
+	if ((map != &nobounce_dmamap && map->pagesneeded == 0)) {
+		/*
+		 * Count the number of bounce pages
+		 * needed in order to complete this transfer
+		 */
+		curaddr = buf;
+		while (buflen != 0) {
+			sgsize = MIN(buflen, dmat->common.maxsegsz);
+			if (bus_dma_run_filter(&dmat->common, curaddr)) {
+				sgsize = MIN(sgsize, PAGE_SIZE);
+				map->pagesneeded++;
+			}
+			curaddr += sgsize;
+			buflen -= sgsize;
+		}
+		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
+	}
+}
+
+static void
+_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap,
+    void *buf, bus_size_t buflen, int flags)
+{
+	vm_offset_t vaddr;
+	vm_offset_t vendaddr;
+	bus_addr_t paddr;
+	bus_size_t sg_len;
+
+	if ((map != &nobounce_dmamap && map->pagesneeded == 0)) {
+		CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
+		    "alignment= %d", dmat->common.lowaddr,
+		    ptoa((vm_paddr_t)Maxmem),
+		    dmat->common.boundary, dmat->common.alignment);
+		CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d",
+		    map, &nobounce_dmamap, map->pagesneeded);
+		/*
+		 * Count the number of bounce pages
+		 * needed in order to complete this transfer
+		 */
+		vaddr = (vm_offset_t)buf;
+		vendaddr = (vm_offset_t)buf + buflen;
+
+		while (vaddr < vendaddr) {
+			sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK);
+			if (pmap == kernel_pmap)
+				paddr = pmap_kextract(vaddr);
+			else
+				paddr = pmap_extract(pmap, vaddr);
+			if (bus_dma_run_filter(&dmat->common, paddr) != 0) {
+				sg_len = roundup2(sg_len,
+				    dmat->common.alignment);
+				map->pagesneeded++;
+			}
+			vaddr += sg_len;
+		}
+		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
+	}
+}
+
+static int
+_bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int flags)
+{
+
+	/* Reserve Necessary Bounce Pages */
+	mtx_lock(&bounce_lock);
+	if (flags & BUS_DMA_NOWAIT) {
+		if (reserve_bounce_pages(dmat, map, 0) != 0) {
+			mtx_unlock(&bounce_lock);
+			return (ENOMEM);
+		}
+	} else {
+		if (reserve_bounce_pages(dmat, map, 1) != 0) {
+			/* Queue us for resources */
+			STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links);
+			mtx_unlock(&bounce_lock);
+			return (EINPROGRESS);
+		}
+	}
+	mtx_unlock(&bounce_lock);
+
+	return (0);
+}
+
+/*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->common.boundary - 1);
+	if (dmat->common.boundary > 0) {
+		baddr = (curaddr + dmat->common.boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+
+	/*
+	 * Insert chunk into a segment, coalescing with
+	 * previous segment if possible.
+	 */
+	seg = *segp;
+	if (seg == -1) {
+		seg = 0;
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	} else {
+		if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+		    (segs[seg].ds_len + sgsize) <= dmat->common.maxsegsz &&
+		    (dmat->common.boundary == 0 ||
+		     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
+			segs[seg].ds_len += sgsize;
+		else {
+			if (++seg >= dmat->common.nsegments)
+				return (0);
+			segs[seg].ds_addr = curaddr;
+			segs[seg].ds_len = sgsize;
+		}
+	}
+	*segp = seg;
+	return (sgsize);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+static int
+bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
+    vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	bus_size_t sgsize;
+	bus_addr_t curaddr;
+	int error;
+
+	if (map == NULL)
+		map = &nobounce_dmamap;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	if ((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) {
+		_bus_dmamap_count_phys(dmat, map, buf, buflen, flags);
+		if (map->pagesneeded != 0) {
+			error = _bus_dmamap_reserve_pages(dmat, map, flags);
+			if (error)
+				return (error);
+		}
+	}
+
+	while (buflen > 0) {
+		curaddr = buf;
+		sgsize = MIN(buflen, dmat->common.maxsegsz);
+		if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+		    map->pagesneeded != 0 &&
+		    bus_dma_run_filter(&dmat->common, curaddr)) {
+			sgsize = MIN(sgsize, PAGE_SIZE);
+			curaddr = add_bounce_page(dmat, map, 0, curaddr,
+			    sgsize);
+		}
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		buf += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+}
+
+/*
+ * Utility function to load a linear buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+static int
+bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
+    bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	bus_size_t sgsize, max_sgsize;
+	bus_addr_t curaddr;
+	vm_offset_t vaddr;
+	int error;
+
+	if (map == NULL)
+		map = &nobounce_dmamap;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	if ((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) {
+		_bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags);
+		if (map->pagesneeded != 0) {
+			error = _bus_dmamap_reserve_pages(dmat, map, flags);
+			if (error)
+				return (error);
+		}
+	}
+
+	vaddr = (vm_offset_t)buf;
+	while (buflen > 0) {
+		/*
+		 * Get the physical address for this segment.
+		 */
+		if (pmap == kernel_pmap)
+			curaddr = pmap_kextract(vaddr);
+		else
+			curaddr = pmap_extract(pmap, vaddr);
+
+		/*
+		 * Compute the segment size, and adjust counts.
+		 */
+		max_sgsize = MIN(buflen, dmat->common.maxsegsz);
+		sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK);
+		if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+		    map->pagesneeded != 0 &&
+		    bus_dma_run_filter(&dmat->common, curaddr)) {
+			sgsize = roundup2(sgsize, dmat->common.alignment);
+			sgsize = MIN(sgsize, max_sgsize);
+			curaddr = add_bounce_page(dmat, map, vaddr, curaddr,
+			    sgsize);
+		} else {
+			sgsize = MIN(sgsize, max_sgsize);
+		}
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		vaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+}
+
+static void
+bounce_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
+    struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
+{
+
+	if (map == NULL)
+		return;
+	map->mem = *mem;
+	map->dmat = dmat;
+	map->callback = callback;
+	map->callback_arg = callback_arg;
+}
+
+static bus_dma_segment_t *
+bounce_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
+    bus_dma_segment_t *segs, int nsegs, int error)
+{
+
+	if (segs == NULL)
+		segs = dmat->segments;
+	return (segs);
+}
+
+/*
+ * Release the mapping held by map.
+ */
+static void
+bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	struct bounce_page *bpage;
+
+	if (map == NULL)
+		return;
+
+	while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
+		STAILQ_REMOVE_HEAD(&map->bpages, links);
+		free_bounce_page(dmat, bpage);
+	}
+}
+
+static void
+bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map,
+    bus_dmasync_op_t op)
+{
+	struct bounce_page *bpage;
+
+	if (map == NULL || (bpage = STAILQ_FIRST(&map->bpages)) == NULL)
+		return;
+
+	/*
+	 * Handle data bouncing.  We might also want to add support for
+	 * invalidating the caches on broken hardware.
+	 */
+	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
+	    "performing bounce", __func__, dmat, dmat->common.flags, op);
+
+	if ((op & BUS_DMASYNC_PREWRITE) != 0) {
+		while (bpage != NULL) {
+			if (bpage->datavaddr != 0) {
+				bcopy((void *)bpage->datavaddr,
+				    (void *)bpage->vaddr, bpage->datacount);
+			} else {
+				physcopyout(bpage->dataaddr,
+				    (void *)bpage->vaddr, bpage->datacount);
+			}
+			bpage = STAILQ_NEXT(bpage, links);
+		}
+		dmat->bounce_zone->total_bounced++;
+	}
+
+	if ((op & BUS_DMASYNC_POSTREAD) != 0) {
+		while (bpage != NULL) {
+			if (bpage->datavaddr != 0) {
+				bcopy((void *)bpage->vaddr,
+				    (void *)bpage->datavaddr,
+				    bpage->datacount);
+			} else {
+				physcopyin((void *)bpage->vaddr,
+				    bpage->dataaddr, bpage->datacount);
+			}
+			bpage = STAILQ_NEXT(bpage, links);
+		}
+		dmat->bounce_zone->total_bounced++;
+	}
+}
+
+static void
+init_bounce_pages(void *dummy __unused)
+{
+
+	total_bpages = 0;
+	STAILQ_INIT(&bounce_zone_list);
+	STAILQ_INIT(&bounce_map_waitinglist);
+	STAILQ_INIT(&bounce_map_callbacklist);
+	mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF);
+}
+SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL);
+
+static struct sysctl_ctx_list *
+busdma_sysctl_tree(struct bounce_zone *bz)
+{
+
+	return (&bz->sysctl_tree);
+}
+
+static struct sysctl_oid *
+busdma_sysctl_tree_top(struct bounce_zone *bz)
+{
+
+	return (bz->sysctl_tree_top);
+}
+
+static int
+alloc_bounce_zone(bus_dma_tag_t dmat)
+{
+	struct bounce_zone *bz;
+
+	/* Check to see if we already have a suitable zone */
+	STAILQ_FOREACH(bz, &bounce_zone_list, links) {
+		if ((dmat->common.alignment <= bz->alignment) &&
+		    (dmat->common.lowaddr >= bz->lowaddr)) {
+			dmat->bounce_zone = bz;
+			return (0);
+		}
+	}
+
+	if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF,
+	    M_NOWAIT | M_ZERO)) == NULL)
+		return (ENOMEM);
+
+	STAILQ_INIT(&bz->bounce_page_list);
+	bz->free_bpages = 0;
+	bz->reserved_bpages = 0;
+	bz->active_bpages = 0;
+	bz->lowaddr = dmat->common.lowaddr;
+	bz->alignment = MAX(dmat->common.alignment, PAGE_SIZE);
+	bz->map_count = 0;
+	snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount);
+	busdma_zonecount++;
+	snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr);
+	STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links);
+	dmat->bounce_zone = bz;
+
+	sysctl_ctx_init(&bz->sysctl_tree);
+	bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree,
+	    SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid,
+	    CTLFLAG_RD, 0, "");
+	if (bz->sysctl_tree_top == NULL) {
+		sysctl_ctx_free(&bz->sysctl_tree);
+		return (0);	/* XXX error code? */
+	}
+
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0,
+	    "Total bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0,
+	    "Free bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0,
+	    "Reserved bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0,
+	    "Active bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0,
+	    "Total bounce requests");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0,
+	    "Total bounce requests that were deferred");
+	SYSCTL_ADD_STRING(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, "");
+	SYSCTL_ADD_UAUTO(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "alignment", CTLFLAG_RD, &bz->alignment, "");
+
+	return (0);
+}
+
+static int
+alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages)
+{
+	struct bounce_zone *bz;
+	int count;
+
+	bz = dmat->bounce_zone;
+	count = 0;
+	while (numpages > 0) {
+		struct bounce_page *bpage;
+
+		bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF,
+						     M_NOWAIT | M_ZERO);
+
+		if (bpage == NULL)
+			break;
+		bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF,
+							 M_NOWAIT, 0ul,
+							 bz->lowaddr,
+							 PAGE_SIZE,
+							 0);
+		if (bpage->vaddr == 0) {
+			free(bpage, M_DEVBUF);
+			break;
+		}
+		bpage->busaddr = pmap_kextract(bpage->vaddr);
+		mtx_lock(&bounce_lock);
+		STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links);
+		total_bpages++;
+		bz->total_bpages++;
+		bz->free_bpages++;
+		mtx_unlock(&bounce_lock);
+		count++;
+		numpages--;
+	}
+	return (count);
+}
+
+static int
+reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit)
+{
+	struct bounce_zone *bz;
+	int pages;
+
+	mtx_assert(&bounce_lock, MA_OWNED);
+	bz = dmat->bounce_zone;
+	pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved);
+	if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages))
+		return (map->pagesneeded - (map->pagesreserved + pages));
+	bz->free_bpages -= pages;
+	bz->reserved_bpages += pages;
+	map->pagesreserved += pages;
+	pages = map->pagesneeded - map->pagesreserved;
+
+	return (pages);
+}
+
+static bus_addr_t
+add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
+		bus_addr_t addr, bus_size_t size)
+{
+	struct bounce_zone *bz;
+	struct bounce_page *bpage;
+
+	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
+	KASSERT(map != NULL && map != &nobounce_dmamap,
+	    ("add_bounce_page: bad map %p", map));
+
+	bz = dmat->bounce_zone;
+	if (map->pagesneeded == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesneeded--;
+
+	if (map->pagesreserved == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesreserved--;
+
+	mtx_lock(&bounce_lock);
+	bpage = STAILQ_FIRST(&bz->bounce_page_list);
+	if (bpage == NULL)
+		panic("add_bounce_page: free page list is empty");
+
+	STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links);
+	bz->reserved_bpages--;
+	bz->active_bpages++;
+	mtx_unlock(&bounce_lock);
+
+	if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) {
+		/* Page offset needs to be preserved. */
+		bpage->vaddr |= addr & PAGE_MASK;
+		bpage->busaddr |= addr & PAGE_MASK;
+	}
+	bpage->datavaddr = vaddr;
+	bpage->dataaddr = addr;
+	bpage->datacount = size;
+	STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
+	return (bpage->busaddr);
+}
+
+static void
+free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
+{
+	struct bus_dmamap *map;
+	struct bounce_zone *bz;
+
+	bz = dmat->bounce_zone;
+	bpage->datavaddr = 0;
+	bpage->datacount = 0;
+	if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) {
+		/*
+		 * Reset the bounce page to start at offset 0.  Other uses
+		 * of this bounce page may need to store a full page of
+		 * data and/or assume it starts on a page boundary.
+		 */
+		bpage->vaddr &= ~PAGE_MASK;
+		bpage->busaddr &= ~PAGE_MASK;
+	}
+
+	mtx_lock(&bounce_lock);
+	STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);
+	bz->free_bpages++;
+	bz->active_bpages--;
+	if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) {
+		if (reserve_bounce_pages(map->dmat, map, 1) == 0) {
+			STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links);
+			STAILQ_INSERT_TAIL(&bounce_map_callbacklist,
+			    map, links);
+			busdma_swi_pending = 1;
+			bz->total_deferred++;
+			swi_sched(vm_ih, 0);
+		}
+	}
+	mtx_unlock(&bounce_lock);
+}
+
+void
+busdma_swi(void)
+{
+	bus_dma_tag_t dmat;
+	struct bus_dmamap *map;
+
+	mtx_lock(&bounce_lock);
+	while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
+		STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
+		mtx_unlock(&bounce_lock);
+		dmat = map->dmat;
+		(dmat->common.lockfunc)(dmat->common.lockfuncarg, BUS_DMA_LOCK);
+		bus_dmamap_load_mem(map->dmat, map, &map->mem,
+		    map->callback, map->callback_arg, BUS_DMA_WAITOK);
+		(dmat->common.lockfunc)(dmat->common.lockfuncarg,
+		    BUS_DMA_UNLOCK);
+		mtx_lock(&bounce_lock);
+	}
+	mtx_unlock(&bounce_lock);
+}
+
+struct bus_dma_impl bus_dma_bounce_impl = {
+	.tag_create = bounce_bus_dma_tag_create,
+	.tag_destroy = bounce_bus_dma_tag_destroy,
+	.map_create = bounce_bus_dmamap_create,
+	.map_destroy = bounce_bus_dmamap_destroy,
+	.mem_alloc = bounce_bus_dmamem_alloc,
+	.mem_free = bounce_bus_dmamem_free,
+	.load_phys = bounce_bus_dmamap_load_phys,
+	.load_buffer = bounce_bus_dmamap_load_buffer,
+	.load_ma = bus_dmamap_load_ma_triv,
+	.map_waitok = bounce_bus_dmamap_waitok,
+	.map_complete = bounce_bus_dmamap_complete,
+	.map_unload = bounce_bus_dmamap_unload,
+	.map_sync = bounce_bus_dmamap_sync
+};


Property changes on: trunk/sys/x86/x86/busdma_bounce.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/x86/busdma_machdep.c
===================================================================
--- trunk/sys/x86/x86/busdma_machdep.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/busdma_machdep.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,7 +1,12 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * Copyright (c) 2013 The FreeBSD Foundation
  * All rights reserved.
  *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -25,161 +30,25 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/busdma_machdep.c 259511 2013-12-17 13:39:50Z kib $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/bus.h>
-#include <sys/interrupt.h>
 #include <sys/kernel.h>
 #include <sys/ktr.h>
 #include <sys/lock.h>
-#include <sys/proc.h>
+#include <sys/memdesc.h>
 #include <sys/mutex.h>
-#include <sys/mbuf.h>
 #include <sys/uio.h>
-#include <sys/sysctl.h>
-
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
-#include <vm/vm_kern.h>
-#include <vm/vm_page.h>
-#include <vm/vm_map.h>
-
-#include <machine/atomic.h>
+#include <vm/pmap.h>
 #include <machine/bus.h>
-#include <machine/md_var.h>
-#include <machine/specialreg.h>
+#include <x86/include/busdma_impl.h>
 
-#ifdef __i386__
-#define MAX_BPAGES 512
-#else
-#define MAX_BPAGES 8192
-#endif
-#define BUS_DMA_COULD_BOUNCE	BUS_DMA_BUS3
-#define BUS_DMA_MIN_ALLOC_COMP	BUS_DMA_BUS4
-
-struct bounce_zone;
-
-struct bus_dma_tag {
-	bus_dma_tag_t	  parent;
-	bus_size_t	  alignment;
-	bus_size_t	  boundary;
-	bus_addr_t	  lowaddr;
-	bus_addr_t	  highaddr;
-	bus_dma_filter_t *filter;
-	void		 *filterarg;
-	bus_size_t	  maxsize;
-	u_int		  nsegments;
-	bus_size_t	  maxsegsz;
-	int		  flags;
-	int		  ref_count;
-	int		  map_count;
-	bus_dma_lock_t	 *lockfunc;
-	void		 *lockfuncarg;
-	bus_dma_segment_t *segments;
-	struct bounce_zone *bounce_zone;
-};
-
-struct bounce_page {
-	vm_offset_t	vaddr;		/* kva of bounce buffer */
-	bus_addr_t	busaddr;	/* Physical address */
-	vm_offset_t	datavaddr;	/* kva of client data */
-	bus_size_t	datacount;	/* client data count */
-	STAILQ_ENTRY(bounce_page) links;
-};
-
-int busdma_swi_pending;
-
-struct bounce_zone {
-	STAILQ_ENTRY(bounce_zone) links;
-	STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
-	int		total_bpages;
-	int		free_bpages;
-	int		reserved_bpages;
-	int		active_bpages;
-	int		total_bounced;
-	int		total_deferred;
-	int		map_count;
-	bus_size_t	alignment;
-	bus_addr_t	lowaddr;
-	char		zoneid[8];
-	char		lowaddrid[20];
-	struct sysctl_ctx_list sysctl_tree;
-	struct sysctl_oid *sysctl_tree_top;
-};
-
-static struct mtx bounce_lock;
-static int total_bpages;
-static int busdma_zonecount;
-static STAILQ_HEAD(, bounce_zone) bounce_zone_list;
-
-static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters");
-SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0,
-	   "Total bounce pages");
-
-struct bus_dmamap {
-	struct bp_list	       bpages;
-	int		       pagesneeded;
-	int		       pagesreserved;
-	bus_dma_tag_t	       dmat;
-	void		      *buf;		/* unmapped buffer pointer */
-	bus_size_t	       buflen;		/* unmapped buffer length */
-	bus_dmamap_callback_t *callback;
-	void		      *callback_arg;
-	STAILQ_ENTRY(bus_dmamap) links;
-};
-
-static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
-static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
-static struct bus_dmamap nobounce_dmamap, contig_dmamap;
-
-static void init_bounce_pages(void *dummy);
-static int alloc_bounce_zone(bus_dma_tag_t dmat);
-static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages);
-static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
-				int commit);
-static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map,
-				   vm_offset_t vaddr, bus_size_t size);
-static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
-int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr);
-int _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap,
-    void *buf, bus_size_t buflen, int flags);
-
-#ifdef XEN
-#undef pmap_kextract
-#define pmap_kextract pmap_kextract_ma
-#endif
-
 /*
- * Return true if a match is made.
- *
- * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'.
- *
- * If paddr is within the bounds of the dma tag then call the filter callback
- * to check for a match, if there is no filter callback then assume a match.
- */
-int
-run_filter(bus_dma_tag_t dmat, bus_addr_t paddr)
-{
-	int retval;
-
-	retval = 0;
-
-	do {
-		if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr)
-		 || ((paddr & (dmat->alignment - 1)) != 0))
-		 && (dmat->filter == NULL
-		  || (*dmat->filter)(dmat->filterarg, paddr) != 0))
-			retval = 1;
-
-		dmat = dmat->parent;		
-	} while (retval == 0 && dmat != NULL);
-	return (retval);
-}
-
-/*
  * Convenience function for manipulating driver locks from busdma (during
  * busdma_swi, for example).  Drivers that don't provide their own locks
  * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
@@ -209,47 +78,59 @@
  * with the tag are meant to never be defered.
  * XXX Should have a way to identify which driver is responsible here.
  */
-static void
-dflt_lock(void *arg, bus_dma_lock_op_t op)
+void
+bus_dma_dflt_lock(void *arg, bus_dma_lock_op_t op)
 {
+
 	panic("driver error: busdma dflt_lock called");
 }
 
 /*
- * Allocate a device specific dma_tag.
+ * Return true if a match is made.
+ *
+ * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'.
+ *
+ * If paddr is within the bounds of the dma tag then call the filter callback
+ * to check for a match, if there is no filter callback then assume a match.
  */
 int
-bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
-		   bus_size_t boundary, bus_addr_t lowaddr,
-		   bus_addr_t highaddr, bus_dma_filter_t *filter,
-		   void *filterarg, bus_size_t maxsize, int nsegments,
-		   bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
-		   void *lockfuncarg, bus_dma_tag_t *dmat)
+bus_dma_run_filter(struct bus_dma_tag_common *tc, bus_addr_t paddr)
 {
-	bus_dma_tag_t newtag;
-	int error = 0;
+	int retval;
 
-	/* Always enforce at least a 4GB (2GB for PAE) boundary. */
-#if defined(__amd64__)
-	if (boundary == 0 || boundary > ((bus_addr_t)1 << 32))
-		boundary = (bus_size_t)1 << 32;
-#elif defined(PAE)
-	if (boundary == 0 || boundary > ((bus_addr_t)1 << 31))
-		boundary = (bus_size_t)1 << 31;
-#endif
+	retval = 0;
+	do {
+		if (((paddr > tc->lowaddr && paddr <= tc->highaddr) ||
+		    ((paddr & (tc->alignment - 1)) != 0)) &&
+		    (tc->filter == NULL ||
+		    (*tc->filter)(tc->filterarg, paddr) != 0))
+			retval = 1;
+
+		tc = tc->parent;		
+	} while (retval == 0 && tc != NULL);
+	return (retval);
+}
+
+int
+common_bus_dma_tag_create(struct bus_dma_tag_common *parent,
+    bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr,
+    bus_addr_t highaddr, bus_dma_filter_t *filter, void *filterarg,
+    bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, int flags,
+    bus_dma_lock_t *lockfunc, void *lockfuncarg, size_t sz, void **dmat)
+{
+	void *newtag;
+	struct bus_dma_tag_common *common;
+
+	KASSERT(sz >= sizeof(struct bus_dma_tag_common), ("sz"));
 	/* Basic sanity checking */
 	if (boundary != 0 && boundary < maxsegsz)
 		maxsegsz = boundary;
-
-	if (maxsegsz == 0) {
+	if (maxsegsz == 0)
 		return (EINVAL);
-	}
-
 	/* Return a NULL tag on failure */
 	*dmat = NULL;
 
-	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF,
-	    M_ZERO | M_NOWAIT);
+	newtag = malloc(sz, M_DEVBUF, M_ZERO | M_NOWAIT);
 	if (newtag == NULL) {
 		CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
 		    __func__, newtag, 0, ENOMEM);
@@ -256,89 +137,77 @@
 		return (ENOMEM);
 	}
 
-	newtag->parent = parent;
-	newtag->alignment = alignment;
-	newtag->boundary = boundary;
-	newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
-	newtag->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1);
-	newtag->filter = filter;
-	newtag->filterarg = filterarg;
-	newtag->maxsize = maxsize;
-	newtag->nsegments = nsegments;
-	newtag->maxsegsz = maxsegsz;
-	newtag->flags = flags;
-	newtag->ref_count = 1; /* Count ourself */
-	newtag->map_count = 0;
+	common = newtag;
+	common->impl = &bus_dma_bounce_impl;
+	common->parent = parent;
+	common->alignment = alignment;
+	common->boundary = boundary;
+	common->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
+	common->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1);
+	common->filter = filter;
+	common->filterarg = filterarg;
+	common->maxsize = maxsize;
+	common->nsegments = nsegments;
+	common->maxsegsz = maxsegsz;
+	common->flags = flags;
+	common->ref_count = 1; /* Count ourself */
 	if (lockfunc != NULL) {
-		newtag->lockfunc = lockfunc;
-		newtag->lockfuncarg = lockfuncarg;
+		common->lockfunc = lockfunc;
+		common->lockfuncarg = lockfuncarg;
 	} else {
-		newtag->lockfunc = dflt_lock;
-		newtag->lockfuncarg = NULL;
+		common->lockfunc = bus_dma_dflt_lock;
+		common->lockfuncarg = NULL;
 	}
-	newtag->segments = NULL;
 
 	/* Take into account any restrictions imposed by our parent tag */
 	if (parent != NULL) {
-		newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr);
-		newtag->highaddr = MAX(parent->highaddr, newtag->highaddr);
-		if (newtag->boundary == 0)
-			newtag->boundary = parent->boundary;
-		else if (parent->boundary != 0)
-			newtag->boundary = MIN(parent->boundary,
-					       newtag->boundary);
-		if ((newtag->filter != NULL) ||
-		    ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0))
-			newtag->flags |= BUS_DMA_COULD_BOUNCE;
-		if (newtag->filter == NULL) {
+		common->impl = parent->impl;
+		common->lowaddr = MIN(parent->lowaddr, common->lowaddr);
+		common->highaddr = MAX(parent->highaddr, common->highaddr);
+		if (common->boundary == 0)
+			common->boundary = parent->boundary;
+		else if (parent->boundary != 0) {
+			common->boundary = MIN(parent->boundary,
+			    common->boundary);
+		}
+		if (common->filter == NULL) {
 			/*
 			 * Short circuit looking at our parent directly
 			 * since we have encapsulated all of its information
 			 */
-			newtag->filter = parent->filter;
-			newtag->filterarg = parent->filterarg;
-			newtag->parent = parent->parent;
+			common->filter = parent->filter;
+			common->filterarg = parent->filterarg;
+			common->parent = parent->parent;
 		}
-		if (newtag->parent != NULL)
-			atomic_add_int(&parent->ref_count, 1);
+		atomic_add_int(&parent->ref_count, 1);
 	}
+	*dmat = common;
+	return (0);
+}
 
-	if (newtag->lowaddr < ptoa((vm_paddr_t)Maxmem)
-	 || newtag->alignment > 1)
-		newtag->flags |= BUS_DMA_COULD_BOUNCE;
+/*
+ * Allocate a device specific dma_tag.
+ */
+int
+bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
+    bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
+    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
+    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+    void *lockfuncarg, bus_dma_tag_t *dmat)
+{
+	struct bus_dma_tag_common *tc;
+	int error;
 
-	if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
-	    (flags & BUS_DMA_ALLOCNOW) != 0) {
-		struct bounce_zone *bz;
-
-		/* Must bounce */
-
-		if ((error = alloc_bounce_zone(newtag)) != 0) {
-			free(newtag, M_DEVBUF);
-			return (error);
-		}
-		bz = newtag->bounce_zone;
-
-		if (ptoa(bz->total_bpages) < maxsize) {
-			int pages;
-
-			pages = atop(maxsize) - bz->total_bpages;
-
-			/* Add pages to our bounce pool */
-			if (alloc_bounce_pages(newtag, pages) < pages)
-				error = ENOMEM;
-		}
-		/* Performed initial allocation */
-		newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
-	}
-	
-	if (error != 0) {
-		free(newtag, M_DEVBUF);
+	if (parent == NULL) {
+		error = bus_dma_bounce_impl.tag_create(parent, alignment,
+		    boundary, lowaddr, highaddr, filter, filterarg, maxsize,
+		    nsegments, maxsegsz, flags, lockfunc, lockfuncarg, dmat);
 	} else {
-		*dmat = newtag;
+		tc = (struct bus_dma_tag_common *)parent;
+		error = tc->impl->tag_create(parent, alignment,
+		    boundary, lowaddr, highaddr, filter, filterarg, maxsize,
+		    nsegments, maxsegsz, flags, lockfunc, lockfuncarg, dmat);
 	}
-	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
-	    __func__, newtag, (newtag != NULL ? newtag->flags : 0), error);
 	return (error);
 }
 
@@ -345,41 +214,10 @@
 int
 bus_dma_tag_destroy(bus_dma_tag_t dmat)
 {
-	bus_dma_tag_t dmat_copy;
-	int error;
+	struct bus_dma_tag_common *tc;
 
-	error = 0;
-	dmat_copy = dmat;
-
-	if (dmat != NULL) {
-
-		if (dmat->map_count != 0) {
-			error = EBUSY;
-			goto out;
-		}
-
-		while (dmat != NULL) {
-			bus_dma_tag_t parent;
-
-			parent = dmat->parent;
-			atomic_subtract_int(&dmat->ref_count, 1);
-			if (dmat->ref_count == 0) {
-				if (dmat->segments != NULL)
-					free(dmat->segments, M_DEVBUF);
-				free(dmat, M_DEVBUF);
-				/*
-				 * Last reference count, so
-				 * release our reference
-				 * count on our parent.
-				 */
-				dmat = parent;
-			} else
-				dmat = NULL;
-		}
-	}
-out:
-	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error);
-	return (error);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->tag_destroy(dmat));
 }
 
 /*
@@ -389,83 +227,10 @@
 int
 bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
 {
-	int error;
+	struct bus_dma_tag_common *tc;
 
-	error = 0;
-
-	if (dmat->segments == NULL) {
-		dmat->segments = (bus_dma_segment_t *)malloc(
-		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
-		    M_NOWAIT);
-		if (dmat->segments == NULL) {
-			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
-			    __func__, dmat, ENOMEM);
-			return (ENOMEM);
-		}
-	}
-
-	/*
-	 * Bouncing might be required if the driver asks for an active
-	 * exclusion region, a data alignment that is stricter than 1, and/or
-	 * an active address boundary.
-	 */
-	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
-
-		/* Must bounce */
-		struct bounce_zone *bz;
-		int maxpages;
-
-		if (dmat->bounce_zone == NULL) {
-			if ((error = alloc_bounce_zone(dmat)) != 0)
-				return (error);
-		}
-		bz = dmat->bounce_zone;
-
-		*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
-					     M_NOWAIT | M_ZERO);
-		if (*mapp == NULL) {
-			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
-			    __func__, dmat, ENOMEM);
-			return (ENOMEM);
-		}
-
-		/* Initialize the new map */
-		STAILQ_INIT(&((*mapp)->bpages));
-
-		/*
-		 * Attempt to add pages to our pool on a per-instance
-		 * basis up to a sane limit.
-		 */
-		if (dmat->alignment > 1)
-			maxpages = MAX_BPAGES;
-		else
-			maxpages = MIN(MAX_BPAGES, Maxmem -atop(dmat->lowaddr));
-		if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
-		 || (bz->map_count > 0 && bz->total_bpages < maxpages)) {
-			int pages;
-
-			pages = MAX(atop(dmat->maxsize), 1);
-			pages = MIN(maxpages - bz->total_bpages, pages);
-			pages = MAX(pages, 1);
-			if (alloc_bounce_pages(dmat, pages) < pages)
-				error = ENOMEM;
-
-			if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) {
-				if (error == 0)
-					dmat->flags |= BUS_DMA_MIN_ALLOC_COMP;
-			} else {
-				error = 0;
-			}
-		}
-		bz->map_count++;
-	} else {
-		*mapp = NULL;
-	}
-	if (error == 0)
-		dmat->map_count++;
-	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
-	    __func__, dmat, dmat->flags, error);
-	return (error);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->map_create(dmat, flags, mapp));
 }
 
 /*
@@ -475,19 +240,10 @@
 int
 bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
 {
-	if (map != NULL && map != &nobounce_dmamap && map != &contig_dmamap) {
-		if (STAILQ_FIRST(&map->bpages) != NULL) {
-			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
-			    __func__, dmat, EBUSY);
-			return (EBUSY);
-		}
-		if (dmat->bounce_zone)
-			dmat->bounce_zone->map_count--;
-		free(map, M_DEVBUF);
-	}
-	dmat->map_count--;
-	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
-	return (0);
+	struct bus_dma_tag_common *tc;
+
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->map_destroy(dmat, map));
 }
 
 
@@ -498,72 +254,12 @@
  */
 int
 bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
-		 bus_dmamap_t *mapp)
+    bus_dmamap_t *mapp)
 {
-	vm_memattr_t attr;
-	int mflags;
+	struct bus_dma_tag_common *tc;
 
-	if (flags & BUS_DMA_NOWAIT)
-		mflags = M_NOWAIT;
-	else
-		mflags = M_WAITOK;
-
-	/* If we succeed, no mapping/bouncing will be required */
-	*mapp = NULL;
-
-	if (dmat->segments == NULL) {
-		dmat->segments = (bus_dma_segment_t *)malloc(
-		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
-		    mflags);
-		if (dmat->segments == NULL) {
-			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
-			    __func__, dmat, dmat->flags, ENOMEM);
-			return (ENOMEM);
-		}
-	}
-	if (flags & BUS_DMA_ZERO)
-		mflags |= M_ZERO;
-	if (flags & BUS_DMA_NOCACHE)
-		attr = VM_MEMATTR_UNCACHEABLE;
-	else
-		attr = VM_MEMATTR_DEFAULT;
-
-	/* 
-	 * XXX:
-	 * (dmat->alignment < dmat->maxsize) is just a quick hack; the exact
-	 * alignment guarantees of malloc need to be nailed down, and the
-	 * code below should be rewritten to take that into account.
-	 *
-	 * In the meantime, we'll warn the user if malloc gets it wrong.
-	 */
-	if ((dmat->maxsize <= PAGE_SIZE) &&
-	   (dmat->alignment < dmat->maxsize) &&
-	    dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem) &&
-	    attr == VM_MEMATTR_DEFAULT) {
-		*vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
-	} else if (dmat->nsegments >= btoc(dmat->maxsize) &&
-	    dmat->alignment <= PAGE_SIZE &&
-	    (dmat->boundary == 0 || dmat->boundary >= dmat->lowaddr)) {
-		/* Page-based multi-segment allocations allowed */
-		*vaddr = (void *)kmem_alloc_attr(kernel_map, dmat->maxsize,
-		    mflags, 0ul, dmat->lowaddr, attr);
-		*mapp = &contig_dmamap;
-	} else {
-		*vaddr = (void *)kmem_alloc_contig(kernel_map, dmat->maxsize,
-		    mflags, 0ul, dmat->lowaddr, dmat->alignment ?
-		    dmat->alignment : 1ul, dmat->boundary, attr);
-		*mapp = &contig_dmamap;
-	}
-	if (*vaddr == NULL) {
-		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
-		    __func__, dmat, dmat->flags, ENOMEM);
-		return (ENOMEM);
-	} else if (vtophys(*vaddr) & (dmat->alignment - 1)) {
-		printf("bus_dmamem_alloc failed to align memory properly.\n");
-	}
-	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
-	    __func__, dmat, dmat->flags, 0);
-	return (0);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->mem_alloc(dmat, vaddr, flags, mapp));
 }
 
 /*
@@ -573,362 +269,73 @@
 void
 bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
 {
-	/*
-	 * dmamem does not need to be bounced, so the map should be
-	 * NULL if malloc() was used and contig_dmamap if
-	 * kmem_alloc_contig() was used.
-	 */
-	if (!(map == NULL || map == &contig_dmamap))
-		panic("bus_dmamem_free: Invalid map freed\n");
-	if (map == NULL)
-		free(vaddr, M_DEVBUF);
-	else
-		kmem_free(kernel_map, (vm_offset_t)vaddr, dmat->maxsize);
-	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
-}
+	struct bus_dma_tag_common *tc;
 
-int
-_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap,
-    void *buf, bus_size_t buflen, int flags)
-{
-	vm_offset_t vaddr;
-	vm_offset_t vendaddr;
-	bus_addr_t paddr;
-
-	if ((map != &nobounce_dmamap && map->pagesneeded == 0)) {
-		CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
-		    "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem),
-		    dmat->boundary, dmat->alignment);
-		CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d",
-		    map, &nobounce_dmamap, map->pagesneeded);
-		/*
-		 * Count the number of bounce pages
-		 * needed in order to complete this transfer
-		 */
-		vaddr = (vm_offset_t)buf;
-		vendaddr = (vm_offset_t)buf + buflen;
-
-		while (vaddr < vendaddr) {
-			bus_size_t sg_len;
-
-			sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK);
-			if (pmap)
-				paddr = pmap_extract(pmap, vaddr);
-			else
-				paddr = pmap_kextract(vaddr);
-			if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
-			    run_filter(dmat, paddr) != 0) {
-				sg_len = roundup2(sg_len, dmat->alignment);
-				map->pagesneeded++;
-			}
-			vaddr += sg_len;
-		}
-		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
-	}
-
-	/* Reserve Necessary Bounce Pages */
-	if (map->pagesneeded != 0) {
-		mtx_lock(&bounce_lock);
-		if (flags & BUS_DMA_NOWAIT) {
-			if (reserve_bounce_pages(dmat, map, 0) != 0) {
-				mtx_unlock(&bounce_lock);
-				return (ENOMEM);
-			}
-		} else {
-			if (reserve_bounce_pages(dmat, map, 1) != 0) {
-				/* Queue us for resources */
-				map->dmat = dmat;
-				map->buf = buf;
-				map->buflen = buflen;
-				STAILQ_INSERT_TAIL(&bounce_map_waitinglist,
-				    map, links);
-				mtx_unlock(&bounce_lock);
-				return (EINPROGRESS);
-			}
-		}
-		mtx_unlock(&bounce_lock);
-	}
-
-	return (0);
+	tc = (struct bus_dma_tag_common *)dmat;
+	tc->impl->mem_free(dmat, vaddr, map);
 }
 
 /*
- * Utility function to load a linear buffer.  lastaddrp holds state
- * between invocations (for multiple-buffer loads).  segp contains
+ * Utility function to load a physical buffer.  segp contains
  * the starting segment on entrace, and the ending segment on exit.
- * first indicates if this is the first invocation of this function.
  */
-static __inline int
-_bus_dmamap_load_buffer(bus_dma_tag_t dmat,
-    			bus_dmamap_t map,
-			void *buf, bus_size_t buflen,
-			pmap_t pmap,
-			int flags,
-			bus_addr_t *lastaddrp,
-			bus_dma_segment_t *segs,
-			int *segp,
-			int first)
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
+    bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
 {
-	bus_size_t sgsize;
-	bus_addr_t curaddr, lastaddr, baddr, bmask;
-	vm_offset_t vaddr;
-	int seg, error;
+	struct bus_dma_tag_common *tc;
 
-	if (map == NULL || map == &contig_dmamap)
-		map = &nobounce_dmamap;
-
-	if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) {
-		error = _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags);
-		if (error)
-			return (error);
-	}
-
-	vaddr = (vm_offset_t)buf;
-	lastaddr = *lastaddrp;
-	bmask = ~(dmat->boundary - 1);
-
-	for (seg = *segp; buflen > 0 ; ) {
-		bus_size_t max_sgsize;
-
-		/*
-		 * Get the physical address for this segment.
-		 */
-		if (pmap)
-			curaddr = pmap_extract(pmap, vaddr);
-		else
-			curaddr = pmap_kextract(vaddr);
-
-		/*
-		 * Compute the segment size, and adjust counts.
-		 */
-		max_sgsize = MIN(buflen, dmat->maxsegsz);
-		sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK);
-		if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
-		    map->pagesneeded != 0 && run_filter(dmat, curaddr)) {
-			sgsize = roundup2(sgsize, dmat->alignment);
-			sgsize = MIN(sgsize, max_sgsize);
-			curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
-		} else {
-			sgsize = MIN(sgsize, max_sgsize);
-		}
-
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			if (sgsize > (baddr - curaddr))
-				sgsize = (baddr - curaddr);
-		}
-
-		/*
-		 * Insert chunk into a segment, coalescing with
-		 * previous segment if possible.
-		 */
-		if (first) {
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-			first = 0;
-		} else {
-			if (curaddr == lastaddr &&
-			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-			    (dmat->boundary == 0 ||
-			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
-				segs[seg].ds_len += sgsize;
-			else {
-				if (++seg >= dmat->nsegments)
-					break;
-				segs[seg].ds_addr = curaddr;
-				segs[seg].ds_len = sgsize;
-			}
-		}
-
-		lastaddr = curaddr + sgsize;
-		vaddr += sgsize;
-		buflen -= sgsize;
-	}
-
-	*segp = seg;
-	*lastaddrp = lastaddr;
-
-	/*
-	 * Did we fit?
-	 */
-	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->load_phys(dmat, map, buf, buflen, flags, segs,
+	    segp));
 }
 
-/*
- * Map the buffer buf into bus space using the dmamap map.
- */
 int
-bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
-		bus_size_t buflen, bus_dmamap_callback_t *callback,
-		void *callback_arg, int flags)
+_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma,
+    bus_size_t tlen, int ma_offs, int flags, bus_dma_segment_t *segs,
+    int *segp)
 {
-	bus_addr_t		lastaddr = 0;
-	int			error, nsegs = 0;
+	struct bus_dma_tag_common *tc;
 
-	if (map != NULL) {
-		flags |= BUS_DMA_WAITOK;
-		map->callback = callback;
-		map->callback_arg = callback_arg;
-	}
-
-	error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, NULL, flags,
-	     &lastaddr, dmat->segments, &nsegs, 1);
-
-	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs + 1);
-
-	if (error == EINPROGRESS) {
-		return (error);
-	}
-
-	if (error)
-		(*callback)(callback_arg, dmat->segments, 0, error);
-	else
-		(*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
-
-	/*
-	 * Return ENOMEM to the caller so that it can pass it up the stack.
-	 * This error only happens when NOWAIT is set, so deferal is disabled.
-	 */
-	if (error == ENOMEM)
-		return (error);
-
-	return (0);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->load_ma(dmat, map, ma, tlen, ma_offs, flags,
+	    segs, segp));
 }
 
-
 /*
- * Like _bus_dmamap_load(), but for mbufs.
+ * Utility function to load a linear buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
  */
-static __inline int
-_bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
-			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
-			int flags)
+int
+_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
+    bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
+    int *segp)
 {
-	int error;
+	struct bus_dma_tag_common *tc;
 
-	M_ASSERTPKTHDR(m0);
-
-	flags |= BUS_DMA_NOWAIT;
-	*nsegs = 0;
-	error = 0;
-	if (m0->m_pkthdr.len <= dmat->maxsize) {
-		int first = 1;
-		bus_addr_t lastaddr = 0;
-		struct mbuf *m;
-
-		for (m = m0; m != NULL && error == 0; m = m->m_next) {
-			if (m->m_len > 0) {
-				error = _bus_dmamap_load_buffer(dmat, map,
-						m->m_data, m->m_len,
-						NULL, flags, &lastaddr,
-						segs, nsegs, first);
-				first = 0;
-			}
-		}
-	} else {
-		error = EINVAL;
-	}
-
-	/* XXX FIXME: Having to increment nsegs is really annoying */
-	++*nsegs;
-	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, *nsegs);
-	return (error);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->load_buffer(dmat, map, buf, buflen, pmap, flags, segs,
+	    segp));
 }
 
-int
-bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
-		     struct mbuf *m0,
-		     bus_dmamap_callback2_t *callback, void *callback_arg,
-		     int flags)
+void
+__bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
+    struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
 {
-	int nsegs, error;
+	struct bus_dma_tag_common *tc;
 
-	error = _bus_dmamap_load_mbuf_sg(dmat, map, m0, dmat->segments, &nsegs,
-	    flags);
-
-	if (error) {
-		/* force "no valid mappings" in callback */
-		(*callback)(callback_arg, dmat->segments, 0, 0, error);
-	} else {
-		(*callback)(callback_arg, dmat->segments,
-			    nsegs, m0->m_pkthdr.len, error);
-	}
-	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs);
-	return (error);
+	tc = (struct bus_dma_tag_common *)dmat;
+	tc->impl->map_waitok(dmat, map, mem, callback, callback_arg);
 }
 
-int
-bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
-			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
-			int flags)
+bus_dma_segment_t *
+_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
+    bus_dma_segment_t *segs, int nsegs, int error)
 {
-	return (_bus_dmamap_load_mbuf_sg(dmat, map, m0, segs, nsegs, flags));
-}
+	struct bus_dma_tag_common *tc;
 
-/*
- * Like _bus_dmamap_load(), but for uios.
- */
-int
-bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map,
-		    struct uio *uio,
-		    bus_dmamap_callback2_t *callback, void *callback_arg,
-		    int flags)
-{
-	bus_addr_t lastaddr = 0;
-	int nsegs, error, first, i;
-	bus_size_t resid;
-	struct iovec *iov;
-	pmap_t pmap;
-
-	flags |= BUS_DMA_NOWAIT;
-	resid = uio->uio_resid;
-	iov = uio->uio_iov;
-
-	if (uio->uio_segflg == UIO_USERSPACE) {
-		KASSERT(uio->uio_td != NULL,
-			("bus_dmamap_load_uio: USERSPACE but no proc"));
-		pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
-	} else
-		pmap = NULL;
-
-	nsegs = 0;
-	error = 0;
-	first = 1;
-	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
-		/*
-		 * Now at the first iovec to load.  Load each iovec
-		 * until we have exhausted the residual count.
-		 */
-		bus_size_t minlen =
-			resid < iov[i].iov_len ? resid : iov[i].iov_len;
-		caddr_t addr = (caddr_t) iov[i].iov_base;
-
-		if (minlen > 0) {
-			error = _bus_dmamap_load_buffer(dmat, map,
-					addr, minlen, pmap, flags, &lastaddr,
-					dmat->segments, &nsegs, first);
-			first = 0;
-
-			resid -= minlen;
-		}
-	}
-
-	if (error) {
-		/* force "no valid mappings" in callback */
-		(*callback)(callback_arg, dmat->segments, 0, 0, error);
-	} else {
-		(*callback)(callback_arg, dmat->segments,
-			    nsegs+1, uio->uio_resid, error);
-	}
-	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs + 1);
-	return (error);
+	tc = (struct bus_dma_tag_common *)dmat;
+	return (tc->impl->map_complete(dmat, map, segs, nsegs, error));
 }
 
 /*
@@ -937,305 +344,17 @@
 void
 _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
 {
-	struct bounce_page *bpage;
+	struct bus_dma_tag_common *tc;
 
-	while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
-		STAILQ_REMOVE_HEAD(&map->bpages, links);
-		free_bounce_page(dmat, bpage);
-	}
+	tc = (struct bus_dma_tag_common *)dmat;
+	tc->impl->map_unload(dmat, map);
 }
 
 void
 _bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
 {
-	struct bounce_page *bpage;
+	struct bus_dma_tag_common *tc;
 
-	if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
-		/*
-		 * Handle data bouncing.  We might also
-		 * want to add support for invalidating
-		 * the caches on broken hardware
-		 */
-		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
-		    "performing bounce", __func__, op, dmat, dmat->flags);
-
-		if (op & BUS_DMASYNC_PREWRITE) {
-			while (bpage != NULL) {
-				bcopy((void *)bpage->datavaddr,
-				      (void *)bpage->vaddr,
-				      bpage->datacount);
-				bpage = STAILQ_NEXT(bpage, links);
-			}
-			dmat->bounce_zone->total_bounced++;
-		}
-
-		if (op & BUS_DMASYNC_POSTREAD) {
-			while (bpage != NULL) {
-				bcopy((void *)bpage->vaddr,
-				      (void *)bpage->datavaddr,
-				      bpage->datacount);
-				bpage = STAILQ_NEXT(bpage, links);
-			}
-			dmat->bounce_zone->total_bounced++;
-		}
-	}
+	tc = (struct bus_dma_tag_common *)dmat;
+	tc->impl->map_sync(dmat, map, op);
 }
-
-static void
-init_bounce_pages(void *dummy __unused)
-{
-
-	total_bpages = 0;
-	STAILQ_INIT(&bounce_zone_list);
-	STAILQ_INIT(&bounce_map_waitinglist);
-	STAILQ_INIT(&bounce_map_callbacklist);
-	mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF);
-}
-SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL);
-
-static struct sysctl_ctx_list *
-busdma_sysctl_tree(struct bounce_zone *bz)
-{
-	return (&bz->sysctl_tree);
-}
-
-static struct sysctl_oid *
-busdma_sysctl_tree_top(struct bounce_zone *bz)
-{
-	return (bz->sysctl_tree_top);
-}
-
-#if defined(__amd64__) || defined(PAE)
-#define	SYSCTL_ADD_BUS_SIZE_T	SYSCTL_ADD_UQUAD
-#else
-#define	SYSCTL_ADD_BUS_SIZE_T(ctx, parent, nbr, name, flag, ptr, desc)	\
-	SYSCTL_ADD_UINT(ctx, parent, nbr, name, flag, ptr, 0, desc)
-#endif
-
-static int
-alloc_bounce_zone(bus_dma_tag_t dmat)
-{
-	struct bounce_zone *bz;
-
-	/* Check to see if we already have a suitable zone */
-	STAILQ_FOREACH(bz, &bounce_zone_list, links) {
-		if ((dmat->alignment <= bz->alignment)
-		 && (dmat->lowaddr >= bz->lowaddr)) {
-			dmat->bounce_zone = bz;
-			return (0);
-		}
-	}
-
-	if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF,
-	    M_NOWAIT | M_ZERO)) == NULL)
-		return (ENOMEM);
-
-	STAILQ_INIT(&bz->bounce_page_list);
-	bz->free_bpages = 0;
-	bz->reserved_bpages = 0;
-	bz->active_bpages = 0;
-	bz->lowaddr = dmat->lowaddr;
-	bz->alignment = MAX(dmat->alignment, PAGE_SIZE);
-	bz->map_count = 0;
-	snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount);
-	busdma_zonecount++;
-	snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr);
-	STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links);
-	dmat->bounce_zone = bz;
-
-	sysctl_ctx_init(&bz->sysctl_tree);
-	bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree,
-	    SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid,
-	    CTLFLAG_RD, 0, "");
-	if (bz->sysctl_tree_top == NULL) {
-		sysctl_ctx_free(&bz->sysctl_tree);
-		return (0);	/* XXX error code? */
-	}
-
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0,
-	    "Total bounce pages");
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0,
-	    "Free bounce pages");
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0,
-	    "Reserved bounce pages");
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0,
-	    "Active bounce pages");
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0,
-	    "Total bounce requests");
-	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0,
-	    "Total bounce requests that were deferred");
-	SYSCTL_ADD_STRING(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, "");
-	SYSCTL_ADD_BUS_SIZE_T(busdma_sysctl_tree(bz),
-	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
-	    "alignment", CTLFLAG_RD, &bz->alignment, "");
-
-	return (0);
-}
-
-static int
-alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages)
-{
-	struct bounce_zone *bz;
-	int count;
-
-	bz = dmat->bounce_zone;
-	count = 0;
-	while (numpages > 0) {
-		struct bounce_page *bpage;
-
-		bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF,
-						     M_NOWAIT | M_ZERO);
-
-		if (bpage == NULL)
-			break;
-		bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF,
-							 M_NOWAIT, 0ul,
-							 bz->lowaddr,
-							 PAGE_SIZE,
-							 0);
-		if (bpage->vaddr == 0) {
-			free(bpage, M_DEVBUF);
-			break;
-		}
-		bpage->busaddr = pmap_kextract(bpage->vaddr);
-		mtx_lock(&bounce_lock);
-		STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links);
-		total_bpages++;
-		bz->total_bpages++;
-		bz->free_bpages++;
-		mtx_unlock(&bounce_lock);
-		count++;
-		numpages--;
-	}
-	return (count);
-}
-
-static int
-reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit)
-{
-	struct bounce_zone *bz;
-	int pages;
-
-	mtx_assert(&bounce_lock, MA_OWNED);
-	bz = dmat->bounce_zone;
-	pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved);
-	if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages))
-		return (map->pagesneeded - (map->pagesreserved + pages));
-	bz->free_bpages -= pages;
-	bz->reserved_bpages += pages;
-	map->pagesreserved += pages;
-	pages = map->pagesneeded - map->pagesreserved;
-
-	return (pages);
-}
-
-static bus_addr_t
-add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
-		bus_size_t size)
-{
-	struct bounce_zone *bz;
-	struct bounce_page *bpage;
-
-	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
-	KASSERT(map != NULL && map != &nobounce_dmamap && map != &contig_dmamap,
-	    ("add_bounce_page: bad map %p", map));
-
-	bz = dmat->bounce_zone;
-	if (map->pagesneeded == 0)
-		panic("add_bounce_page: map doesn't need any pages");
-	map->pagesneeded--;
-
-	if (map->pagesreserved == 0)
-		panic("add_bounce_page: map doesn't need any pages");
-	map->pagesreserved--;
-
-	mtx_lock(&bounce_lock);
-	bpage = STAILQ_FIRST(&bz->bounce_page_list);
-	if (bpage == NULL)
-		panic("add_bounce_page: free page list is empty");
-
-	STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links);
-	bz->reserved_bpages--;
-	bz->active_bpages++;
-	mtx_unlock(&bounce_lock);
-
-	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
-		/* Page offset needs to be preserved. */
-		bpage->vaddr |= vaddr & PAGE_MASK;
-		bpage->busaddr |= vaddr & PAGE_MASK;
-	}
-	bpage->datavaddr = vaddr;
-	bpage->datacount = size;
-	STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
-	return (bpage->busaddr);
-}
-
-static void
-free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
-{
-	struct bus_dmamap *map;
-	struct bounce_zone *bz;
-
-	bz = dmat->bounce_zone;
-	bpage->datavaddr = 0;
-	bpage->datacount = 0;
-	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
-		/*
-		 * Reset the bounce page to start at offset 0.  Other uses
-		 * of this bounce page may need to store a full page of
-		 * data and/or assume it starts on a page boundary.
-		 */
-		bpage->vaddr &= ~PAGE_MASK;
-		bpage->busaddr &= ~PAGE_MASK;
-	}
-
-	mtx_lock(&bounce_lock);
-	STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);
-	bz->free_bpages++;
-	bz->active_bpages--;
-	if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) {
-		if (reserve_bounce_pages(map->dmat, map, 1) == 0) {
-			STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links);
-			STAILQ_INSERT_TAIL(&bounce_map_callbacklist,
-					   map, links);
-			busdma_swi_pending = 1;
-			bz->total_deferred++;
-			swi_sched(vm_ih, 0);
-		}
-	}
-	mtx_unlock(&bounce_lock);
-}
-
-void
-busdma_swi(void)
-{
-	bus_dma_tag_t dmat;
-	struct bus_dmamap *map;
-
-	mtx_lock(&bounce_lock);
-	while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
-		STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
-		mtx_unlock(&bounce_lock);
-		dmat = map->dmat;
-		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK);
-		bus_dmamap_load(map->dmat, map, map->buf, map->buflen,
-				map->callback, map->callback_arg, /*flags*/0);
-		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK);
-		mtx_lock(&bounce_lock);
-	}
-	mtx_unlock(&bounce_lock);
-}

Modified: trunk/sys/x86/x86/dump_machdep.c
===================================================================
--- trunk/sys/x86/x86/dump_machdep.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/dump_machdep.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2002 Marcel Moolenaar
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/dump_machdep.c 236503 2012-06-03 08:01:12Z avg $");
 
 #include "opt_watchdog.h"
 

Added: trunk/sys/x86/x86/fdt_machdep.c
===================================================================
--- trunk/sys/x86/x86/fdt_machdep.c	                        (rev 0)
+++ trunk/sys/x86/x86/fdt_machdep.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,78 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Juniper Networks, 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/fdt_machdep.c 250840 2013-05-21 03:05:49Z marcel $");
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker.h>
+
+#include <machine/metadata.h>
+#include <x86/fdt.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+int
+x86_init_fdt(void)
+{
+	void *dtbp, *mdp;
+	int error;
+
+	if (OF_install(OFW_FDT, 0) == FALSE) {
+		error = ENXIO;
+		goto out;
+	}
+
+	mdp = preload_search_by_type("elf kernel");
+	if (mdp == NULL)
+		mdp = preload_search_by_type("elf32 kernel");
+	dtbp = (mdp != NULL) ? MD_FETCH(mdp, MODINFOMD_DTBP, void *) : NULL;
+
+#if defined(FDT_DTB_STATIC)
+	/*
+	 * In case the device tree blob was not retrieved (from metadata) try
+	 * to use the statically embedded one.
+	 */
+	if (dtbp == NULL)
+		dtbp = &fdt_static_dtb;
+#endif
+
+	if (dtbp == NULL) {
+		error = ENOENT;
+		goto out;
+	}
+
+	error = OF_init(dtbp) ? ENXIO : 0;
+
+ out:
+	return (error);
+}


Property changes on: trunk/sys/x86/x86/fdt_machdep.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/x86/identcpu.c
===================================================================
--- trunk/sys/x86/x86/identcpu.c	                        (rev 0)
+++ trunk/sys/x86/x86/identcpu.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,2407 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * Copyright (c) 1997 KATO Takenori.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/identcpu.c 332743 2018-04-19 00:11:02Z jhb $");
+
+#include "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/eventhandler.h>
+#include <sys/limits.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/power.h>
+
+#include <machine/asmacros.h>
+#include <machine/clock.h>
+#include <machine/cputypes.h>
+#include <machine/frame.h>
+#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
+
+#include <amd64/vmm/intel/vmx_controls.h>
+#include <x86/isa/icu.h>
+#include <x86/vmware.h>
+
+#ifdef __i386__
+#define	IDENTBLUE_CYRIX486	0
+#define	IDENTBLUE_IBMCPU	1
+#define	IDENTBLUE_CYRIXM2	2
+
+static void identifycyrix(void);
+static void print_transmeta_info(void);
+#endif
+static u_int find_cpu_vendor_id(void);
+static void print_AMD_info(void);
+static void print_INTEL_info(void);
+static void print_INTEL_TLB(u_int data);
+static void print_hypervisor_info(void);
+static void print_svm_info(void);
+static void print_via_padlock_info(void);
+static void print_vmx_info(void);
+
+int	cpu_class;
+char machine[] = MACHINE;
+
+#ifdef __amd64__
+#ifdef SCTL_MASK32
+extern int adaptive_machine_arch;
+#endif
+
+static int
+sysctl_hw_machine(SYSCTL_HANDLER_ARGS)
+{
+#ifdef SCTL_MASK32
+	static const char machine32[] = "i386";
+#endif
+	int error;
+
+#ifdef SCTL_MASK32
+	if ((req->flags & SCTL_MASK32) != 0 && adaptive_machine_arch)
+		error = SYSCTL_OUT(req, machine32, sizeof(machine32));
+	else
+#endif
+		error = SYSCTL_OUT(req, machine, sizeof(machine));
+	return (error);
+
+}
+SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD,
+    NULL, 0, sysctl_hw_machine, "A", "Machine class");
+#else
+SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
+    machine, 0, "Machine class");
+#endif
+
+static char cpu_model[128];
+SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD,
+    cpu_model, 0, "Machine model");
+
+static int hw_clockrate;
+SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD,
+    &hw_clockrate, 0, "CPU instruction clock rate");
+
+u_int hv_high;
+char hv_vendor[16];
+SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD, hv_vendor, 0,
+    "Hypervisor vendor");
+
+static eventhandler_tag tsc_post_tag;
+
+static char cpu_brand[48];
+
+#ifdef __i386__
+#define	MAX_BRAND_INDEX	8
+
+static const char *cpu_brandtable[MAX_BRAND_INDEX + 1] = {
+	NULL,			/* No brand */
+	"Intel Celeron",
+	"Intel Pentium III",
+	"Intel Pentium III Xeon",
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	"Intel Pentium 4"
+};
+#endif
+
+static struct {
+	char	*cpu_name;
+	int	cpu_class;
+} cpus[] = {
+#ifdef __i386__
+	{ "Intel 80286",	CPUCLASS_286 },		/* CPU_286   */
+	{ "i386SX",		CPUCLASS_386 },		/* CPU_386SX */
+	{ "i386DX",		CPUCLASS_386 },		/* CPU_386   */
+	{ "i486SX",		CPUCLASS_486 },		/* CPU_486SX */
+	{ "i486DX",		CPUCLASS_486 },		/* CPU_486   */
+	{ "Pentium",		CPUCLASS_586 },		/* CPU_586   */
+	{ "Cyrix 486",		CPUCLASS_486 },		/* CPU_486DLC */
+	{ "Pentium Pro",	CPUCLASS_686 },		/* CPU_686 */
+	{ "Cyrix 5x86",		CPUCLASS_486 },		/* CPU_M1SC */
+	{ "Cyrix 6x86",		CPUCLASS_486 },		/* CPU_M1 */
+	{ "Blue Lightning",	CPUCLASS_486 },		/* CPU_BLUE */
+	{ "Cyrix 6x86MX",	CPUCLASS_686 },		/* CPU_M2 */
+	{ "NexGen 586",		CPUCLASS_386 },		/* CPU_NX586 (XXX) */
+	{ "Cyrix 486S/DX",	CPUCLASS_486 },		/* CPU_CY486DX */
+	{ "Pentium II",		CPUCLASS_686 },		/* CPU_PII */
+	{ "Pentium III",	CPUCLASS_686 },		/* CPU_PIII */
+	{ "Pentium 4",		CPUCLASS_686 },		/* CPU_P4 */
+#else
+	{ "Clawhammer",		CPUCLASS_K8 },		/* CPU_CLAWHAMMER */
+	{ "Sledgehammer",	CPUCLASS_K8 },		/* CPU_SLEDGEHAMMER */
+#endif
+};
+
+static struct {
+	char	*vendor;
+	u_int	vendor_id;
+} cpu_vendors[] = {
+	{ INTEL_VENDOR_ID,	CPU_VENDOR_INTEL },	/* GenuineIntel */
+	{ AMD_VENDOR_ID,	CPU_VENDOR_AMD },	/* AuthenticAMD */
+	{ CENTAUR_VENDOR_ID,	CPU_VENDOR_CENTAUR },	/* CentaurHauls */
+#ifdef __i386__
+	{ NSC_VENDOR_ID,	CPU_VENDOR_NSC },	/* Geode by NSC */
+	{ CYRIX_VENDOR_ID,	CPU_VENDOR_CYRIX },	/* CyrixInstead */
+	{ TRANSMETA_VENDOR_ID,	CPU_VENDOR_TRANSMETA },	/* GenuineTMx86 */
+	{ SIS_VENDOR_ID,	CPU_VENDOR_SIS },	/* SiS SiS SiS  */
+	{ UMC_VENDOR_ID,	CPU_VENDOR_UMC },	/* UMC UMC UMC  */
+	{ NEXGEN_VENDOR_ID,	CPU_VENDOR_NEXGEN },	/* NexGenDriven */
+	{ RISE_VENDOR_ID,	CPU_VENDOR_RISE },	/* RiseRiseRise */
+#if 0
+	/* XXX CPUID 8000_0000h and 8086_0000h, not 0000_0000h */
+	{ "TransmetaCPU",	CPU_VENDOR_TRANSMETA },
+#endif
+#endif
+};
+
+void
+printcpuinfo(void)
+{
+	u_int regs[4], i;
+	char *brand;
+
+	cpu_class = cpus[cpu].cpu_class;
+	printf("CPU: ");
+	strncpy(cpu_model, cpus[cpu].cpu_name, sizeof (cpu_model));
+
+	/* Check for extended CPUID information and a processor name. */
+	if (cpu_exthigh >= 0x80000004) {
+		brand = cpu_brand;
+		for (i = 0x80000002; i < 0x80000005; i++) {
+			do_cpuid(i, regs);
+			memcpy(brand, regs, sizeof(regs));
+			brand += sizeof(regs);
+		}
+	}
+
+	switch (cpu_vendor_id) {
+	case CPU_VENDOR_INTEL:
+#ifdef __i386__
+		if ((cpu_id & 0xf00) > 0x300) {
+			u_int brand_index;
+
+			cpu_model[0] = '\0';
+
+			switch (cpu_id & 0x3000) {
+			case 0x1000:
+				strcpy(cpu_model, "Overdrive ");
+				break;
+			case 0x2000:
+				strcpy(cpu_model, "Dual ");
+				break;
+			}
+
+			switch (cpu_id & 0xf00) {
+			case 0x400:
+				strcat(cpu_model, "i486 ");
+			        /* Check the particular flavor of 486 */
+				switch (cpu_id & 0xf0) {
+				case 0x00:
+				case 0x10:
+					strcat(cpu_model, "DX");
+					break;
+				case 0x20:
+					strcat(cpu_model, "SX");
+					break;
+				case 0x30:
+					strcat(cpu_model, "DX2");
+					break;
+				case 0x40:
+					strcat(cpu_model, "SL");
+					break;
+				case 0x50:
+					strcat(cpu_model, "SX2");
+					break;
+				case 0x70:
+					strcat(cpu_model,
+					    "DX2 Write-Back Enhanced");
+					break;
+				case 0x80:
+					strcat(cpu_model, "DX4");
+					break;
+				}
+				break;
+			case 0x500:
+			        /* Check the particular flavor of 586 */
+			        strcat(cpu_model, "Pentium");
+			        switch (cpu_id & 0xf0) {
+				case 0x00:
+				        strcat(cpu_model, " A-step");
+					break;
+				case 0x10:
+				        strcat(cpu_model, "/P5");
+					break;
+				case 0x20:
+				        strcat(cpu_model, "/P54C");
+					break;
+				case 0x30:
+				        strcat(cpu_model, "/P24T");
+					break;
+				case 0x40:
+				        strcat(cpu_model, "/P55C");
+					break;
+				case 0x70:
+				        strcat(cpu_model, "/P54C");
+					break;
+				case 0x80:
+				        strcat(cpu_model, "/P55C (quarter-micron)");
+					break;
+				default:
+				        /* nothing */
+					break;
+				}
+#if defined(I586_CPU) && !defined(NO_F00F_HACK)
+				/*
+				 * XXX - If/when Intel fixes the bug, this
+				 * should also check the version of the
+				 * CPU, not just that it's a Pentium.
+				 */
+				has_f00f_bug = 1;
+#endif
+				break;
+			case 0x600:
+			        /* Check the particular flavor of 686 */
+  			        switch (cpu_id & 0xf0) {
+				case 0x00:
+				        strcat(cpu_model, "Pentium Pro A-step");
+					break;
+				case 0x10:
+				        strcat(cpu_model, "Pentium Pro");
+					break;
+				case 0x30:
+				case 0x50:
+				case 0x60:
+				        strcat(cpu_model,
+				"Pentium II/Pentium II Xeon/Celeron");
+					cpu = CPU_PII;
+					break;
+				case 0x70:
+				case 0x80:
+				case 0xa0:
+				case 0xb0:
+				        strcat(cpu_model,
+					"Pentium III/Pentium III Xeon/Celeron");
+					cpu = CPU_PIII;
+					break;
+				default:
+				        strcat(cpu_model, "Unknown 80686");
+					break;
+				}
+				break;
+			case 0xf00:
+				strcat(cpu_model, "Pentium 4");
+				cpu = CPU_P4;
+				break;
+			default:
+				strcat(cpu_model, "unknown");
+				break;
+			}
+
+			/*
+			 * If we didn't get a brand name from the extended
+			 * CPUID, try to look it up in the brand table.
+			 */
+			if (cpu_high > 0 && *cpu_brand == '\0') {
+				brand_index = cpu_procinfo & CPUID_BRAND_INDEX;
+				if (brand_index <= MAX_BRAND_INDEX &&
+				    cpu_brandtable[brand_index] != NULL)
+					strcpy(cpu_brand,
+					    cpu_brandtable[brand_index]);
+			}
+		}
+#else
+		/* Please make up your mind folks! */
+		strcat(cpu_model, "EM64T");
+#endif
+		break;
+	case CPU_VENDOR_AMD:
+		/*
+		 * Values taken from AMD Processor Recognition
+		 * http://www.amd.com/K6/k6docs/pdf/20734g.pdf
+		 * (also describes ``Features'' encodings.
+		 */
+		strcpy(cpu_model, "AMD ");
+#ifdef __i386__
+		switch (cpu_id & 0xFF0) {
+		case 0x410:
+			strcat(cpu_model, "Standard Am486DX");
+			break;
+		case 0x430:
+			strcat(cpu_model, "Enhanced Am486DX2 Write-Through");
+			break;
+		case 0x470:
+			strcat(cpu_model, "Enhanced Am486DX2 Write-Back");
+			break;
+		case 0x480:
+			strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Through");
+			break;
+		case 0x490:
+			strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Back");
+			break;
+		case 0x4E0:
+			strcat(cpu_model, "Am5x86 Write-Through");
+			break;
+		case 0x4F0:
+			strcat(cpu_model, "Am5x86 Write-Back");
+			break;
+		case 0x500:
+			strcat(cpu_model, "K5 model 0");
+			break;
+		case 0x510:
+			strcat(cpu_model, "K5 model 1");
+			break;
+		case 0x520:
+			strcat(cpu_model, "K5 PR166 (model 2)");
+			break;
+		case 0x530:
+			strcat(cpu_model, "K5 PR200 (model 3)");
+			break;
+		case 0x560:
+			strcat(cpu_model, "K6");
+			break;
+		case 0x570:
+			strcat(cpu_model, "K6 266 (model 1)");
+			break;
+		case 0x580:
+			strcat(cpu_model, "K6-2");
+			break;
+		case 0x590:
+			strcat(cpu_model, "K6-III");
+			break;
+		case 0x5a0:
+			strcat(cpu_model, "Geode LX");
+			break;
+		default:
+			strcat(cpu_model, "Unknown");
+			break;
+		}
+#else
+		if ((cpu_id & 0xf00) == 0xf00)
+			strcat(cpu_model, "AMD64 Processor");
+		else
+			strcat(cpu_model, "Unknown");
+#endif
+		break;
+#ifdef __i386__
+	case CPU_VENDOR_CYRIX:
+		strcpy(cpu_model, "Cyrix ");
+		switch (cpu_id & 0xff0) {
+		case 0x440:
+			strcat(cpu_model, "MediaGX");
+			break;
+		case 0x520:
+			strcat(cpu_model, "6x86");
+			break;
+		case 0x540:
+			cpu_class = CPUCLASS_586;
+			strcat(cpu_model, "GXm");
+			break;
+		case 0x600:
+			strcat(cpu_model, "6x86MX");
+			break;
+		default:
+			/*
+			 * Even though CPU supports the cpuid
+			 * instruction, it can be disabled.
+			 * Therefore, this routine supports all Cyrix
+			 * CPUs.
+			 */
+			switch (cyrix_did & 0xf0) {
+			case 0x00:
+				switch (cyrix_did & 0x0f) {
+				case 0x00:
+					strcat(cpu_model, "486SLC");
+					break;
+				case 0x01:
+					strcat(cpu_model, "486DLC");
+					break;
+				case 0x02:
+					strcat(cpu_model, "486SLC2");
+					break;
+				case 0x03:
+					strcat(cpu_model, "486DLC2");
+					break;
+				case 0x04:
+					strcat(cpu_model, "486SRx");
+					break;
+				case 0x05:
+					strcat(cpu_model, "486DRx");
+					break;
+				case 0x06:
+					strcat(cpu_model, "486SRx2");
+					break;
+				case 0x07:
+					strcat(cpu_model, "486DRx2");
+					break;
+				case 0x08:
+					strcat(cpu_model, "486SRu");
+					break;
+				case 0x09:
+					strcat(cpu_model, "486DRu");
+					break;
+				case 0x0a:
+					strcat(cpu_model, "486SRu2");
+					break;
+				case 0x0b:
+					strcat(cpu_model, "486DRu2");
+					break;
+				default:
+					strcat(cpu_model, "Unknown");
+					break;
+				}
+				break;
+			case 0x10:
+				switch (cyrix_did & 0x0f) {
+				case 0x00:
+					strcat(cpu_model, "486S");
+					break;
+				case 0x01:
+					strcat(cpu_model, "486S2");
+					break;
+				case 0x02:
+					strcat(cpu_model, "486Se");
+					break;
+				case 0x03:
+					strcat(cpu_model, "486S2e");
+					break;
+				case 0x0a:
+					strcat(cpu_model, "486DX");
+					break;
+				case 0x0b:
+					strcat(cpu_model, "486DX2");
+					break;
+				case 0x0f:
+					strcat(cpu_model, "486DX4");
+					break;
+				default:
+					strcat(cpu_model, "Unknown");
+					break;
+				}
+				break;
+			case 0x20:
+				if ((cyrix_did & 0x0f) < 8)
+					strcat(cpu_model, "6x86");	/* Where did you get it? */
+				else
+					strcat(cpu_model, "5x86");
+				break;
+			case 0x30:
+				strcat(cpu_model, "6x86");
+				break;
+			case 0x40:
+				if ((cyrix_did & 0xf000) == 0x3000) {
+					cpu_class = CPUCLASS_586;
+					strcat(cpu_model, "GXm");
+				} else
+					strcat(cpu_model, "MediaGX");
+				break;
+			case 0x50:
+				strcat(cpu_model, "6x86MX");
+				break;
+			case 0xf0:
+				switch (cyrix_did & 0x0f) {
+				case 0x0d:
+					strcat(cpu_model, "Overdrive CPU");
+					break;
+				case 0x0e:
+					strcpy(cpu_model, "Texas Instruments 486SXL");
+					break;
+				case 0x0f:
+					strcat(cpu_model, "486SLC/DLC");
+					break;
+				default:
+					strcat(cpu_model, "Unknown");
+					break;
+				}
+				break;
+			default:
+				strcat(cpu_model, "Unknown");
+				break;
+			}
+			break;
+		}
+		break;
+	case CPU_VENDOR_RISE:
+		strcpy(cpu_model, "Rise ");
+		switch (cpu_id & 0xff0) {
+		case 0x500:	/* 6401 and 6441 (Kirin) */
+		case 0x520:	/* 6510 (Lynx) */
+			strcat(cpu_model, "mP6");
+			break;
+		default:
+			strcat(cpu_model, "Unknown");
+		}
+		break;
+#endif
+	case CPU_VENDOR_CENTAUR:
+#ifdef __i386__
+		switch (cpu_id & 0xff0) {
+		case 0x540:
+			strcpy(cpu_model, "IDT WinChip C6");
+			break;
+		case 0x580:
+			strcpy(cpu_model, "IDT WinChip 2");
+			break;
+		case 0x590:
+			strcpy(cpu_model, "IDT WinChip 3");
+			break;
+		case 0x660:
+			strcpy(cpu_model, "VIA C3 Samuel");
+			break;
+		case 0x670:
+			if (cpu_id & 0x8)
+				strcpy(cpu_model, "VIA C3 Ezra");
+			else
+				strcpy(cpu_model, "VIA C3 Samuel 2");
+			break;
+		case 0x680:
+			strcpy(cpu_model, "VIA C3 Ezra-T");
+			break;
+		case 0x690:
+			strcpy(cpu_model, "VIA C3 Nehemiah");
+			break;
+		case 0x6a0:
+		case 0x6d0:
+			strcpy(cpu_model, "VIA C7 Esther");
+			break;
+		case 0x6f0:
+			strcpy(cpu_model, "VIA Nano");
+			break;
+		default:
+			strcpy(cpu_model, "VIA/IDT Unknown");
+		}
+#else
+		strcpy(cpu_model, "VIA ");
+		if ((cpu_id & 0xff0) == 0x6f0)
+			strcat(cpu_model, "Nano Processor");
+		else
+			strcat(cpu_model, "Unknown");
+#endif
+		break;
+#ifdef __i386__
+	case CPU_VENDOR_IBM:
+		strcpy(cpu_model, "Blue Lightning CPU");
+		break;
+	case CPU_VENDOR_NSC:
+		switch (cpu_id & 0xff0) {
+		case 0x540:
+			strcpy(cpu_model, "Geode SC1100");
+			cpu = CPU_GEODE1100;
+			break;
+		default:
+			strcpy(cpu_model, "Geode/NSC unknown");
+			break;
+		}
+		break;
+#endif
+	default:
+		strcat(cpu_model, "Unknown");
+		break;
+	}
+
+	/*
+	 * Replace cpu_model with cpu_brand minus leading spaces if
+	 * we have one.
+	 */
+	brand = cpu_brand;
+	while (*brand == ' ')
+		++brand;
+	if (*brand != '\0')
+		strcpy(cpu_model, brand);
+
+	printf("%s (", cpu_model);
+	if (tsc_freq != 0) {
+		hw_clockrate = (tsc_freq + 5000) / 1000000;
+		printf("%jd.%02d-MHz ",
+		    (intmax_t)(tsc_freq + 4999) / 1000000,
+		    (u_int)((tsc_freq + 4999) / 10000) % 100);
+	}
+	switch(cpu_class) {
+#ifdef __i386__
+	case CPUCLASS_286:
+		printf("286");
+		break;
+	case CPUCLASS_386:
+		printf("386");
+		break;
+#if defined(I486_CPU)
+	case CPUCLASS_486:
+		printf("486");
+		break;
+#endif
+#if defined(I586_CPU)
+	case CPUCLASS_586:
+		printf("586");
+		break;
+#endif
+#if defined(I686_CPU)
+	case CPUCLASS_686:
+		printf("686");
+		break;
+#endif
+#else
+	case CPUCLASS_K8:
+		printf("K8");
+		break;
+#endif
+	default:
+		printf("Unknown");	/* will panic below... */
+	}
+	printf("-class CPU)\n");
+	if (*cpu_vendor)
+		printf("  Origin=\"%s\"", cpu_vendor);
+	if (cpu_id)
+		printf("  Id=0x%x", cpu_id);
+
+	if (cpu_vendor_id == CPU_VENDOR_INTEL ||
+	    cpu_vendor_id == CPU_VENDOR_AMD ||
+	    cpu_vendor_id == CPU_VENDOR_CENTAUR ||
+#ifdef __i386__
+	    cpu_vendor_id == CPU_VENDOR_TRANSMETA ||
+	    cpu_vendor_id == CPU_VENDOR_RISE ||
+	    cpu_vendor_id == CPU_VENDOR_NSC ||
+	    (cpu_vendor_id == CPU_VENDOR_CYRIX && ((cpu_id & 0xf00) > 0x500)) ||
+#endif
+	    0) {
+		printf("  Family=0x%x", CPUID_TO_FAMILY(cpu_id));
+		printf("  Model=0x%x", CPUID_TO_MODEL(cpu_id));
+		printf("  Stepping=%u", cpu_id & CPUID_STEPPING);
+#ifdef __i386__
+		if (cpu_vendor_id == CPU_VENDOR_CYRIX)
+			printf("\n  DIR=0x%04x", cyrix_did);
+#endif
+
+		/*
+		 * AMD CPUID Specification
+		 * http://support.amd.com/us/Embedded_TechDocs/25481.pdf
+		 *
+		 * Intel Processor Identification and CPUID Instruction
+		 * http://www.intel.com/assets/pdf/appnote/241618.pdf
+		 */
+		if (cpu_high > 0) {
+
+			/*
+			 * Here we should probably set up flags indicating
+			 * whether or not various features are available.
+			 * The interesting ones are probably VME, PSE, PAE,
+			 * and PGE.  The code already assumes without bothering
+			 * to check that all CPUs >= Pentium have a TSC and
+			 * MSRs.
+			 */
+			printf("\n  Features=0x%b", cpu_feature,
+			"\020"
+			"\001FPU"	/* Integral FPU */
+			"\002VME"	/* Extended VM86 mode support */
+			"\003DE"	/* Debugging Extensions (CR4.DE) */
+			"\004PSE"	/* 4MByte page tables */
+			"\005TSC"	/* Timestamp counter */
+			"\006MSR"	/* Machine specific registers */
+			"\007PAE"	/* Physical address extension */
+			"\010MCE"	/* Machine Check support */
+			"\011CX8"	/* CMPEXCH8 instruction */
+			"\012APIC"	/* SMP local APIC */
+			"\013oldMTRR"	/* Previous implementation of MTRR */
+			"\014SEP"	/* Fast System Call */
+			"\015MTRR"	/* Memory Type Range Registers */
+			"\016PGE"	/* PG_G (global bit) support */
+			"\017MCA"	/* Machine Check Architecture */
+			"\020CMOV"	/* CMOV instruction */
+			"\021PAT"	/* Page attributes table */
+			"\022PSE36"	/* 36 bit address space support */
+			"\023PN"	/* Processor Serial number */
+			"\024CLFLUSH"	/* Has the CLFLUSH instruction */
+			"\025<b20>"
+			"\026DTS"	/* Debug Trace Store */
+			"\027ACPI"	/* ACPI support */
+			"\030MMX"	/* MMX instructions */
+			"\031FXSR"	/* FXSAVE/FXRSTOR */
+			"\032SSE"	/* Streaming SIMD Extensions */
+			"\033SSE2"	/* Streaming SIMD Extensions #2 */
+			"\034SS"	/* Self snoop */
+			"\035HTT"	/* Hyperthreading (see EBX bit 16-23) */
+			"\036TM"	/* Thermal Monitor clock slowdown */
+			"\037IA64"	/* CPU can execute IA64 instructions */
+			"\040PBE"	/* Pending Break Enable */
+			);
+
+			if (cpu_feature2 != 0) {
+				printf("\n  Features2=0x%b", cpu_feature2,
+				"\020"
+				"\001SSE3"	/* SSE3 */
+				"\002PCLMULQDQ"	/* Carry-Less Mul Quadword */
+				"\003DTES64"	/* 64-bit Debug Trace */
+				"\004MON"	/* MONITOR/MWAIT Instructions */
+				"\005DS_CPL"	/* CPL Qualified Debug Store */
+				"\006VMX"	/* Virtual Machine Extensions */
+				"\007SMX"	/* Safer Mode Extensions */
+				"\010EST"	/* Enhanced SpeedStep */
+				"\011TM2"	/* Thermal Monitor 2 */
+				"\012SSSE3"	/* SSSE3 */
+				"\013CNXT-ID"	/* L1 context ID available */
+				"\014SDBG"	/* IA32 silicon debug */
+				"\015FMA"	/* Fused Multiply Add */
+				"\016CX16"	/* CMPXCHG16B Instruction */
+				"\017xTPR"	/* Send Task Priority Messages*/
+				"\020PDCM"	/* Perf/Debug Capability MSR */
+				"\021<b16>"
+				"\022PCID"	/* Process-context Identifiers*/
+				"\023DCA"	/* Direct Cache Access */
+				"\024SSE4.1"	/* SSE 4.1 */
+				"\025SSE4.2"	/* SSE 4.2 */
+				"\026x2APIC"	/* xAPIC Extensions */
+				"\027MOVBE"	/* MOVBE Instruction */
+				"\030POPCNT"	/* POPCNT Instruction */
+				"\031TSCDLT"	/* TSC-Deadline Timer */
+				"\032AESNI"	/* AES Crypto */
+				"\033XSAVE"	/* XSAVE/XRSTOR States */
+				"\034OSXSAVE"	/* OS-Enabled State Management*/
+				"\035AVX"	/* Advanced Vector Extensions */
+				"\036F16C"	/* Half-precision conversions */
+				"\037RDRAND"	/* RDRAND Instruction */
+				"\040HV"	/* Hypervisor */
+				);
+			}
+
+			if (amd_feature != 0) {
+				printf("\n  AMD Features=0x%b", amd_feature,
+				"\020"		/* in hex */
+				"\001<s0>"	/* Same */
+				"\002<s1>"	/* Same */
+				"\003<s2>"	/* Same */
+				"\004<s3>"	/* Same */
+				"\005<s4>"	/* Same */
+				"\006<s5>"	/* Same */
+				"\007<s6>"	/* Same */
+				"\010<s7>"	/* Same */
+				"\011<s8>"	/* Same */
+				"\012<s9>"	/* Same */
+				"\013<b10>"	/* Undefined */
+				"\014SYSCALL"	/* Have SYSCALL/SYSRET */
+				"\015<s12>"	/* Same */
+				"\016<s13>"	/* Same */
+				"\017<s14>"	/* Same */
+				"\020<s15>"	/* Same */
+				"\021<s16>"	/* Same */
+				"\022<s17>"	/* Same */
+				"\023<b18>"	/* Reserved, unknown */
+				"\024MP"	/* Multiprocessor Capable */
+				"\025NX"	/* Has EFER.NXE, NX */
+				"\026<b21>"	/* Undefined */
+				"\027MMX+"	/* AMD MMX Extensions */
+				"\030<s23>"	/* Same */
+				"\031<s24>"	/* Same */
+				"\032FFXSR"	/* Fast FXSAVE/FXRSTOR */
+				"\033Page1GB"	/* 1-GB large page support */
+				"\034RDTSCP"	/* RDTSCP */
+				"\035<b28>"	/* Undefined */
+				"\036LM"	/* 64 bit long mode */
+				"\0373DNow!+"	/* AMD 3DNow! Extensions */
+				"\0403DNow!"	/* AMD 3DNow! */
+				);
+			}
+
+			if (amd_feature2 != 0) {
+				printf("\n  AMD Features2=0x%b", amd_feature2,
+				"\020"
+				"\001LAHF"	/* LAHF/SAHF in long mode */
+				"\002CMP"	/* CMP legacy */
+				"\003SVM"	/* Secure Virtual Mode */
+				"\004ExtAPIC"	/* Extended APIC register */
+				"\005CR8"	/* CR8 in legacy mode */
+				"\006ABM"	/* LZCNT instruction */
+				"\007SSE4A"	/* SSE4A */
+				"\010MAS"	/* Misaligned SSE mode */
+				"\011Prefetch"	/* 3DNow! Prefetch/PrefetchW */
+				"\012OSVW"	/* OS visible workaround */
+				"\013IBS"	/* Instruction based sampling */
+				"\014XOP"	/* XOP extended instructions */
+				"\015SKINIT"	/* SKINIT/STGI */
+				"\016WDT"	/* Watchdog timer */
+				"\017<b14>"
+				"\020LWP"	/* Lightweight Profiling */
+				"\021FMA4"	/* 4-operand FMA instructions */
+				"\022TCE"	/* Translation Cache Extension */
+				"\023<b18>"
+				"\024NodeId"	/* NodeId MSR support */
+				"\025<b20>"
+				"\026TBM"	/* Trailing Bit Manipulation */
+				"\027Topology"	/* Topology Extensions */
+				"\030PCXC"	/* Core perf count */
+				"\031PNXC"	/* NB perf count */
+				"\032<b25>"
+				"\033DBE"	/* Data Breakpoint extension */
+				"\034PTSC"	/* Performance TSC */
+				"\035PL2I"	/* L2I perf count */
+				"\036MWAITX"	/* MONITORX/MWAITX instructions */
+				"\037<b30>"
+				"\040<b31>"
+				);
+			}
+
+			if (cpu_stdext_feature != 0) {
+				printf("\n  Structured Extended Features=0x%b",
+				    cpu_stdext_feature,
+				       "\020"
+				       /* RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */
+				       "\001FSGSBASE"
+				       "\002TSCADJ"
+				       "\003SGX"
+				       /* Bit Manipulation Instructions */
+				       "\004BMI1"
+				       /* Hardware Lock Elision */
+				       "\005HLE"
+				       /* Advanced Vector Instructions 2 */
+				       "\006AVX2"
+				       /* FDP_EXCPTN_ONLY */
+				       "\007FDPEXC"
+				       /* Supervisor Mode Execution Prot. */
+				       "\010SMEP"
+				       /* Bit Manipulation Instructions */
+				       "\011BMI2"
+				       "\012ERMS"
+				       /* Invalidate Processor Context ID */
+				       "\013INVPCID"
+				       /* Restricted Transactional Memory */
+				       "\014RTM"
+				       "\015PQM"
+				       "\016NFPUSG"
+				       /* Intel Memory Protection Extensions */
+				       "\017MPX"
+				       "\020PQE"
+				       /* AVX512 Foundation */
+				       "\021AVX512F"
+				       /* Enhanced NRBG */
+				       "\023RDSEED"
+				       /* ADCX + ADOX */
+				       "\024ADX"
+				       /* Supervisor Mode Access Prevention */
+				       "\025SMAP"
+				       "\030CLFLUSHOPT"
+				       "\032PROCTRACE"
+				       "\033AVX512PF"
+				       "\034AVX512ER"
+				       "\035AVX512CD"
+				       "\036SHA"
+				       );
+			}
+
+			if (cpu_stdext_feature2 != 0) {
+				printf("\n  Structured Extended Features2=0x%b",
+				    cpu_stdext_feature2,
+				       "\020"
+				       "\001PREFETCHWT1"
+				       "\003UMIP"
+				       "\004PKU"
+				       "\005OSPKE"
+				       "\027RDPID"
+				       "\037SGXLC"
+				       );
+			}
+
+			if ((cpu_feature2 & CPUID2_XSAVE) != 0) {
+				cpuid_count(0xd, 0x1, regs);
+				if (regs[0] != 0) {
+					printf("\n  XSAVE Features=0x%b",
+					    regs[0],
+					    "\020"
+					    "\001XSAVEOPT"
+					    "\002XSAVEC"
+					    "\003XINUSE"
+					    "\004XSAVES");
+				}
+			}
+
+			if (via_feature_rng != 0 || via_feature_xcrypt != 0)
+				print_via_padlock_info();
+
+			if (cpu_feature2 & CPUID2_VMX)
+				print_vmx_info();
+
+			if (amd_feature2 & AMDID2_SVM)
+				print_svm_info();
+
+			if ((cpu_feature & CPUID_HTT) &&
+			    cpu_vendor_id == CPU_VENDOR_AMD)
+				cpu_feature &= ~CPUID_HTT;
+
+			/*
+			 * If this CPU supports P-state invariant TSC then
+			 * mention the capability.
+			 */
+			if (tsc_is_invariant) {
+				printf("\n  TSC: P-state invariant");
+				if (tsc_perf_stat)
+					printf(", performance statistics");
+			}
+		}
+#ifdef __i386__
+	} else if (cpu_vendor_id == CPU_VENDOR_CYRIX) {
+		printf("  DIR=0x%04x", cyrix_did);
+		printf("  Stepping=%u", (cyrix_did & 0xf000) >> 12);
+		printf("  Revision=%u", (cyrix_did & 0x0f00) >> 8);
+#ifndef CYRIX_CACHE_REALLY_WORKS
+		if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
+			printf("\n  CPU cache: write-through mode");
+#endif
+#endif
+	}
+
+	/* Avoid ugly blank lines: only print newline when we have to. */
+	if (*cpu_vendor || cpu_id)
+		printf("\n");
+
+	if (bootverbose) {
+		if (cpu_vendor_id == CPU_VENDOR_AMD)
+			print_AMD_info();
+		else if (cpu_vendor_id == CPU_VENDOR_INTEL)
+			print_INTEL_info();
+#ifdef __i386__
+		else if (cpu_vendor_id == CPU_VENDOR_TRANSMETA)
+			print_transmeta_info();
+#endif
+	}
+
+	print_hypervisor_info();
+}
+
+void
+panicifcpuunsupported(void)
+{
+
+#ifdef __i386__
+#if !defined(lint)
+#if !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
+#error This kernel is not configured for one of the supported CPUs
+#endif
+#else /* lint */
+#endif /* lint */
+#else /* __amd64__ */
+#ifndef HAMMER
+#error "You need to specify a cpu type"
+#endif
+#endif
+	/*
+	 * Now that we have told the user what they have,
+	 * let them know if that machine type isn't configured.
+	 */
+	switch (cpu_class) {
+#ifdef __i386__
+	case CPUCLASS_286:	/* a 286 should not make it this far, anyway */
+	case CPUCLASS_386:
+#if !defined(I486_CPU)
+	case CPUCLASS_486:
+#endif
+#if !defined(I586_CPU)
+	case CPUCLASS_586:
+#endif
+#if !defined(I686_CPU)
+	case CPUCLASS_686:
+#endif
+#else /* __amd64__ */
+	case CPUCLASS_X86:
+#ifndef HAMMER
+	case CPUCLASS_K8:
+#endif
+#endif
+		panic("CPU class not configured");
+	default:
+		break;
+	}
+}
+
+#ifdef __i386__
+static	volatile u_int trap_by_rdmsr;
+
+/*
+ * Special exception 6 handler.
+ * The rdmsr instruction generates invalid opcodes fault on 486-class
+ * Cyrix CPU.  Stacked eip register points the rdmsr instruction in the
+ * function identblue() when this handler is called.  Stacked eip should
+ * be advanced.
+ */
+inthand_t	bluetrap6;
+#ifdef __GNUCLIKE_ASM
+__asm
+("									\n\
+	.text								\n\
+	.p2align 2,0x90							\n\
+	.type	" __XSTRING(CNAME(bluetrap6)) ", at function		\n\
+" __XSTRING(CNAME(bluetrap6)) ":					\n\
+	ss								\n\
+	movl	$0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) "		\n\
+	addl	$2, (%esp)	/* rdmsr is a 2-byte instruction */	\n\
+	iret								\n\
+");
+#endif
+
+/*
+ * Special exception 13 handler.
+ * Accessing non-existent MSR generates general protection fault.
+ */
+inthand_t	bluetrap13;
+#ifdef __GNUCLIKE_ASM
+__asm
+("									\n\
+	.text								\n\
+	.p2align 2,0x90							\n\
+	.type	" __XSTRING(CNAME(bluetrap13)) ", at function		\n\
+" __XSTRING(CNAME(bluetrap13)) ":					\n\
+	ss								\n\
+	movl	$0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) "		\n\
+	popl	%eax		/* discard error code */		\n\
+	addl	$2, (%esp)	/* rdmsr is a 2-byte instruction */	\n\
+	iret								\n\
+");
+#endif
+
+/*
+ * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
+ * support cpuid instruction.  This function should be called after
+ * loading interrupt descriptor table register.
+ *
+ * I don't like this method that handles fault, but I couldn't get
+ * information for any other methods.  Does blue giant know?
+ */
+static int
+identblue(void)
+{
+
+	trap_by_rdmsr = 0;
+
+	/*
+	 * Cyrix 486-class CPU does not support rdmsr instruction.
+	 * The rdmsr instruction generates invalid opcode fault, and exception
+	 * will be trapped by bluetrap6() on Cyrix 486-class CPU.  The
+	 * bluetrap6() set the magic number to trap_by_rdmsr.
+	 */
+	setidt(IDT_UD, bluetrap6, SDT_SYS386TGT, SEL_KPL,
+	    GSEL(GCODE_SEL, SEL_KPL));
+
+	/*
+	 * Certain BIOS disables cpuid instruction of Cyrix 6x86MX CPU.
+	 * In this case, rdmsr generates general protection fault, and
+	 * exception will be trapped by bluetrap13().
+	 */
+	setidt(IDT_GP, bluetrap13, SDT_SYS386TGT, SEL_KPL,
+	    GSEL(GCODE_SEL, SEL_KPL));
+
+	rdmsr(0x1002);		/* Cyrix CPU generates fault. */
+
+	if (trap_by_rdmsr == 0xa8c1d)
+		return IDENTBLUE_CYRIX486;
+	else if (trap_by_rdmsr == 0xa89c4)
+		return IDENTBLUE_CYRIXM2;
+	return IDENTBLUE_IBMCPU;
+}
+
+
+/*
+ * identifycyrix() set lower 16 bits of cyrix_did as follows:
+ *
+ *  F E D C B A 9 8 7 6 5 4 3 2 1 0
+ * +-------+-------+---------------+
+ * |  SID  |  RID  |   Device ID   |
+ * |    (DIR 1)    |    (DIR 0)    |
+ * +-------+-------+---------------+
+ */
+static void
+identifycyrix(void)
+{
+	register_t saveintr;
+	int	ccr2_test = 0, dir_test = 0;
+	u_char	ccr2, ccr3;
+
+	saveintr = intr_disable();
+
+	ccr2 = read_cyrix_reg(CCR2);
+	write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
+	read_cyrix_reg(CCR2);
+	if (read_cyrix_reg(CCR2) != ccr2)
+		ccr2_test = 1;
+	write_cyrix_reg(CCR2, ccr2);
+
+	ccr3 = read_cyrix_reg(CCR3);
+	write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
+	read_cyrix_reg(CCR3);
+	if (read_cyrix_reg(CCR3) != ccr3)
+		dir_test = 1;					/* CPU supports DIRs. */
+	write_cyrix_reg(CCR3, ccr3);
+
+	if (dir_test) {
+		/* Device ID registers are available. */
+		cyrix_did = read_cyrix_reg(DIR1) << 8;
+		cyrix_did += read_cyrix_reg(DIR0);
+	} else if (ccr2_test)
+		cyrix_did = 0x0010;		/* 486S A-step */
+	else
+		cyrix_did = 0x00ff;		/* Old 486SLC/DLC and TI486SXLC/SXL */
+
+	intr_restore(saveintr);
+}
+#endif
+
+/* Update TSC freq with the value indicated by the caller. */
+static void
+tsc_freq_changed(void *arg __unused, const struct cf_level *level, int status)
+{
+
+	/* If there was an error during the transition, don't do anything. */
+	if (status != 0)
+		return;
+
+	/* Total setting for this level gives the new frequency in MHz. */
+	hw_clockrate = level->total_set.freq;
+}
+
+static void
+hook_tsc_freq(void *arg __unused)
+{
+
+	if (tsc_is_invariant)
+		return;
+
+	tsc_post_tag = EVENTHANDLER_REGISTER(cpufreq_post_change,
+	    tsc_freq_changed, NULL, EVENTHANDLER_PRI_ANY);
+}
+
+SYSINIT(hook_tsc_freq, SI_SUB_CONFIGURE, SI_ORDER_ANY, hook_tsc_freq, NULL);
+
+#ifndef XEN
+static const char *const vm_bnames[] = {
+	"QEMU",				/* QEMU */
+	"Plex86",			/* Plex86 */
+	"Bochs",			/* Bochs */
+	"Xen",				/* Xen */
+	"BHYVE",			/* bhyve */
+	"Seabios",			/* KVM */
+	NULL
+};
+
+static const char *const vm_pnames[] = {
+	"VMware Virtual Platform",	/* VMWare VM */
+	"Virtual Machine",		/* Microsoft VirtualPC */
+	"VirtualBox",			/* Sun xVM VirtualBox */
+	"Parallels Virtual Platform",	/* Parallels VM */
+	"KVM",				/* KVM */
+	NULL
+};
+
+void
+identify_hypervisor(void)
+{
+	u_int regs[4];
+	char *p;
+	int i;
+
+	/*
+	 * [RFC] CPUID usage for interaction between Hypervisors and Linux.
+	 * http://lkml.org/lkml/2008/10/1/246
+	 *
+	 * KB1009458: Mechanisms to determine if software is running in
+	 * a VMware virtual machine
+	 * http://kb.vmware.com/kb/1009458
+	 */
+	if (cpu_feature2 & CPUID2_HV) {
+		vm_guest = VM_GUEST_VM;
+		do_cpuid(0x40000000, regs);
+
+		/*
+		 * KVM from Linux kernels prior to commit
+		 * 57c22e5f35aa4b9b2fe11f73f3e62bbf9ef36190 set %eax
+		 * to 0 rather than a valid hv_high value.  Check for
+		 * the KVM signature bytes and fixup %eax to the
+		 * highest supported leaf in that case.
+		 */
+		if (regs[0] == 0 && regs[1] == 0x4b4d564b &&
+		    regs[2] == 0x564b4d56 && regs[3] == 0x0000004d)
+			regs[0] = 0x40000001;
+			
+		if (regs[0] >= 0x40000000) {
+			hv_high = regs[0];
+			((u_int *)&hv_vendor)[0] = regs[1];
+			((u_int *)&hv_vendor)[1] = regs[2];
+			((u_int *)&hv_vendor)[2] = regs[3];
+			hv_vendor[12] = '\0';
+			if (strcmp(hv_vendor, "VMwareVMware") == 0)
+				vm_guest = VM_GUEST_VMWARE;
+			else if (strcmp(hv_vendor, "Microsoft Hv") == 0)
+				vm_guest = VM_GUEST_HV;
+		}
+		return;
+	}
+
+	/*
+	 * Examine SMBIOS strings for older hypervisors.
+	 */
+	p = getenv("smbios.system.serial");
+	if (p != NULL) {
+		if (strncmp(p, "VMware-", 7) == 0 || strncmp(p, "VMW", 3) == 0) {
+			vmware_hvcall(VMW_HVCMD_GETVERSION, regs);
+			if (regs[1] == VMW_HVMAGIC) {
+				vm_guest = VM_GUEST_VMWARE;			
+				freeenv(p);
+				return;
+			}
+		}
+		freeenv(p);
+	}
+
+	/*
+	 * XXX: Some of these entries may not be needed since they were
+	 * added to FreeBSD before the checks above.
+	 */
+	p = getenv("smbios.bios.vendor");
+	if (p != NULL) {
+		for (i = 0; vm_bnames[i] != NULL; i++)
+			if (strcmp(p, vm_bnames[i]) == 0) {
+				vm_guest = VM_GUEST_VM;
+				freeenv(p);
+				return;
+			}
+		freeenv(p);
+	}
+	p = getenv("smbios.system.product");
+	if (p != NULL) {
+		for (i = 0; vm_pnames[i] != NULL; i++)
+			if (strcmp(p, vm_pnames[i]) == 0) {
+				vm_guest = VM_GUEST_VM;
+				freeenv(p);
+				return;
+			}
+		freeenv(p);
+	}
+}
+#endif
+
+bool
+fix_cpuid(void)
+{
+	uint64_t msr;
+
+	/*
+	 * Clear "Limit CPUID Maxval" bit and return true if the caller should
+	 * get the largest standard CPUID function number again if it is set
+	 * from BIOS.  It is necessary for probing correct CPU topology later
+	 * and for the correct operation of the AVX-aware userspace.
+	 */
+	if (cpu_vendor_id == CPU_VENDOR_INTEL &&
+	    ((CPUID_TO_FAMILY(cpu_id) == 0xf &&
+	    CPUID_TO_MODEL(cpu_id) >= 0x3) ||
+	    (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+	    CPUID_TO_MODEL(cpu_id) >= 0xe))) {
+		msr = rdmsr(MSR_IA32_MISC_ENABLE);
+		if ((msr & IA32_MISC_EN_LIMCPUID) != 0) {
+			msr &= ~IA32_MISC_EN_LIMCPUID;
+			wrmsr(MSR_IA32_MISC_ENABLE, msr);
+			return (true);
+		}
+	}
+
+	/*
+	 * Re-enable AMD Topology Extension that could be disabled by BIOS
+	 * on some notebook processors.  Without the extension it's really
+	 * hard to determine the correct CPU cache topology.
+	 * See BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 15h
+	 * Models 60h-6Fh Processors, Publication # 50742.
+	 */
+	if (vm_guest == VM_GUEST_NO && cpu_vendor_id == CPU_VENDOR_AMD &&
+	    CPUID_TO_FAMILY(cpu_id) == 0x15) {
+		msr = rdmsr(MSR_EXTFEATURES);
+		if ((msr & ((uint64_t)1 << 54)) == 0) {
+			msr |= (uint64_t)1 << 54;
+			wrmsr(MSR_EXTFEATURES, msr);
+			return (true);
+		}
+	}
+	return (false);
+}
+
+#ifdef __amd64__
+void
+identify_cpu(void)
+{
+	u_int regs[4];
+
+	do_cpuid(0, regs);
+	cpu_high = regs[0];
+	((u_int *)&cpu_vendor)[0] = regs[1];
+	((u_int *)&cpu_vendor)[1] = regs[3];
+	((u_int *)&cpu_vendor)[2] = regs[2];
+	cpu_vendor[12] = '\0';
+
+	do_cpuid(1, regs);
+	cpu_id = regs[0];
+	cpu_procinfo = regs[1];
+	cpu_feature = regs[3];
+	cpu_feature2 = regs[2];
+}
+#endif
+
+/*
+ * Final stage of CPU identification.
+ */
+void
+finishidentcpu(void)
+{
+	u_int regs[4], cpu_stdext_disable;
+#ifdef __i386__
+	u_char ccr3;
+#endif
+
+	cpu_vendor_id = find_cpu_vendor_id();
+
+	if (fix_cpuid()) {
+		do_cpuid(0, regs);
+		cpu_high = regs[0];
+	}
+
+	if (cpu_high >= 5 && (cpu_feature2 & CPUID2_MON) != 0) {
+		do_cpuid(5, regs);
+		cpu_mon_mwait_flags = regs[2];
+		cpu_mon_min_size = regs[0] &  CPUID5_MON_MIN_SIZE;
+		cpu_mon_max_size = regs[1] &  CPUID5_MON_MAX_SIZE;
+	}
+
+	if (cpu_high >= 7) {
+		cpuid_count(7, 0, regs);
+		cpu_stdext_feature = regs[1];
+
+		/*
+		 * Some hypervisors fail to filter out unsupported
+		 * extended features.  For now, disable the
+		 * extensions, activation of which requires setting a
+		 * bit in CR4, and which VM monitors do not support.
+		 */
+		if (cpu_feature2 & CPUID2_HV) {
+			cpu_stdext_disable = CPUID_STDEXT_FSGSBASE |
+			    CPUID_STDEXT_SMEP;
+		} else
+			cpu_stdext_disable = 0;
+		TUNABLE_INT_FETCH("hw.cpu_stdext_disable", &cpu_stdext_disable);
+		cpu_stdext_feature &= ~cpu_stdext_disable;
+		cpu_stdext_feature2 = regs[2];
+	}
+
+#ifdef __i386__
+	if (cpu_high > 0 &&
+	    (cpu_vendor_id == CPU_VENDOR_INTEL ||
+	     cpu_vendor_id == CPU_VENDOR_AMD ||
+	     cpu_vendor_id == CPU_VENDOR_TRANSMETA ||
+	     cpu_vendor_id == CPU_VENDOR_CENTAUR ||
+	     cpu_vendor_id == CPU_VENDOR_NSC)) {
+		do_cpuid(0x80000000, regs);
+		if (regs[0] >= 0x80000000)
+			cpu_exthigh = regs[0];
+	}
+#else
+	if (cpu_vendor_id == CPU_VENDOR_INTEL ||
+	    cpu_vendor_id == CPU_VENDOR_AMD ||
+	    cpu_vendor_id == CPU_VENDOR_CENTAUR) {
+		do_cpuid(0x80000000, regs);
+		cpu_exthigh = regs[0];
+	}
+#endif
+	if (cpu_exthigh >= 0x80000001) {
+		do_cpuid(0x80000001, regs);
+		amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff);
+		amd_feature2 = regs[2];
+	}
+	if (cpu_exthigh >= 0x80000007) {
+		do_cpuid(0x80000007, regs);
+		amd_pminfo = regs[3];
+	}
+	if (cpu_exthigh >= 0x80000008) {
+		do_cpuid(0x80000008, regs);
+		cpu_maxphyaddr = regs[0] & 0xff;
+		cpu_procinfo2 = regs[2];
+	} else {
+		cpu_maxphyaddr = (cpu_feature & CPUID_PAE) != 0 ? 36 : 32;
+	}
+
+#ifdef __i386__
+	if (cpu_vendor_id == CPU_VENDOR_CYRIX) {
+		if (cpu == CPU_486) {
+			/*
+			 * These conditions are equivalent to:
+			 *     - CPU does not support cpuid instruction.
+			 *     - Cyrix/IBM CPU is detected.
+			 */
+			if (identblue() == IDENTBLUE_IBMCPU) {
+				strcpy(cpu_vendor, "IBM");
+				cpu_vendor_id = CPU_VENDOR_IBM;
+				cpu = CPU_BLUE;
+				return;
+			}
+		}
+		switch (cpu_id & 0xf00) {
+		case 0x600:
+			/*
+			 * Cyrix's datasheet does not describe DIRs.
+			 * Therefor, I assume it does not have them
+			 * and use the result of the cpuid instruction.
+			 * XXX they seem to have it for now at least. -Peter
+			 */
+			identifycyrix();
+			cpu = CPU_M2;
+			break;
+		default:
+			identifycyrix();
+			/*
+			 * This routine contains a trick.
+			 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
+			 */
+			switch (cyrix_did & 0x00f0) {
+			case 0x00:
+			case 0xf0:
+				cpu = CPU_486DLC;
+				break;
+			case 0x10:
+				cpu = CPU_CY486DX;
+				break;
+			case 0x20:
+				if ((cyrix_did & 0x000f) < 8)
+					cpu = CPU_M1;
+				else
+					cpu = CPU_M1SC;
+				break;
+			case 0x30:
+				cpu = CPU_M1;
+				break;
+			case 0x40:
+				/* MediaGX CPU */
+				cpu = CPU_M1SC;
+				break;
+			default:
+				/* M2 and later CPUs are treated as M2. */
+				cpu = CPU_M2;
+
+				/*
+				 * enable cpuid instruction.
+				 */
+				ccr3 = read_cyrix_reg(CCR3);
+				write_cyrix_reg(CCR3, CCR3_MAPEN0);
+				write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
+				write_cyrix_reg(CCR3, ccr3);
+
+				do_cpuid(0, regs);
+				cpu_high = regs[0];	/* eax */
+				do_cpuid(1, regs);
+				cpu_id = regs[0];	/* eax */
+				cpu_feature = regs[3];	/* edx */
+				break;
+			}
+		}
+	} else if (cpu == CPU_486 && *cpu_vendor == '\0') {
+		/*
+		 * There are BlueLightning CPUs that do not change
+		 * undefined flags by dividing 5 by 2.  In this case,
+		 * the CPU identification routine in locore.s leaves
+		 * cpu_vendor null string and puts CPU_486 into the
+		 * cpu.
+		 */
+		if (identblue() == IDENTBLUE_IBMCPU) {
+			strcpy(cpu_vendor, "IBM");
+			cpu_vendor_id = CPU_VENDOR_IBM;
+			cpu = CPU_BLUE;
+			return;
+		}
+	}
+#else
+	/* XXX */
+	cpu = CPU_CLAWHAMMER;
+#endif
+}
+
+static u_int
+find_cpu_vendor_id(void)
+{
+	int	i;
+
+	for (i = 0; i < sizeof(cpu_vendors) / sizeof(cpu_vendors[0]); i++)
+		if (strcmp(cpu_vendor, cpu_vendors[i].vendor) == 0)
+			return (cpu_vendors[i].vendor_id);
+	return (0);
+}
+
+static void
+print_AMD_assoc(int i)
+{
+	if (i == 255)
+		printf(", fully associative\n");
+	else
+		printf(", %d-way associative\n", i);
+}
+
+static void
+print_AMD_l2_assoc(int i)
+{
+	switch (i & 0x0f) {
+	case 0: printf(", disabled/not present\n"); break;
+	case 1: printf(", direct mapped\n"); break;
+	case 2: printf(", 2-way associative\n"); break;
+	case 4: printf(", 4-way associative\n"); break;
+	case 6: printf(", 8-way associative\n"); break;
+	case 8: printf(", 16-way associative\n"); break;
+	case 15: printf(", fully associative\n"); break;
+	default: printf(", reserved configuration\n"); break;
+	}
+}
+
+static void
+print_AMD_info(void)
+{
+#ifdef __i386__
+	uint64_t amd_whcr;
+#endif
+	u_int regs[4];
+
+	if (cpu_exthigh >= 0x80000005) {
+		do_cpuid(0x80000005, regs);
+		printf("L1 2MB data TLB: %d entries", (regs[0] >> 16) & 0xff);
+		print_AMD_assoc(regs[0] >> 24);
+
+		printf("L1 2MB instruction TLB: %d entries", regs[0] & 0xff);
+		print_AMD_assoc((regs[0] >> 8) & 0xff);
+
+		printf("L1 4KB data TLB: %d entries", (regs[1] >> 16) & 0xff);
+		print_AMD_assoc(regs[1] >> 24);
+
+		printf("L1 4KB instruction TLB: %d entries", regs[1] & 0xff);
+		print_AMD_assoc((regs[1] >> 8) & 0xff);
+
+		printf("L1 data cache: %d kbytes", regs[2] >> 24);
+		printf(", %d bytes/line", regs[2] & 0xff);
+		printf(", %d lines/tag", (regs[2] >> 8) & 0xff);
+		print_AMD_assoc((regs[2] >> 16) & 0xff);
+
+		printf("L1 instruction cache: %d kbytes", regs[3] >> 24);
+		printf(", %d bytes/line", regs[3] & 0xff);
+		printf(", %d lines/tag", (regs[3] >> 8) & 0xff);
+		print_AMD_assoc((regs[3] >> 16) & 0xff);
+	}
+
+	if (cpu_exthigh >= 0x80000006) {
+		do_cpuid(0x80000006, regs);
+		if ((regs[0] >> 16) != 0) {
+			printf("L2 2MB data TLB: %d entries",
+			    (regs[0] >> 16) & 0xfff);
+			print_AMD_l2_assoc(regs[0] >> 28);
+			printf("L2 2MB instruction TLB: %d entries",
+			    regs[0] & 0xfff);
+			print_AMD_l2_assoc((regs[0] >> 28) & 0xf);
+		} else {
+			printf("L2 2MB unified TLB: %d entries",
+			    regs[0] & 0xfff);
+			print_AMD_l2_assoc((regs[0] >> 28) & 0xf);
+		}
+		if ((regs[1] >> 16) != 0) {
+			printf("L2 4KB data TLB: %d entries",
+			    (regs[1] >> 16) & 0xfff);
+			print_AMD_l2_assoc(regs[1] >> 28);
+
+			printf("L2 4KB instruction TLB: %d entries",
+			    (regs[1] >> 16) & 0xfff);
+			print_AMD_l2_assoc((regs[1] >> 28) & 0xf);
+		} else {
+			printf("L2 4KB unified TLB: %d entries",
+			    (regs[1] >> 16) & 0xfff);
+			print_AMD_l2_assoc((regs[1] >> 28) & 0xf);
+		}
+		printf("L2 unified cache: %d kbytes", regs[2] >> 16);
+		printf(", %d bytes/line", regs[2] & 0xff);
+		printf(", %d lines/tag", (regs[2] >> 8) & 0x0f);
+		print_AMD_l2_assoc((regs[2] >> 12) & 0x0f);
+	}
+
+#ifdef __i386__
+	if (((cpu_id & 0xf00) == 0x500)
+	    && (((cpu_id & 0x0f0) > 0x80)
+		|| (((cpu_id & 0x0f0) == 0x80)
+		    && (cpu_id & 0x00f) > 0x07))) {
+		/* K6-2(new core [Stepping 8-F]), K6-III or later */
+		amd_whcr = rdmsr(0xc0000082);
+		if (!(amd_whcr & (0x3ff << 22))) {
+			printf("Write Allocate Disable\n");
+		} else {
+			printf("Write Allocate Enable Limit: %dM bytes\n",
+			    (u_int32_t)((amd_whcr & (0x3ff << 22)) >> 22) * 4);
+			printf("Write Allocate 15-16M bytes: %s\n",
+			    (amd_whcr & (1 << 16)) ? "Enable" : "Disable");
+		}
+	} else if (((cpu_id & 0xf00) == 0x500)
+		   && ((cpu_id & 0x0f0) > 0x50)) {
+		/* K6, K6-2(old core) */
+		amd_whcr = rdmsr(0xc0000082);
+		if (!(amd_whcr & (0x7f << 1))) {
+			printf("Write Allocate Disable\n");
+		} else {
+			printf("Write Allocate Enable Limit: %dM bytes\n",
+			    (u_int32_t)((amd_whcr & (0x7f << 1)) >> 1) * 4);
+			printf("Write Allocate 15-16M bytes: %s\n",
+			    (amd_whcr & 0x0001) ? "Enable" : "Disable");
+			printf("Hardware Write Allocate Control: %s\n",
+			    (amd_whcr & 0x0100) ? "Enable" : "Disable");
+		}
+	}
+#endif
+	/*
+	 * Opteron Rev E shows a bug as in very rare occasions a read memory
+	 * barrier is not performed as expected if it is followed by a
+	 * non-atomic read-modify-write instruction.
+	 * As long as that bug pops up very rarely (intensive machine usage
+	 * on other operating systems generally generates one unexplainable
+	 * crash any 2 months) and as long as a model specific fix would be
+	 * impractical at this stage, print out a warning string if the broken
+	 * model and family are identified.
+	 */
+	if (CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x20 &&
+	    CPUID_TO_MODEL(cpu_id) <= 0x3f)
+		printf("WARNING: This architecture revision has known SMP "
+		    "hardware bugs which may cause random instability\n");
+}
+
+static void
+print_INTEL_info(void)
+{
+	u_int regs[4];
+	u_int rounds, regnum;
+	u_int nwaycode, nway;
+
+	if (cpu_high >= 2) {
+		rounds = 0;
+		do {
+			do_cpuid(0x2, regs);
+			if (rounds == 0 && (rounds = (regs[0] & 0xff)) == 0)
+				break;	/* we have a buggy CPU */
+
+			for (regnum = 0; regnum <= 3; ++regnum) {
+				if (regs[regnum] & (1<<31))
+					continue;
+				if (regnum != 0)
+					print_INTEL_TLB(regs[regnum] & 0xff);
+				print_INTEL_TLB((regs[regnum] >> 8) & 0xff);
+				print_INTEL_TLB((regs[regnum] >> 16) & 0xff);
+				print_INTEL_TLB((regs[regnum] >> 24) & 0xff);
+			}
+		} while (--rounds > 0);
+	}
+
+	if (cpu_exthigh >= 0x80000006) {
+		do_cpuid(0x80000006, regs);
+		nwaycode = (regs[2] >> 12) & 0x0f;
+		if (nwaycode >= 0x02 && nwaycode <= 0x08)
+			nway = 1 << (nwaycode / 2);
+		else
+			nway = 0;
+		printf("L2 cache: %u kbytes, %u-way associative, %u bytes/line\n",
+		    (regs[2] >> 16) & 0xffff, nway, regs[2] & 0xff);
+	}
+}
+
+static void
+print_INTEL_TLB(u_int data)
+{
+	switch (data) {
+	case 0x0:
+	case 0x40:
+	default:
+		break;
+	case 0x1:
+		printf("Instruction TLB: 4 KB pages, 4-way set associative, 32 entries\n");
+		break;
+	case 0x2:
+		printf("Instruction TLB: 4 MB pages, fully associative, 2 entries\n");
+		break;
+	case 0x3:
+		printf("Data TLB: 4 KB pages, 4-way set associative, 64 entries\n");
+		break;
+	case 0x4:
+		printf("Data TLB: 4 MB Pages, 4-way set associative, 8 entries\n");
+		break;
+	case 0x6:
+		printf("1st-level instruction cache: 8 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x8:
+		printf("1st-level instruction cache: 16 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x9:
+		printf("1st-level instruction cache: 32 KB, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0xa:
+		printf("1st-level data cache: 8 KB, 2-way set associative, 32 byte line size\n");
+		break;
+	case 0xb:
+		printf("Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries\n");
+		break;
+	case 0xc:
+		printf("1st-level data cache: 16 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0xd:
+		printf("1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size");
+		break;
+	case 0xe:
+		printf("1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size\n");
+		break;
+	case 0x1d:
+		printf("2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size\n");
+		break;
+	case 0x21:
+		printf("2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0x22:
+		printf("3rd-level cache: 512 KB, 4-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x23:
+		printf("3rd-level cache: 1 MB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x24:
+		printf("2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0x25:
+		printf("3rd-level cache: 2 MB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x29:
+		printf("3rd-level cache: 4 MB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x2c:
+		printf("1st-level data cache: 32 KB, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0x30:
+		printf("1st-level instruction cache: 32 KB, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0x39: /* De-listed in SDM rev. 54 */
+		printf("2nd-level cache: 128 KB, 4-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x3b: /* De-listed in SDM rev. 54 */
+		printf("2nd-level cache: 128 KB, 2-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x3c: /* De-listed in SDM rev. 54 */
+		printf("2nd-level cache: 256 KB, 4-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x41:
+		printf("2nd-level cache: 128 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x42:
+		printf("2nd-level cache: 256 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x43:
+		printf("2nd-level cache: 512 KB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x44:
+		printf("2nd-level cache: 1 MB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x45:
+		printf("2nd-level cache: 2 MB, 4-way set associative, 32 byte line size\n");
+		break;
+	case 0x46:
+		printf("3rd-level cache: 4 MB, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0x47:
+		printf("3rd-level cache: 8 MB, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0x48:
+		printf("2nd-level cache: 3MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0x49:
+		if (CPUID_TO_FAMILY(cpu_id) == 0xf &&
+		    CPUID_TO_MODEL(cpu_id) == 0x6)
+			printf("3rd-level cache: 4MB, 16-way set associative, 64-byte line size\n");
+		else
+			printf("2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size");
+		break;
+	case 0x4a:
+		printf("3rd-level cache: 6MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0x4b:
+		printf("3rd-level cache: 8MByte, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0x4c:
+		printf("3rd-level cache: 12MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0x4d:
+		printf("3rd-level cache: 16MByte, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0x4e:
+		printf("2nd-level cache: 6MByte, 24-way set associative, 64 byte line size\n");
+		break;
+	case 0x4f:
+		printf("Instruction TLB: 4 KByte pages, 32 entries\n");
+		break;
+	case 0x50:
+		printf("Instruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 64 entries\n");
+		break;
+	case 0x51:
+		printf("Instruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 128 entries\n");
+		break;
+	case 0x52:
+		printf("Instruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 256 entries\n");
+		break;
+	case 0x55:
+		printf("Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries\n");
+		break;
+	case 0x56:
+		printf("Data TLB0: 4 MByte pages, 4-way set associative, 16 entries\n");
+		break;
+	case 0x57:
+		printf("Data TLB0: 4 KByte pages, 4-way associative, 16 entries\n");
+		break;
+	case 0x59:
+		printf("Data TLB0: 4 KByte pages, fully associative, 16 entries\n");
+		break;
+	case 0x5a:
+		printf("Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries\n");
+		break;
+	case 0x5b:
+		printf("Data TLB: 4 KB or 4 MB pages, fully associative, 64 entries\n");
+		break;
+	case 0x5c:
+		printf("Data TLB: 4 KB or 4 MB pages, fully associative, 128 entries\n");
+		break;
+	case 0x5d:
+		printf("Data TLB: 4 KB or 4 MB pages, fully associative, 256 entries\n");
+		break;
+	case 0x60:
+		printf("1st-level data cache: 16 KB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x61:
+		printf("Instruction TLB: 4 KByte pages, fully associative, 48 entries\n");
+		break;
+	case 0x63:
+		printf("Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries\n");
+		break;
+	case 0x64:
+		printf("Data TLB: 4 KBytes pages, 4-way set associative, 512 entries\n");
+		break;
+	case 0x66:
+		printf("1st-level data cache: 8 KB, 4-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x67:
+		printf("1st-level data cache: 16 KB, 4-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x68:
+		printf("1st-level data cache: 32 KB, 4 way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x6a:
+		printf("uTLB: 4KByte pages, 8-way set associative, 64 entries\n");
+		break;
+	case 0x6b:
+		printf("DTLB: 4KByte pages, 8-way set associative, 256 entries\n");
+		break;
+	case 0x6c:
+		printf("DTLB: 2M/4M pages, 8-way set associative, 128 entries\n");
+		break;
+	case 0x6d:
+		printf("DTLB: 1 GByte pages, fully associative, 16 entries\n");
+		break;
+	case 0x70:
+		printf("Trace cache: 12K-uops, 8-way set associative\n");
+		break;
+	case 0x71:
+		printf("Trace cache: 16K-uops, 8-way set associative\n");
+		break;
+	case 0x72:
+		printf("Trace cache: 32K-uops, 8-way set associative\n");
+		break;
+	case 0x76:
+		printf("Instruction TLB: 2M/4M pages, fully associative, 8 entries\n");
+		break;
+	case 0x78:
+		printf("2nd-level cache: 1 MB, 4-way set associative, 64-byte line size\n");
+		break;
+	case 0x79:
+		printf("2nd-level cache: 128 KB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x7a:
+		printf("2nd-level cache: 256 KB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x7b:
+		printf("2nd-level cache: 512 KB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x7c:
+		printf("2nd-level cache: 1 MB, 8-way set associative, sectored cache, 64 byte line size\n");
+		break;
+	case 0x7d:
+		printf("2nd-level cache: 2-MB, 8-way set associative, 64-byte line size\n");
+		break;
+	case 0x7f:
+		printf("2nd-level cache: 512-KB, 2-way set associative, 64-byte line size\n");
+		break;
+	case 0x80:
+		printf("2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size\n");
+		break;
+	case 0x82:
+		printf("2nd-level cache: 256 KB, 8-way set associative, 32 byte line size\n");
+		break;
+	case 0x83:
+		printf("2nd-level cache: 512 KB, 8-way set associative, 32 byte line size\n");
+		break;
+	case 0x84:
+		printf("2nd-level cache: 1 MB, 8-way set associative, 32 byte line size\n");
+		break;
+	case 0x85:
+		printf("2nd-level cache: 2 MB, 8-way set associative, 32 byte line size\n");
+		break;
+	case 0x86:
+		printf("2nd-level cache: 512 KB, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0x87:
+		printf("2nd-level cache: 1 MB, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0xa0:
+		printf("DTLB: 4k pages, fully associative, 32 entries\n");
+		break;
+	case 0xb0:
+		printf("Instruction TLB: 4 KB Pages, 4-way set associative, 128 entries\n");
+		break;
+	case 0xb1:
+		printf("Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries\n");
+		break;
+	case 0xb2:
+		printf("Instruction TLB: 4KByte pages, 4-way set associative, 64 entries\n");
+		break;
+	case 0xb3:
+		printf("Data TLB: 4 KB Pages, 4-way set associative, 128 entries\n");
+		break;
+	case 0xb4:
+		printf("Data TLB1: 4 KByte pages, 4-way associative, 256 entries\n");
+		break;
+	case 0xb5:
+		printf("Instruction TLB: 4KByte pages, 8-way set associative, 64 entries\n");
+		break;
+	case 0xb6:
+		printf("Instruction TLB: 4KByte pages, 8-way set associative, 128 entries\n");
+		break;
+	case 0xba:
+		printf("Data TLB1: 4 KByte pages, 4-way associative, 64 entries\n");
+		break;
+	case 0xc0:
+		printf("Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries\n");
+		break;
+	case 0xc1:
+		printf("Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries\n");
+		break;
+	case 0xc2:
+		printf("DTLB: 4 KByte/2 MByte pages, 4-way associative, 16 entries\n");
+		break;
+	case 0xc3:
+		printf("Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries\n");
+		break;
+	case 0xc4:
+		printf("DTLB: 2M/4M Byte pages, 4-way associative, 32 entries\n");
+		break;
+	case 0xca:
+		printf("Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries\n");
+		break;
+	case 0xd0:
+		printf("3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0xd1:
+		printf("3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0xd2:
+		printf("3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size\n");
+		break;
+	case 0xd6:
+		printf("3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0xd7:
+		printf("3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0xd8:
+		printf("3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size\n");
+		break;
+	case 0xdc:
+		printf("3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0xdd:
+		printf("3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0xde:
+		printf("3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size\n");
+		break;
+	case 0xe2:
+		printf("3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0xe3:
+		printf("3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0xe4:
+		printf("3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size\n");
+		break;
+	case 0xea:
+		printf("3rd-level cache: 12MByte, 24-way set associative, 64 byte line size\n");
+		break;
+	case 0xeb:
+		printf("3rd-level cache: 18MByte, 24-way set associative, 64 byte line size\n");
+		break;
+	case 0xec:
+		printf("3rd-level cache: 24MByte, 24-way set associative, 64 byte line size\n");
+		break;
+	case 0xf0:
+		printf("64-Byte prefetching\n");
+		break;
+	case 0xf1:
+		printf("128-Byte prefetching\n");
+		break;
+	}
+}
+
+static void
+print_svm_info(void)
+{
+	u_int features, regs[4];
+	uint64_t msr;
+	int comma;
+
+	printf("\n  SVM: ");
+	do_cpuid(0x8000000A, regs);
+	features = regs[3];
+
+	msr = rdmsr(MSR_VM_CR);
+	if ((msr & VM_CR_SVMDIS) == VM_CR_SVMDIS)
+		printf("(disabled in BIOS) ");
+
+	if (!bootverbose) {
+		comma = 0;
+		if (features & (1 << 0)) {
+			printf("%sNP", comma ? "," : "");
+                        comma = 1; 
+		}
+		if (features & (1 << 3)) {
+			printf("%sNRIP", comma ? "," : "");
+                        comma = 1; 
+		}
+		if (features & (1 << 5)) {
+			printf("%sVClean", comma ? "," : "");
+                        comma = 1; 
+		}
+		if (features & (1 << 6)) {
+			printf("%sAFlush", comma ? "," : "");
+                        comma = 1; 
+		}
+		if (features & (1 << 7)) {
+			printf("%sDAssist", comma ? "," : "");
+                        comma = 1; 
+		}
+		printf("%sNAsids=%d", comma ? "," : "", regs[1]);
+		return;
+	}
+
+	printf("Features=0x%b", features,
+	       "\020"
+	       "\001NP"			/* Nested paging */
+	       "\002LbrVirt"		/* LBR virtualization */
+	       "\003SVML"		/* SVM lock */
+	       "\004NRIPS"		/* NRIP save */
+	       "\005TscRateMsr"		/* MSR based TSC rate control */
+	       "\006VmcbClean"		/* VMCB clean bits */
+	       "\007FlushByAsid"	/* Flush by ASID */
+	       "\010DecodeAssist"	/* Decode assist */
+	       "\011<b8>"
+	       "\012<b9>"
+	       "\013PauseFilter"	/* PAUSE intercept filter */    
+	       "\014<b11>"
+	       "\015PauseFilterThreshold" /* PAUSE filter threshold */
+	       "\016AVIC"		/* virtual interrupt controller */
+                );
+	printf("\nRevision=%d, ASIDs=%d", regs[0] & 0xff, regs[1]);
+}
+
+#ifdef __i386__
+static void
+print_transmeta_info(void)
+{
+	u_int regs[4], nreg = 0;
+
+	do_cpuid(0x80860000, regs);
+	nreg = regs[0];
+	if (nreg >= 0x80860001) {
+		do_cpuid(0x80860001, regs);
+		printf("  Processor revision %u.%u.%u.%u\n",
+		       (regs[1] >> 24) & 0xff,
+		       (regs[1] >> 16) & 0xff,
+		       (regs[1] >> 8) & 0xff,
+		       regs[1] & 0xff);
+	}
+	if (nreg >= 0x80860002) {
+		do_cpuid(0x80860002, regs);
+		printf("  Code Morphing Software revision %u.%u.%u-%u-%u\n",
+		       (regs[1] >> 24) & 0xff,
+		       (regs[1] >> 16) & 0xff,
+		       (regs[1] >> 8) & 0xff,
+		       regs[1] & 0xff,
+		       regs[2]);
+	}
+	if (nreg >= 0x80860006) {
+		char info[65];
+		do_cpuid(0x80860003, (u_int*) &info[0]);
+		do_cpuid(0x80860004, (u_int*) &info[16]);
+		do_cpuid(0x80860005, (u_int*) &info[32]);
+		do_cpuid(0x80860006, (u_int*) &info[48]);
+		info[64] = 0;
+		printf("  %s\n", info);
+	}
+}
+#endif
+
+static void
+print_via_padlock_info(void)
+{
+	u_int regs[4];
+
+	do_cpuid(0xc0000001, regs);
+	printf("\n  VIA Padlock Features=0x%b", regs[3],
+	"\020"
+	"\003RNG"		/* RNG */
+	"\007AES"		/* ACE */
+	"\011AES-CTR"		/* ACE2 */
+	"\013SHA1,SHA256"	/* PHE */
+	"\015RSA"		/* PMM */
+	);
+}
+
+static uint32_t
+vmx_settable(uint64_t basic, int msr, int true_msr)
+{
+	uint64_t val;
+
+	if (basic & (1ULL << 55))
+		val = rdmsr(true_msr);
+	else
+		val = rdmsr(msr);
+
+	/* Just report the controls that can be set to 1. */
+	return (val >> 32);
+}
+
+static void
+print_vmx_info(void)
+{
+	uint64_t basic, msr;
+	uint32_t entry, exit, mask, pin, proc, proc2;
+	int comma;
+
+	printf("\n  VT-x: ");
+	msr = rdmsr(MSR_IA32_FEATURE_CONTROL);
+	if (!(msr & IA32_FEATURE_CONTROL_VMX_EN))
+		printf("(disabled in BIOS) ");
+	basic = rdmsr(MSR_VMX_BASIC);
+	pin = vmx_settable(basic, MSR_VMX_PINBASED_CTLS,
+	    MSR_VMX_TRUE_PINBASED_CTLS);
+	proc = vmx_settable(basic, MSR_VMX_PROCBASED_CTLS,
+	    MSR_VMX_TRUE_PROCBASED_CTLS);
+	if (proc & PROCBASED_SECONDARY_CONTROLS)
+		proc2 = vmx_settable(basic, MSR_VMX_PROCBASED_CTLS2,
+		    MSR_VMX_PROCBASED_CTLS2);
+	else
+		proc2 = 0;
+	exit = vmx_settable(basic, MSR_VMX_EXIT_CTLS, MSR_VMX_TRUE_EXIT_CTLS);
+	entry = vmx_settable(basic, MSR_VMX_ENTRY_CTLS, MSR_VMX_TRUE_ENTRY_CTLS);
+
+	if (!bootverbose) {
+		comma = 0;
+		if (exit & VM_EXIT_SAVE_PAT && exit & VM_EXIT_LOAD_PAT &&
+		    entry & VM_ENTRY_LOAD_PAT) {
+			printf("%sPAT", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc & PROCBASED_HLT_EXITING) {
+			printf("%sHLT", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc & PROCBASED_MTF) {
+			printf("%sMTF", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc & PROCBASED_PAUSE_EXITING) {
+			printf("%sPAUSE", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc2 & PROCBASED2_ENABLE_EPT) {
+			printf("%sEPT", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc2 & PROCBASED2_UNRESTRICTED_GUEST) {
+			printf("%sUG", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc2 & PROCBASED2_ENABLE_VPID) {
+			printf("%sVPID", comma ? "," : "");
+			comma = 1;
+		}
+		if (proc & PROCBASED_USE_TPR_SHADOW &&
+		    proc2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES &&
+		    proc2 & PROCBASED2_VIRTUALIZE_X2APIC_MODE &&
+		    proc2 & PROCBASED2_APIC_REGISTER_VIRTUALIZATION &&
+		    proc2 & PROCBASED2_VIRTUAL_INTERRUPT_DELIVERY) {
+			printf("%sVID", comma ? "," : "");
+			comma = 1;
+			if (pin & PINBASED_POSTED_INTERRUPT)
+				printf(",PostIntr");
+		}
+		return;
+	}
+
+	mask = basic >> 32;
+	printf("Basic Features=0x%b", mask,
+	"\020"
+	"\02132PA"		/* 32-bit physical addresses */
+	"\022SMM"		/* SMM dual-monitor */
+	"\027INS/OUTS"		/* VM-exit info for INS and OUTS */
+	"\030TRUE"		/* TRUE_CTLS MSRs */
+	);
+	printf("\n        Pin-Based Controls=0x%b", pin,
+	"\020"
+	"\001ExtINT"		/* External-interrupt exiting */
+	"\004NMI"		/* NMI exiting */
+	"\006VNMI"		/* Virtual NMIs */
+	"\007PreTmr"		/* Activate VMX-preemption timer */
+	"\010PostIntr"		/* Process posted interrupts */
+	);
+	printf("\n        Primary Processor Controls=0x%b", proc,
+	"\020"
+	"\003INTWIN"		/* Interrupt-window exiting */
+	"\004TSCOff"		/* Use TSC offsetting */
+	"\010HLT"		/* HLT exiting */
+	"\012INVLPG"		/* INVLPG exiting */
+	"\013MWAIT"		/* MWAIT exiting */
+	"\014RDPMC"		/* RDPMC exiting */
+	"\015RDTSC"		/* RDTSC exiting */
+	"\020CR3-LD"		/* CR3-load exiting */
+	"\021CR3-ST"		/* CR3-store exiting */
+	"\024CR8-LD"		/* CR8-load exiting */
+	"\025CR8-ST"		/* CR8-store exiting */
+	"\026TPR"		/* Use TPR shadow */
+	"\027NMIWIN"		/* NMI-window exiting */
+	"\030MOV-DR"		/* MOV-DR exiting */
+	"\031IO"		/* Unconditional I/O exiting */
+	"\032IOmap"		/* Use I/O bitmaps */
+	"\034MTF"		/* Monitor trap flag */
+	"\035MSRmap"		/* Use MSR bitmaps */
+	"\036MONITOR"		/* MONITOR exiting */
+	"\037PAUSE"		/* PAUSE exiting */
+	);
+	if (proc & PROCBASED_SECONDARY_CONTROLS)
+		printf("\n        Secondary Processor Controls=0x%b", proc2,
+		"\020"
+		"\001APIC"		/* Virtualize APIC accesses */
+		"\002EPT"		/* Enable EPT */
+		"\003DT"		/* Descriptor-table exiting */
+		"\004RDTSCP"		/* Enable RDTSCP */
+		"\005x2APIC"		/* Virtualize x2APIC mode */
+		"\006VPID"		/* Enable VPID */
+		"\007WBINVD"		/* WBINVD exiting */
+		"\010UG"		/* Unrestricted guest */
+		"\011APIC-reg"		/* APIC-register virtualization */
+		"\012VID"		/* Virtual-interrupt delivery */
+		"\013PAUSE-loop"	/* PAUSE-loop exiting */
+		"\014RDRAND"		/* RDRAND exiting */
+		"\015INVPCID"		/* Enable INVPCID */
+		"\016VMFUNC"		/* Enable VM functions */
+		"\017VMCS"		/* VMCS shadowing */
+		"\020EPT#VE"		/* EPT-violation #VE */
+		"\021XSAVES"		/* Enable XSAVES/XRSTORS */
+		);
+	printf("\n        Exit Controls=0x%b", mask,
+	"\020"
+	"\003DR"		/* Save debug controls */
+				/* Ignore Host address-space size */
+	"\015PERF"		/* Load MSR_PERF_GLOBAL_CTRL */
+	"\020AckInt"		/* Acknowledge interrupt on exit */
+	"\023PAT-SV"		/* Save MSR_PAT */
+	"\024PAT-LD"		/* Load MSR_PAT */
+	"\025EFER-SV"		/* Save MSR_EFER */
+	"\026EFER-LD"		/* Load MSR_EFER */
+	"\027PTMR-SV"		/* Save VMX-preemption timer value */
+	);
+	printf("\n        Entry Controls=0x%b", mask,
+	"\020"
+	"\003DR"		/* Save debug controls */
+				/* Ignore IA-32e mode guest */
+				/* Ignore Entry to SMM */
+				/* Ignore Deactivate dual-monitor treatment */
+	"\016PERF"		/* Load MSR_PERF_GLOBAL_CTRL */
+	"\017PAT"		/* Load MSR_PAT */
+	"\020EFER"		/* Load MSR_EFER */
+	);
+	if (proc & PROCBASED_SECONDARY_CONTROLS &&
+	    (proc2 & (PROCBASED2_ENABLE_EPT | PROCBASED2_ENABLE_VPID)) != 0) {
+		msr = rdmsr(MSR_VMX_EPT_VPID_CAP);
+		mask = msr;
+		printf("\n        EPT Features=0x%b", mask,
+		"\020"
+		"\001XO"		/* Execute-only translations */
+		"\007PW4"		/* Page-walk length of 4 */
+		"\011UC"		/* EPT paging-structure mem can be UC */
+		"\017WB"		/* EPT paging-structure mem can be WB */
+		"\0212M"		/* EPT PDE can map a 2-Mbyte page */
+		"\0221G"		/* EPT PDPTE can map a 1-Gbyte page */
+		"\025INVEPT"		/* INVEPT is supported */
+		"\026AD"		/* Accessed and dirty flags for EPT */
+		"\032single"		/* INVEPT single-context type */
+		"\033all"		/* INVEPT all-context type */
+		);
+		mask = msr >> 32;
+		printf("\n        VPID Features=0x%b", mask,
+		"\020"
+		"\001INVVPID"		/* INVVPID is supported */
+		"\011individual"	/* INVVPID individual-address type */
+		"\012single"		/* INVVPID single-context type */
+		"\013all"		/* INVVPID all-context type */
+		 /* INVVPID single-context-retaining-globals type */
+		"\014single-globals"
+		);
+	}
+}
+
+static void
+print_hypervisor_info(void)
+{
+
+	if (*hv_vendor)
+		printf("Hypervisor: Origin = \"%s\"\n", hv_vendor);
+}


Property changes on: trunk/sys/x86/x86/identcpu.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/x86/intr_machdep.c
===================================================================
--- trunk/sys/x86/x86/intr_machdep.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/intr_machdep.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -26,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/x86/x86/intr_machdep.c 307244 2016-10-14 02:03:53Z sephe $
  */
 
 /*
@@ -49,6 +47,7 @@
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/smp.h>
+#include <sys/sx.h>
 #include <sys/syslog.h>
 #include <sys/systm.h>
 #include <machine/clock.h>
@@ -76,7 +75,8 @@
 
 static int intrcnt_index;
 static struct intsrc *interrupt_sources[NUM_IO_INTS];
-static struct mtx intr_table_lock;
+static struct sx intrsrc_lock;
+static struct mtx intrpic_lock;
 static struct mtx intrcnt_lock;
 static TAILQ_HEAD(pics_head, pic) pics;
 
@@ -120,7 +120,7 @@
 {
 	int error;
 
-	mtx_lock(&intr_table_lock);
+	mtx_lock(&intrpic_lock);
 	if (intr_pic_registered(pic))
 		error = EBUSY;
 	else {
@@ -127,7 +127,7 @@
 		TAILQ_INSERT_TAIL(&pics, pic, pics);
 		error = 0;
 	}
-	mtx_unlock(&intr_table_lock);
+	mtx_unlock(&intrpic_lock);
 	return (error);
 }
 
@@ -151,9 +151,9 @@
 	    vector);
 	if (error)
 		return (error);
-	mtx_lock(&intr_table_lock);
+	sx_xlock(&intrsrc_lock);
 	if (interrupt_sources[vector] != NULL) {
-		mtx_unlock(&intr_table_lock);
+		sx_xunlock(&intrsrc_lock);
 		intr_event_destroy(isrc->is_event);
 		return (EEXIST);
 	}
@@ -160,7 +160,7 @@
 	intrcnt_register(isrc);
 	interrupt_sources[vector] = isrc;
 	isrc->is_handlers = 0;
-	mtx_unlock(&intr_table_lock);
+	sx_xunlock(&intrsrc_lock);
 	return (0);
 }
 
@@ -184,7 +184,7 @@
 	error = intr_event_add_handler(isrc->is_event, name, filter, handler,
 	    arg, intr_priority(flags), flags, cookiep);
 	if (error == 0) {
-		mtx_lock(&intr_table_lock);
+		sx_xlock(&intrsrc_lock);
 		intrcnt_updatename(isrc);
 		isrc->is_handlers++;
 		if (isrc->is_handlers == 1) {
@@ -191,7 +191,7 @@
 			isrc->is_pic->pic_enable_intr(isrc);
 			isrc->is_pic->pic_enable_source(isrc);
 		}
-		mtx_unlock(&intr_table_lock);
+		sx_xunlock(&intrsrc_lock);
 	}
 	return (error);
 }
@@ -205,7 +205,7 @@
 	isrc = intr_handler_source(cookie);
 	error = intr_event_remove_handler(cookie);
 	if (error == 0) {
-		mtx_lock(&intr_table_lock);
+		sx_xlock(&intrsrc_lock);
 		isrc->is_handlers--;
 		if (isrc->is_handlers == 0) {
 			isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
@@ -212,7 +212,7 @@
 			isrc->is_pic->pic_disable_intr(isrc);
 		}
 		intrcnt_updatename(isrc);
-		mtx_unlock(&intr_table_lock);
+		sx_xunlock(&intrsrc_lock);
 	}
 	return (error);
 }
@@ -279,7 +279,7 @@
 }
 
 void
-intr_resume(void)
+intr_resume(bool suspend_cancelled)
 {
 	struct pic *pic;
 
@@ -286,12 +286,12 @@
 #ifndef DEV_ATPIC
 	atpic_reset();
 #endif
-	mtx_lock(&intr_table_lock);
+	mtx_lock(&intrpic_lock);
 	TAILQ_FOREACH(pic, &pics, pics) {
 		if (pic->pic_resume != NULL)
-			pic->pic_resume(pic);
+			pic->pic_resume(pic, suspend_cancelled);
 	}
-	mtx_unlock(&intr_table_lock);
+	mtx_unlock(&intrpic_lock);
 }
 
 void
@@ -299,12 +299,12 @@
 {
 	struct pic *pic;
 
-	mtx_lock(&intr_table_lock);
+	mtx_lock(&intrpic_lock);
 	TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) {
 		if (pic->pic_suspend != NULL)
 			pic->pic_suspend(pic);
 	}
-	mtx_unlock(&intr_table_lock);
+	mtx_unlock(&intrpic_lock);
 }
 
 static int
@@ -320,9 +320,9 @@
 	 */
 	if (assign_cpu && cpu != NOCPU) {
 		isrc = arg;
-		mtx_lock(&intr_table_lock);
+		sx_xlock(&intrsrc_lock);
 		error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]);
-		mtx_unlock(&intr_table_lock);
+		sx_xunlock(&intrsrc_lock);
 	} else
 		error = 0;
 	return (error);
@@ -382,7 +382,8 @@
 	intrcnt_setname("???", 0);
 	intrcnt_index = 1;
 	TAILQ_INIT(&pics);
-	mtx_init(&intr_table_lock, "intr sources", NULL, MTX_DEF);
+	mtx_init(&intrpic_lock, "intrpic", NULL, MTX_DEF);
+	sx_init(&intrsrc_lock, "intrsrc");
 	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
 }
 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
@@ -452,7 +453,7 @@
  * allocate CPUs round-robin.
  */
 
-static cpuset_t intr_cpus;
+static cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
 static int current_cpu;
 
 /*
@@ -530,7 +531,7 @@
 		return;
 
 	/* Round-robin assign a CPU to each enabled source. */
-	mtx_lock(&intr_table_lock);
+	sx_xlock(&intrsrc_lock);
 	assign_cpu = 1;
 	for (i = 0; i < NUM_IO_INTS; i++) {
 		isrc = interrupt_sources[i];
@@ -551,7 +552,7 @@
 
 		}
 	}
-	mtx_unlock(&intr_table_lock);
+	sx_xunlock(&intrsrc_lock);
 }
 SYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
     NULL);
@@ -565,11 +566,4 @@
 
 	return (PCPU_GET(apic_id));
 }
-
-/* Use an empty stub for compatibility. */
-void
-intr_add_cpu(u_int cpu __unused)
-{
-
-}
 #endif

Modified: trunk/sys/x86/x86/io_apic.c
===================================================================
--- trunk/sys/x86/x86/io_apic.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/io_apic.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -28,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/io_apic.c 330959 2018-03-14 23:59:52Z marius $");
 
 #include "opt_isa.h"
 
@@ -119,7 +117,7 @@
 static int	ioapic_source_pending(struct intsrc *isrc);
 static int	ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
 		    enum intr_polarity pol);
-static void	ioapic_resume(struct pic *pic);
+static void	ioapic_resume(struct pic *pic, bool suspend_cancelled);
 static int	ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
 static void	ioapic_program_intpin(struct ioapic_intsrc *intpin);
 
@@ -255,7 +253,7 @@
 ioapic_program_intpin(struct ioapic_intsrc *intpin)
 {
 	struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
-	uint32_t low, high, value;
+	uint32_t low, high;
 
 	/*
 	 * If a pin is completely invalid or if it is valid but hasn't
@@ -273,7 +271,11 @@
 		return;
 	}
 
-	/* Set the destination. */
+	/*
+	 * Set the destination.  Note that with Intel interrupt remapping,
+	 * the previously reserved bits 55:48 now have a purpose so ensure
+	 * these are zero.
+	 */
 	low = IOART_DESTPHY;
 	high = intpin->io_cpu << APIC_ID_SHIFT;
 
@@ -311,12 +313,9 @@
 	}
 
 	/* Write the values to the APIC. */
+	ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), high);
 	intpin->io_lowreg = low;
 	ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
-	value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
-	value &= ~IOART_DEST;
-	value |= high;
-	ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
 }
 
 static int
@@ -328,6 +327,18 @@
 	u_int old_id;
 
 	/*
+	 * On Hyper-V:
+	 * - Stick to the first cpu for all I/O APIC pins.
+	 * - And don't allow destination cpu changes.
+	 */
+	if (vm_guest == VM_GUEST_HV) {
+		if (intpin->io_vector)
+			return (EINVAL);
+		else
+			apic_id = 0;
+	}
+
+	/*
 	 * keep 1st core as the destination for NMI
 	 */
 	if (intpin->io_irq == IRQ_NMI)
@@ -486,7 +497,7 @@
 }
 
 static void
-ioapic_resume(struct pic *pic)
+ioapic_resume(struct pic *pic, bool suspend_cancelled)
 {
 	struct ioapic *io = (struct ioapic *)pic;
 	int i;
@@ -795,11 +806,18 @@
 	    io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
 	    io->io_intbase + io->io_numintr - 1);
 
-	/* Register valid pins as interrupt sources. */
+	/*
+	 * Reprogram pins to handle special case pins (such as NMI and
+	 * SMI) and register valid pins as interrupt sources.
+	 */
 	intr_register_pic(&io->io_pic);
-	for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
+	for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
+		mtx_lock_spin(&icu_lock);
+		ioapic_program_intpin(pin);
+		mtx_unlock_spin(&icu_lock);
 		if (pin->io_irq < NUM_IO_INTS)
 			intr_register_source(&pin->io_intsrc);
+	}
 }
 
 /* A simple new-bus driver to consume PCI I/O APIC devices. */
@@ -922,3 +940,99 @@
 
 static devclass_t apic_devclass;
 DRIVER_MODULE(apic, nexus, apic_driver, apic_devclass, 0, 0);
+
+#include "opt_ddb.h"
+
+#ifdef DDB
+#include <ddb/ddb.h>
+
+static const char *
+ioapic_delivery_mode(uint32_t mode)
+{
+
+	switch (mode) {
+	case IOART_DELFIXED:
+		return ("fixed");
+	case IOART_DELLOPRI:
+		return ("lowestpri");
+	case IOART_DELSMI:
+		return ("SMI");
+	case IOART_DELRSV1:
+		return ("rsrvd1");
+	case IOART_DELNMI:
+		return ("NMI");
+	case IOART_DELINIT:
+		return ("INIT");
+	case IOART_DELRSV2:
+		return ("rsrvd2");
+	case IOART_DELEXINT:
+		return ("ExtINT");
+	default:
+		return ("");
+	}
+}
+
+static u_int
+db_ioapic_read(volatile ioapic_t *apic, int reg)
+{
+
+	apic->ioregsel = reg;
+	return (apic->iowin);
+}
+
+static void
+db_show_ioapic_one(volatile ioapic_t *io_addr)
+{
+	uint32_t r, lo, hi;
+	int mre, i;
+
+	r = db_ioapic_read(io_addr, IOAPIC_VER);
+	mre = (r & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT;
+	db_printf("Id 0x%08x Ver 0x%02x MRE %d\n",
+	    db_ioapic_read(io_addr, IOAPIC_ID), r & IOART_VER_VERSION, mre);
+	for (i = 0; i < mre; i++) {
+		lo = db_ioapic_read(io_addr, IOAPIC_REDTBL_LO(i));
+		hi = db_ioapic_read(io_addr, IOAPIC_REDTBL_HI(i));
+		db_printf("  pin %d Dest %s/%x %smasked Trig %s RemoteIRR %d "
+		    "Polarity %s Status %s DeliveryMode %s Vec %d\n", i,
+		    (lo & IOART_DESTMOD) == IOART_DESTLOG ? "log" : "phy",
+		    (hi & IOART_DEST) >> 24,
+		    (lo & IOART_INTMASK) == IOART_INTMSET ? "" : "not",
+		    (lo & IOART_TRGRMOD) == IOART_TRGRLVL ? "lvl" : "edge",
+		    (lo & IOART_REM_IRR) == IOART_REM_IRR ? 1 : 0,
+		    (lo & IOART_INTPOL) == IOART_INTALO ? "low" : "high",
+		    (lo & IOART_DELIVS) == IOART_DELIVS ? "pend" : "idle",
+		    ioapic_delivery_mode(lo & IOART_DELMOD),
+		    (lo & IOART_INTVEC));
+	  }
+}
+
+DB_SHOW_COMMAND(ioapic, db_show_ioapic)
+{
+	struct ioapic *ioapic;
+	int idx, i;
+
+	if (!have_addr) {
+		db_printf("usage: show ioapic index\n");
+		return;
+	}
+
+	idx = (int)addr;
+	i = 0;
+	STAILQ_FOREACH(ioapic, &ioapic_list, io_next) {
+		if (idx == i) {
+			db_show_ioapic_one(ioapic->io_addr);
+			break;
+		}
+		i++;
+	}
+}
+
+DB_SHOW_ALL_COMMAND(ioapics, db_show_all_ioapics)
+{
+	struct ioapic *ioapic;
+
+	STAILQ_FOREACH(ioapic, &ioapic_list, io_next)
+		db_show_ioapic_one(ioapic->io_addr);
+}
+#endif

Added: trunk/sys/x86/x86/legacy.c
===================================================================
--- trunk/sys/x86/x86/legacy.c	                        (rev 0)
+++ trunk/sys/x86/x86/legacy.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,373 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright 1998 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ */
+
+#ifdef __i386__
+#include "opt_eisa.h"
+#include "opt_mca.h"
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/legacy.c 233707 2012-03-30 19:10:14Z jhb $");
+
+/*
+ * This code implements a system driver for legacy systems that do not
+ * support ACPI or when ACPI support is not present in the kernel.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+#include <sys/smp.h>
+
+#ifdef DEV_MCA
+#include <i386/bios/mca_machdep.h>
+#endif
+
+#include <machine/clock.h>
+#include <machine/resource.h>
+#include <x86/legacyvar.h>
+
+static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device");
+struct legacy_device {
+	int	lg_pcibus;
+	int	lg_pcislot;
+	int	lg_pcifunc;
+};
+
+#define DEVTOAT(dev)	((struct legacy_device *)device_get_ivars(dev))
+
+static	int legacy_probe(device_t);
+static	int legacy_attach(device_t);
+static	int legacy_print_child(device_t, device_t);
+static device_t legacy_add_child(device_t bus, u_int order, const char *name,
+				int unit);
+static	int legacy_read_ivar(device_t, device_t, int, uintptr_t *);
+static	int legacy_write_ivar(device_t, device_t, int, uintptr_t);
+
+static device_method_t legacy_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		legacy_probe),
+	DEVMETHOD(device_attach,	legacy_attach),
+	DEVMETHOD(device_detach,	bus_generic_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_print_child,	legacy_print_child),
+	DEVMETHOD(bus_add_child,	legacy_add_child),
+	DEVMETHOD(bus_read_ivar,	legacy_read_ivar),
+	DEVMETHOD(bus_write_ivar,	legacy_write_ivar),
+	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
+	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
+	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+
+	{ 0, 0 }
+};
+
+static driver_t legacy_driver = {
+	"legacy",
+	legacy_methods,
+	1,			/* no softc */
+};
+static devclass_t legacy_devclass;
+
+DRIVER_MODULE(legacy, nexus, legacy_driver, legacy_devclass, 0, 0);
+
+static int
+legacy_probe(device_t dev)
+{
+
+	device_set_desc(dev, "legacy system");
+	device_quiet(dev);
+	return (0);
+}
+
+static int
+legacy_attach(device_t dev)
+{
+	device_t child;
+
+	/*
+	 * Let our child drivers identify any child devices that they
+	 * can find.  Once that is done attach any devices that we
+	 * found.
+	 */
+	bus_generic_probe(dev);
+	bus_generic_attach(dev);
+
+	/*
+	 * If we didn't see EISA or ISA on a pci bridge, create some
+	 * connection points now so they show up "on motherboard".
+	 */
+#ifdef DEV_EISA
+	if (!devclass_get_device(devclass_find("eisa"), 0)) {
+		child = BUS_ADD_CHILD(dev, 0, "eisa", 0);
+		if (child == NULL)
+			panic("legacy_attach eisa");
+		device_probe_and_attach(child);
+	}
+#endif
+#ifdef DEV_MCA
+	if (MCA_system && !devclass_get_device(devclass_find("mca"), 0)) {
+        	child = BUS_ADD_CHILD(dev, 0, "mca", 0);
+        	if (child == 0)
+                	panic("legacy_probe mca");
+		device_probe_and_attach(child);
+	}
+#endif
+	if (!devclass_get_device(devclass_find("isa"), 0)) {
+		child = BUS_ADD_CHILD(dev, 0, "isa", 0);
+		if (child == NULL)
+			panic("legacy_attach isa");
+		device_probe_and_attach(child);
+	}
+
+	return 0;
+}
+
+static int
+legacy_print_child(device_t bus, device_t child)
+{
+	struct legacy_device *atdev = DEVTOAT(child);
+	int retval = 0;
+
+	retval += bus_print_child_header(bus, child);
+	if (atdev->lg_pcibus != -1)
+		retval += printf(" pcibus %d", atdev->lg_pcibus);
+	retval += printf(" on motherboard\n");	/* XXX "motherboard", ick */
+
+	return (retval);
+}
+
+static device_t
+legacy_add_child(device_t bus, u_int order, const char *name, int unit)
+{
+	device_t child;
+	struct legacy_device *atdev;
+
+	atdev = malloc(sizeof(struct legacy_device), M_LEGACYDEV,
+	    M_NOWAIT | M_ZERO);
+	if (atdev == NULL)
+		return(NULL);
+	atdev->lg_pcibus = -1;
+	atdev->lg_pcislot = -1;
+	atdev->lg_pcifunc = -1;
+
+	child = device_add_child_ordered(bus, order, name, unit);
+	if (child == NULL)
+		free(atdev, M_LEGACYDEV);
+	else
+		/* should we free this in legacy_child_detached? */
+		device_set_ivars(child, atdev);
+
+	return (child);
+}
+
+static int
+legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+	struct legacy_device *atdev = DEVTOAT(child);
+
+	switch (which) {
+	case LEGACY_IVAR_PCIDOMAIN:
+		*result = 0;
+		break;
+	case LEGACY_IVAR_PCIBUS:
+		*result = atdev->lg_pcibus;
+		break;
+	case LEGACY_IVAR_PCISLOT:
+		*result = atdev->lg_pcislot;
+		break;
+	case LEGACY_IVAR_PCIFUNC:
+		*result = atdev->lg_pcifunc;
+		break;
+	default:
+		return ENOENT;
+	}
+	return 0;
+}
+	
+
+static int
+legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+	struct legacy_device *atdev = DEVTOAT(child);
+
+	switch (which) {
+	case LEGACY_IVAR_PCIDOMAIN:
+		return EINVAL;
+	case LEGACY_IVAR_PCIBUS:
+		atdev->lg_pcibus = value;
+		break;
+	case LEGACY_IVAR_PCISLOT:
+		atdev->lg_pcislot = value;
+		break;
+	case LEGACY_IVAR_PCIFUNC:
+		atdev->lg_pcifunc = value;
+		break;
+	default:
+		return ENOENT;
+	}
+	return 0;
+}
+
+/*
+ * Legacy CPU attachment when ACPI is not available.  Drivers like
+ * cpufreq(4) hang off this.
+ */
+static void	cpu_identify(driver_t *driver, device_t parent);
+static int	cpu_read_ivar(device_t dev, device_t child, int index,
+		    uintptr_t *result);
+static device_t cpu_add_child(device_t bus, u_int order, const char *name,
+		    int unit);
+static struct resource_list *cpu_get_rlist(device_t dev, device_t child);
+
+struct cpu_device {
+	struct resource_list cd_rl;
+	struct pcpu *cd_pcpu;
+};
+
+static device_method_t cpu_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_identify,	cpu_identify),
+	DEVMETHOD(device_probe,		bus_generic_probe),
+	DEVMETHOD(device_attach,	bus_generic_attach),
+	DEVMETHOD(device_detach,	bus_generic_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_add_child,	cpu_add_child),
+	DEVMETHOD(bus_read_ivar,	cpu_read_ivar),
+	DEVMETHOD(bus_get_resource_list, cpu_get_rlist),
+	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
+	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
+	DEVMETHOD(bus_alloc_resource,	bus_generic_rl_alloc_resource),
+	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
+	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+
+	DEVMETHOD_END
+};
+
+static driver_t cpu_driver = {
+	"cpu",
+	cpu_methods,
+	1,		/* no softc */
+};
+static devclass_t cpu_devclass;
+DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0);
+
+static void
+cpu_identify(driver_t *driver, device_t parent)
+{
+	device_t child;
+	int i;
+
+	/*
+	 * Attach a cpuX device for each CPU.  We use an order of 150
+	 * so that these devices are attached after the Host-PCI
+	 * bridges (which are added at order 100).
+	 */
+	CPU_FOREACH(i) {
+		child = BUS_ADD_CHILD(parent, 150, "cpu", i);
+		if (child == NULL)
+			panic("legacy_attach cpu");
+	}
+}
+
+static device_t
+cpu_add_child(device_t bus, u_int order, const char *name, int unit)
+{
+	struct cpu_device *cd;
+	device_t child;
+	struct pcpu *pc;
+
+	if ((cd = malloc(sizeof(*cd), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL)
+		return (NULL);
+
+	resource_list_init(&cd->cd_rl);
+	pc = pcpu_find(device_get_unit(bus));
+	cd->cd_pcpu = pc;
+
+	child = device_add_child_ordered(bus, order, name, unit);
+	if (child != NULL) {
+		pc->pc_device = child;
+		device_set_ivars(child, cd);
+	} else
+		free(cd, M_DEVBUF);
+	return (child);
+}
+
+static struct resource_list *
+cpu_get_rlist(device_t dev, device_t child)
+{
+	struct cpu_device *cpdev;
+
+	cpdev = device_get_ivars(child);
+	return (&cpdev->cd_rl);
+}
+
+static int
+cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+	struct cpu_device *cpdev;
+
+	switch (index) {
+	case CPU_IVAR_PCPU:
+		cpdev = device_get_ivars(child);
+		*result = (uintptr_t)cpdev->cd_pcpu;
+		break;
+	case CPU_IVAR_NOMINAL_MHZ:
+		if (tsc_is_invariant) {
+			*result = (uintptr_t)(atomic_load_acq_64(&tsc_freq) /
+			    1000000);
+			break;
+		}
+		/* FALLTHROUGH */
+	default:
+		return (ENOENT);
+	}
+	return (0);
+}


Property changes on: trunk/sys/x86/x86/legacy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/x86/x86/local_apic.c
===================================================================
--- trunk/sys/x86/x86/local_apic.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/local_apic.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * Copyright (c) 1996, by Steve Passe
@@ -32,8 +33,9 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/local_apic.c 314662 2017-03-04 12:04:24Z avg $");
 
+#include "opt_atpic.h"
 #include "opt_hwpmc_hooks.h"
 #include "opt_kdtrace.h"
 
@@ -55,7 +57,7 @@
 #include <vm/pmap.h>
 
 #include <x86/apicreg.h>
-#include <machine/cpu.h>
+#include <machine/clock.h>
 #include <machine/cputypes.h>
 #include <machine/frame.h>
 #include <machine/intr_machdep.h>
@@ -90,6 +92,7 @@
 #define	IRQ_TIMER	(NUM_IO_INTS + 1)
 #define	IRQ_SYSCALL	(NUM_IO_INTS + 2)
 #define	IRQ_DTRACE_RET	(NUM_IO_INTS + 3)
+#define	IRQ_EVTCHN	(NUM_IO_INTS + 4)
 
 /*
  * Support for local APICs.  Local APICs manage interrupts on each
@@ -110,7 +113,7 @@
 };
 
 struct lapic {
-	struct lvt la_lvts[LVT_MAX + 1];
+	struct lvt la_lvts[APIC_LVT_MAX + 1];
 	u_int la_id:8;
 	u_int la_cluster:4;
 	u_int la_cluster_id:2;
@@ -118,12 +121,13 @@
 	u_long *la_timer_count;
 	u_long la_timer_period;
 	u_int la_timer_mode;
+	uint32_t lvt_timer_cache;
 	/* Include IDT_SYSCALL to make indexing easier. */
 	int la_ioint_irqs[APIC_NUM_IOINTS + 1];
 } static lapics[MAX_APIC_ID + 1];
 
 /* Global defaults for local APIC LVT entries. */
-static struct lvt lvts[LVT_MAX + 1] = {
+static struct lvt lvts[APIC_LVT_MAX + 1] = {
 	{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 },	/* LINT0: masked ExtINT */
 	{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 },	/* LINT1: NMI */
 	{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT },	/* Timer */
@@ -156,16 +160,21 @@
 vm_paddr_t lapic_paddr;
 static u_long lapic_timer_divisor;
 static struct eventtimer lapic_et;
+#ifdef SMP
+static uint64_t lapic_ipi_wait_mult;
+#endif
 
 static void	lapic_enable(void);
-static void	lapic_resume(struct pic *pic);
-static void	lapic_timer_oneshot(u_int count, int enable_int);
-static void	lapic_timer_periodic(u_int count, int enable_int);
-static void	lapic_timer_stop(void);
+static void	lapic_resume(struct pic *pic, bool suspend_cancelled);
+static void	lapic_timer_oneshot(struct lapic *,
+		    u_int count, int enable_int);
+static void	lapic_timer_periodic(struct lapic *,
+		    u_int count, int enable_int);
+static void	lapic_timer_stop(struct lapic *);
 static void	lapic_timer_set_divisor(u_int divisor);
 static uint32_t	lvt_mode(struct lapic *la, u_int pin, uint32_t value);
 static int	lapic_et_start(struct eventtimer *et,
-    struct bintime *first, struct bintime *period);
+    sbintime_t first, sbintime_t period);
 static int	lapic_et_stop(struct eventtimer *et);
 
 struct pic lapic_pic = { .pic_resume = lapic_resume };
@@ -175,7 +184,7 @@
 {
 	struct lvt *lvt;
 
-	KASSERT(pin <= LVT_MAX, ("%s: pin %u out of range", __func__, pin));
+	KASSERT(pin <= APIC_LVT_MAX, ("%s: pin %u out of range", __func__, pin));
 	if (la->la_lvts[pin].lvt_active)
 		lvt = &la->la_lvts[pin];
 	else
@@ -198,7 +207,7 @@
 		if (!lvt->lvt_edgetrigger) {
 			printf("lapic%u: Forcing LINT%u to edge trigger\n",
 			    la->la_id, pin);
-			value |= APIC_LVT_TM;
+			value &= ~APIC_LVT_TM;
 		}
 		/* Use a vector of 0. */
 		break;
@@ -217,6 +226,9 @@
 void
 lapic_init(vm_paddr_t addr)
 {
+#ifdef SMP
+	uint64_t r, r1, r2, rx;
+#endif
 	u_int regs[4];
 	int i, arat;
 
@@ -264,15 +276,45 @@
 		}
 		lapic_et.et_frequency = 0;
 		/* We don't know frequency yet, so trying to guess. */
-		lapic_et.et_min_period.sec = 0;
-		lapic_et.et_min_period.frac = 0x00001000LL << 32;
-		lapic_et.et_max_period.sec = 1;
-		lapic_et.et_max_period.frac = 0;
+		lapic_et.et_min_period = 0x00001000LL;
+		lapic_et.et_max_period = SBT_1S;
 		lapic_et.et_start = lapic_et_start;
 		lapic_et.et_stop = lapic_et_stop;
 		lapic_et.et_priv = NULL;
 		et_register(&lapic_et);
 	}
+
+#ifdef SMP
+#define	LOOPS	100000
+	/*
+	 * Calibrate the busy loop waiting for IPI ack in xAPIC mode.
+	 * lapic_ipi_wait_mult contains the number of iterations which
+	 * approximately delay execution for 1 microsecond (the
+	 * argument to native_lapic_ipi_wait() is in microseconds).
+	 *
+	 * We assume that TSC is present and already measured.
+	 * Possible TSC frequency jumps are irrelevant to the
+	 * calibration loop below, the CPU clock management code is
+	 * not yet started, and we do not enter sleep states.
+	 */
+	KASSERT((cpu_feature & CPUID_TSC) != 0 && tsc_freq != 0,
+	    ("TSC not initialized"));
+	r = rdtsc();
+	for (rx = 0; rx < LOOPS; rx++) {
+		(void)lapic->icr_lo;
+		ia32_pause();
+	}
+	r = rdtsc() - r;
+	r1 = tsc_freq * LOOPS;
+	r2 = r * 1000000;
+	lapic_ipi_wait_mult = r1 >= r2 ? r1 / r2 : 1;
+	if (bootverbose) {
+		printf("LAPIC: ipi_wait() us multiplier %ju (r %ju tsc %ju)\n",
+		    (uintmax_t)lapic_ipi_wait_mult, (uintmax_t)r,
+		    (uintmax_t)tsc_freq);
+	}
+#undef LOOPS
+#endif /* SMP */
 }
 
 /*
@@ -298,7 +340,7 @@
 	 */
 	lapics[apic_id].la_present = 1;
 	lapics[apic_id].la_id = apic_id;
-	for (i = 0; i <= LVT_MAX; i++) {
+	for (i = 0; i <= APIC_LVT_MAX; i++) {
 		lapics[apic_id].la_lvts[i] = lvts[i];
 		lapics[apic_id].la_lvts[i].lvt_active = 0;
 	}
@@ -308,8 +350,12 @@
 	lapics[apic_id].la_ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] =
 	    IRQ_TIMER;
 #ifdef KDTRACE_HOOKS
-	lapics[apic_id].la_ioint_irqs[IDT_DTRACE_RET - APIC_IO_INTS] = IRQ_DTRACE_RET;
+	lapics[apic_id].la_ioint_irqs[IDT_DTRACE_RET - APIC_IO_INTS] =
+	    IRQ_DTRACE_RET;
 #endif
+#ifdef XENHVM
+	lapics[apic_id].la_ioint_irqs[IDT_EVTCHN - APIC_IO_INTS] = IRQ_EVTCHN;
+#endif
 
 
 #ifdef SMP
@@ -333,10 +379,10 @@
 	    lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
 	printf("  timer: 0x%08x therm: 0x%08x err: 0x%08x",
 	    lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error);
-	if (maxlvt >= LVT_PMC)
+	if (maxlvt >= APIC_LVT_PMC)
 		printf(" pmc: 0x%08x", lapic->lvt_pcint);
 	printf("\n");
-	if (maxlvt >= LVT_CMCI)
+	if (maxlvt >= APIC_LVT_CMCI)
 		printf("   cmci: 0x%08x\n", lapic->lvt_cmci);
 }
 
@@ -360,15 +406,16 @@
 	lapic_enable();
 
 	/* Program LINT[01] LVT entries. */
-	lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
-	lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
+	lapic->lvt_lint0 = lvt_mode(la, APIC_LVT_LINT0, lapic->lvt_lint0);
+	lapic->lvt_lint1 = lvt_mode(la, APIC_LVT_LINT1, lapic->lvt_lint1);
 
 	/* Program the PMC LVT entry if present. */
-	if (maxlvt >= LVT_PMC)
-		lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
+	if (maxlvt >= APIC_LVT_PMC)
+		lapic->lvt_pcint = lvt_mode(la, APIC_LVT_PMC, lapic->lvt_pcint);
 
 	/* Program timer LVT and setup handler. */
-	lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
+	la->lvt_timer_cache = lapic->lvt_timer =
+	    lvt_mode(la, APIC_LVT_TIMER, lapic->lvt_timer);
 	if (boot) {
 		snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
 		intrcnt_add(buf, &la->la_timer_count);
@@ -380,21 +427,21 @@
 		    lapic_id()));
 		lapic_timer_set_divisor(lapic_timer_divisor);
 		if (la->la_timer_mode == 1)
-			lapic_timer_periodic(la->la_timer_period, 1);
+			lapic_timer_periodic(la, la->la_timer_period, 1);
 		else
-			lapic_timer_oneshot(la->la_timer_period, 1);
+			lapic_timer_oneshot(la, la->la_timer_period, 1);
 	}
 
 	/* Program error LVT and clear any existing errors. */
-	lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
+	lapic->lvt_error = lvt_mode(la, APIC_LVT_ERROR, lapic->lvt_error);
 	lapic->esr = 0;
 
 	/* XXX: Thermal LVT */
 
 	/* Program the CMCI LVT entry if present. */
-	if (maxlvt >= LVT_CMCI)
-		lapic->lvt_cmci = lvt_mode(la, LVT_CMCI, lapic->lvt_cmci);
-	    
+	if (maxlvt >= APIC_LVT_CMCI)
+		lapic->lvt_cmci = lvt_mode(la, APIC_LVT_CMCI, lapic->lvt_cmci);
+
 	intr_restore(saveintr);
 }
 
@@ -417,7 +464,7 @@
 	struct lapic *la;
 
 	la = &lapics[lapic_id()];
-	lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
+	lapic->lvt_pcint = lvt_mode(la, APIC_LVT_PMC, lapic->lvt_pcint);
 }
 #endif
 
@@ -433,10 +480,10 @@
 
 	/* Fail if the PMC LVT is not present. */
 	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
-	if (maxlvt < LVT_PMC)
+	if (maxlvt < APIC_LVT_PMC)
 		return (0);
 
-	lvts[LVT_PMC].lvt_masked = 0;
+	lvts[APIC_LVT_PMC].lvt_masked = 0;
 
 #ifdef SMP
 	/*
@@ -467,10 +514,10 @@
 
 	/* Fail if the PMC LVT is not present. */
 	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
-	if (maxlvt < LVT_PMC)
+	if (maxlvt < APIC_LVT_PMC)
 		return;
 
-	lvts[LVT_PMC].lvt_masked = 1;
+	lvts[APIC_LVT_PMC].lvt_masked = 1;
 
 #ifdef SMP
 	/* The APs should always be started when hwpmc is unloaded. */
@@ -481,12 +528,12 @@
 }
 
 static int
-lapic_et_start(struct eventtimer *et,
-    struct bintime *first, struct bintime *period)
+lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
 {
 	struct lapic *la;
 	u_long value;
 
+	la = &lapics[PCPU_GET(apic_id)];
 	if (et->et_frequency == 0) {
 		/* Start off with a divisor of 2 (power on reset default). */
 		lapic_timer_divisor = 2;
@@ -493,7 +540,7 @@
 		/* Try to calibrate the local APIC timer. */
 		do {
 			lapic_timer_set_divisor(lapic_timer_divisor);
-			lapic_timer_oneshot(APIC_TIMER_MAX_COUNT, 0);
+			lapic_timer_oneshot(la, APIC_TIMER_MAX_COUNT, 0);
 			DELAY(1000000);
 			value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
 			if (value != APIC_TIMER_MAX_COUNT)
@@ -506,29 +553,19 @@
 			printf("lapic: Divisor %lu, Frequency %lu Hz\n",
 			    lapic_timer_divisor, value);
 		et->et_frequency = value;
-		et->et_min_period.sec = 0;
-		et->et_min_period.frac =
-		    ((0x00000002LLU << 32) / et->et_frequency) << 32;
-		et->et_max_period.sec = 0xfffffffeLLU / et->et_frequency;
-		et->et_max_period.frac =
-		    ((0xfffffffeLLU << 32) / et->et_frequency) << 32;
+		et->et_min_period = (0x00000002LLU << 32) / et->et_frequency;
+		et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency;
 	}
-	lapic_timer_set_divisor(lapic_timer_divisor);
-	la = &lapics[lapic_id()];
-	if (period != NULL) {
+	if (la->la_timer_mode == 0)
+		lapic_timer_set_divisor(lapic_timer_divisor);
+	if (period != 0) {
 		la->la_timer_mode = 1;
-		la->la_timer_period =
-		    (et->et_frequency * (period->frac >> 32)) >> 32;
-		if (period->sec != 0)
-			la->la_timer_period += et->et_frequency * period->sec;
-		lapic_timer_periodic(la->la_timer_period, 1);
+		la->la_timer_period = ((uint32_t)et->et_frequency * period) >> 32;
+		lapic_timer_periodic(la, la->la_timer_period, 1);
 	} else {
 		la->la_timer_mode = 2;
-		la->la_timer_period =
-		    (et->et_frequency * (first->frac >> 32)) >> 32;
-		if (first->sec != 0)
-			la->la_timer_period += et->et_frequency * first->sec;
-		lapic_timer_oneshot(la->la_timer_period, 1);
+		la->la_timer_period = ((uint32_t)et->et_frequency * first) >> 32;
+		lapic_timer_oneshot(la, la->la_timer_period, 1);
 	}
 	return (0);
 }
@@ -536,10 +573,10 @@
 static int
 lapic_et_stop(struct eventtimer *et)
 {
-	struct lapic *la = &lapics[lapic_id()];
+	struct lapic *la = &lapics[PCPU_GET(apic_id)];
 
 	la->la_timer_mode = 0;
-	lapic_timer_stop();
+	lapic_timer_stop(la);
 	return (0);
 }
 
@@ -568,7 +605,7 @@
 
 /* Reset the local APIC on the BSP during resume. */
 static void
-lapic_resume(struct pic *pic)
+lapic_resume(struct pic *pic, bool suspend_cancelled)
 {
 
 	lapic_setup(0);
@@ -620,7 +657,7 @@
 lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
 {
 
-	if (pin > LVT_MAX)
+	if (pin > APIC_LVT_MAX)
 		return (EINVAL);
 	if (apic_id == APIC_ID_ALL) {
 		lvts[pin].lvt_masked = masked;
@@ -644,7 +681,7 @@
 {
 	struct lvt *lvt;
 
-	if (pin > LVT_MAX)
+	if (pin > APIC_LVT_MAX)
 		return (EINVAL);
 	if (apic_id == APIC_ID_ALL) {
 		lvt = &lvts[pin];
@@ -699,7 +736,7 @@
 lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
 {
 
-	if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM)
+	if (pin > APIC_LVT_MAX || pol == INTR_POLARITY_CONFORM)
 		return (EINVAL);
 	if (apic_id == APIC_ID_ALL) {
 		lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH);
@@ -724,7 +761,7 @@
 lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
 {
 
-	if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
+	if (pin > APIC_LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
 		return (EINVAL);
 	if (apic_id == APIC_ID_ALL) {
 		lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
@@ -795,7 +832,7 @@
 	 * Don't do any accounting for the disabled HTT cores, since it
 	 * will provide misleading numbers for the userland.
 	 *
-	 * No locking is necessary here, since even if we loose the race
+	 * No locking is necessary here, since even if we lose the race
 	 * when hlt_cpus_mask changes it is not a big deal, really.
 	 *
 	 * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask
@@ -833,11 +870,11 @@
 }
 
 static void
-lapic_timer_oneshot(u_int count, int enable_int)
+lapic_timer_oneshot(struct lapic *la, u_int count, int enable_int)
 {
 	u_int32_t value;
 
-	value = lapic->lvt_timer;
+	value = la->lvt_timer_cache;
 	value &= ~APIC_LVTT_TM;
 	value |= APIC_LVTT_TM_ONE_SHOT;
 	if (enable_int)
@@ -847,11 +884,11 @@
 }
 
 static void
-lapic_timer_periodic(u_int count, int enable_int)
+lapic_timer_periodic(struct lapic *la, u_int count, int enable_int)
 {
 	u_int32_t value;
 
-	value = lapic->lvt_timer;
+	value = la->lvt_timer_cache;
 	value &= ~APIC_LVTT_TM;
 	value |= APIC_LVTT_TM_PERIODIC;
 	if (enable_int)
@@ -861,11 +898,11 @@
 }
 
 static void
-lapic_timer_stop(void)
+lapic_timer_stop(struct lapic *la)
 {
 	u_int32_t value;
 
-	value = lapic->lvt_timer;
+	value = la->lvt_timer_cache;
 	value &= ~APIC_LVTT_TM;
 	value |= APIC_LVT_M;
 	lapic->lvt_timer = value;
@@ -890,11 +927,15 @@
 {
 	u_int apic_id;
 
+#ifdef DEV_ATPIC
+	if (lapic == NULL)
+		return;
+#endif
 	apic_id = PCPU_GET(apic_id);
 	KASSERT(lapics[apic_id].la_present,
 	    ("%s: missing APIC %u", __func__, apic_id));
-	lapics[apic_id].la_lvts[LVT_CMCI].lvt_masked = 0;
-	lapics[apic_id].la_lvts[LVT_CMCI].lvt_active = 1;
+	lapics[apic_id].la_lvts[APIC_LVT_CMCI].lvt_masked = 0;
+	lapics[apic_id].la_lvts[APIC_LVT_CMCI].lvt_active = 1;
 	if (bootverbose)
 		printf("lapic%u: CMCI unmasked\n", apic_id);
 }
@@ -1139,6 +1180,10 @@
 			if (irq == IRQ_DTRACE_RET)
 				continue;
 #endif
+#ifdef XENHVM
+			if (irq == IRQ_EVTCHN)
+				continue;
+#endif
 			db_printf("vec 0x%2x -> ", i + APIC_IO_INTS);
 			if (irq == IRQ_TIMER)
 				db_printf("lapic timer\n");
@@ -1258,9 +1303,6 @@
 apic_init(void *dummy __unused)
 {
 	struct apic_enumerator *enumerator;
-#ifndef __amd64__
-	uint64_t apic_base;
-#endif
 	int retval, best;
 
 	/* We only support built in local APICs. */
@@ -1286,6 +1328,9 @@
 	if (best_enum == NULL) {
 		if (bootverbose)
 			printf("APIC: Could not find any APICs.\n");
+#ifndef DEV_ATPIC
+		panic("running without device atpic requires a local APIC");
+#endif
 		return;
 	}
 
@@ -1293,18 +1338,13 @@
 		printf("APIC: Using the %s enumerator.\n",
 		    best_enum->apic_name);
 
-#ifndef __amd64__
+#ifdef I686_CPU
 	/*
 	 * To work around an errata, we disable the local APIC on some
 	 * CPUs during early startup.  We need to turn the local APIC back
 	 * on on such CPUs now.
 	 */
-	if (cpu == CPU_686 && cpu_vendor_id == CPU_VENDOR_INTEL &&
-	    (cpu_id & 0xff0) == 0x610) {
-		apic_base = rdmsr(MSR_APICBASE);
-		apic_base |= APICBASE_ENABLED;
-		wrmsr(MSR_APICBASE, apic_base);
-	}
+	ppro_reenable_apic();
 #endif
 
 	/* Probe the CPU's in the system. */
@@ -1324,7 +1364,7 @@
 apic_setup_local(void *dummy __unused)
 {
 	int retval;
- 
+
 	if (best_enum == NULL)
 		return;
 
@@ -1381,22 +1421,17 @@
  * private to the MD code.  The public interface for the rest of the
  * kernel is defined in mp_machdep.c.
  */
+
+/*
+ * Wait delay microseconds for IPI to be sent.  If delay is -1, we
+ * wait forever.
+ */
 int
 lapic_ipi_wait(int delay)
 {
-	int x, incr;
+	uint64_t rx;
 
-	/*
-	 * Wait delay loops for IPI to be sent.  This is highly bogus
-	 * since this is sensitive to CPU clock speed.  If delay is
-	 * -1, we wait forever.
-	 */
-	if (delay == -1) {
-		incr = 0;
-		delay = 1;
-	} else
-		incr = 1;
-	for (x = 0; x < delay; x += incr) {
+	for (rx = 0; delay == -1 || rx < lapic_ipi_wait_mult * delay; rx++) {
 		if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE)
 			return (1);
 		ia32_pause();
@@ -1433,9 +1468,9 @@
 	intr_restore(saveintr);
 }
 
-#define	BEFORE_SPIN	1000000
+#define	BEFORE_SPIN	50000
 #ifdef DETECT_DEADLOCK
-#define	AFTER_SPIN	1000
+#define	AFTER_SPIN	50
 #endif
 
 void
@@ -1446,7 +1481,7 @@
 	KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
 	    ("%s: invalid vector %d", __func__, vector));
 
-	icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE;
+	icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT;
 
 	/*
 	 * IPI_STOP_HARD is just a "fake" vector used to send a NMI.
@@ -1454,9 +1489,9 @@
 	 * the vector.
 	 */
 	if (vector == IPI_STOP_HARD)
-		icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT;
+		icrlo |= APIC_DELMODE_NMI;
 	else
-		icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT;
+		icrlo |= vector | APIC_DELMODE_FIXED;
 	destfield = 0;
 	switch (dest) {
 	case APIC_IPI_DEST_SELF:

Modified: trunk/sys/x86/x86/mca.c
===================================================================
--- trunk/sys/x86/x86/mca.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/mca.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
  * Written by: John H. Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
  *
@@ -30,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/mca.c 314667 2017-03-04 13:03:31Z avg $");
 
 #ifdef __amd64__
 #define	DEV_APIC
@@ -53,6 +54,7 @@
 #include <sys/taskqueue.h>
 #include <machine/intr_machdep.h>
 #include <machine/apicvar.h>
+#include <machine/cpu.h>
 #include <machine/cputypes.h>
 #include <x86/mca.h>
 #include <machine/md_var.h>
@@ -72,7 +74,7 @@
  */
 struct cmc_state {
 	int	max_threshold;
-	int	last_intr;
+	time_t	last_intr;
 };
 #endif
 
@@ -84,7 +86,7 @@
 
 static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture");
 
-static int mca_count;		/* Number of records stored. */
+static volatile int mca_count;	/* Number of records stored. */
 static int mca_banks;		/* Number of per-CPU register banks. */
 
 static SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL,
@@ -100,6 +102,11 @@
 SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0,
     "Administrative toggle for logging of level one TLB parity (L1TP) errors");
 
+static int intel6h_HSD131;
+TUNABLE_INT("hw.mca.intel6h_hsd131", &intel6h_HSD131);
+SYSCTL_INT(_hw_mca, OID_AUTO, intel6h_HSD131, CTLFLAG_RDTUN, &intel6h_HSD131, 0,
+    "Administrative toggle for logging of spurious corrected errors");
+
 int workaround_erratum383;
 SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0,
     "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?");
@@ -243,12 +250,43 @@
 	return ("???");
 }
 
+static int
+mca_mute(const struct mca_record *rec)
+{
+
+	/*
+	 * Skip spurious corrected parity errors generated by Intel Haswell-
+	 * and Broadwell-based CPUs (see HSD131, HSM142, HSW131 and BDM48
+	 * erratum respectively), unless reporting is enabled.
+	 * Note that these errors also have been observed with the D0-stepping
+	 * of Haswell, while at least initially the CPU specification updates
+	 * suggested only the C0-stepping to be affected.  Similarly, Celeron
+	 * 2955U with a CPU ID of 0x45 apparently are also concerned with the
+	 * same problem, with HSM142 only referring to 0x3c and 0x46.
+	 */
+	if (cpu_vendor_id == CPU_VENDOR_INTEL &&
+	    CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+	    (CPUID_TO_MODEL(cpu_id) == 0x3c ||	/* HSD131, HSM142, HSW131 */
+	    CPUID_TO_MODEL(cpu_id) == 0x3d ||	/* BDM48 */
+	    CPUID_TO_MODEL(cpu_id) == 0x45 ||
+	    CPUID_TO_MODEL(cpu_id) == 0x46) &&	/* HSM142 */
+	    rec->mr_bank == 0 &&
+	    (rec->mr_status & 0xa0000000ffffffff) == 0x80000000000f0005 &&
+	    !intel6h_HSD131)
+	    	return (1);
+
+	return (0);
+}
+
 /* Dump details about a single machine check. */
-static void __nonnull(1)
+static void
 mca_log(const struct mca_record *rec)
 {
 	uint16_t mca_error;
 
+	if (mca_mute(rec))
+	    	return;
+
 	printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank,
 	    (long long)rec->mr_status);
 	printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n",
@@ -380,7 +418,7 @@
 		printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc);
 }
 
-static int __nonnull(2)
+static int
 mca_check_status(int bank, struct mca_record *rec)
 {
 	uint64_t status;
@@ -447,7 +485,7 @@
 	mca_fill_freelist();
 }
 
-static void __nonnull(2)
+static void
 mca_record_entry(enum scan_mode mode, const struct mca_record *record)
 {
 	struct mca_internal *rec;
@@ -498,7 +536,7 @@
 	cc = &cmc_state[PCPU_GET(cpuid)][bank];
 	ctl = rdmsr(MSR_MC_CTL2(bank));
 	count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38;
-	delta = (u_int)(ticks - cc->last_intr);
+	delta = (u_int)(time_uptime - cc->last_intr);
 
 	/*
 	 * If an interrupt was received less than cmc_throttle seconds
@@ -513,9 +551,9 @@
 			limit = min(limit << 1, cc->max_threshold);
 			ctl &= ~MC_CTL2_THRESHOLD;
 			ctl |= limit;
-			wrmsr(MSR_MC_CTL2(bank), limit);
+			wrmsr(MSR_MC_CTL2(bank), ctl);
 		}
-		cc->last_intr = ticks;
+		cc->last_intr = time_uptime;
 		return;
 	}
 
@@ -546,7 +584,7 @@
 	if ((ctl & MC_CTL2_THRESHOLD) != limit) {
 		ctl &= ~MC_CTL2_THRESHOLD;
 		ctl |= limit;
-		wrmsr(MSR_MC_CTL2(bank), limit);
+		wrmsr(MSR_MC_CTL2(bank), ctl);
 	}
 }
 #endif
@@ -699,8 +737,8 @@
 {
 	int i;
 
-	cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state **),
-	    M_MCA, M_WAITOK);
+	cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state *), M_MCA,
+	    M_WAITOK);
 	for (i = 0; i <= mp_maxid; i++)
 		cmc_state[i] = malloc(sizeof(struct cmc_state) * mca_banks,
 		    M_MCA, M_WAITOK | M_ZERO);
@@ -728,12 +766,13 @@
 	mtx_init(&mca_lock, "mca", NULL, MTX_SPIN);
 	STAILQ_INIT(&mca_records);
 	TASK_INIT(&mca_scan_task, 0, mca_scan_cpus, NULL);
-	callout_init(&mca_timer, CALLOUT_MPSAFE);
+	callout_init(&mca_timer, 1);
 	STAILQ_INIT(&mca_freelist);
 	TASK_INIT(&mca_refill_task, 0, mca_refill, NULL);
 	mca_fill_freelist();
 	SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO,
-	    "count", CTLFLAG_RD, &mca_count, 0, "Record count");
+	    "count", CTLFLAG_RD, (int *)(uintptr_t)&mca_count, 0,
+	    "Record count");
 	SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO,
 	    "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks,
 	    0, sysctl_positive_int, "I",
@@ -814,7 +853,7 @@
 		return;
 
 	cc = &cmc_state[PCPU_GET(cpuid)][i];
-	cc->last_intr = -ticks;
+	cc->last_intr = 0;
 	ctl = rdmsr(MSR_MC_CTL2(i));
 	ctl &= ~MC_CTL2_THRESHOLD;
 	ctl |= MC_CTL2_CMCI_EN | 1;
@@ -939,7 +978,7 @@
 mca_intr(void)
 {
 	uint64_t mcg_status;
-	int recoverable;
+	int old_count, recoverable;
 
 	if (!(cpu_feature & CPUID_MCA)) {
 		/*
@@ -953,15 +992,27 @@
 	}
 
 	/* Scan the banks and check for any non-recoverable errors. */
+	old_count = mca_count;
 	recoverable = mca_scan(MCE);
 	mcg_status = rdmsr(MSR_MCG_STATUS);
 	if (!(mcg_status & MCG_STATUS_RIPV))
 		recoverable = 0;
 
+	if (!recoverable) {
+		/*
+		 * Wait for at least one error to be logged before
+		 * panic'ing.  Some errors will assert a machine check
+		 * on all CPUs, but only certain CPUs will find a valid
+		 * bank to log.
+		 */
+		while (mca_count == old_count)
+			cpu_spinwait();
+
+		panic("Unrecoverable machine check exception");
+	}
+
 	/* Clear MCIP. */
 	wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP);
-	if (!recoverable)
-		panic("Unrecoverable machine check exception");
 }
 
 #ifdef DEV_APIC

Modified: trunk/sys/x86/x86/mptable.c
===================================================================
--- trunk/sys/x86/x86/mptable.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/mptable.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * Copyright (c) 1996, by Steve Passe
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/mptable.c 262141 2014-02-18 01:15:32Z jhb $");
 
 #include "opt_mptable_force_htt.h"
 #include <sys/param.h>
@@ -786,9 +787,9 @@
 	else
 		apic_id = intr->dst_apic_id;
 	if (intr->dst_apic_int == 0)
-		pin = LVT_LINT0;
+		pin = APIC_LVT_LINT0;
 	else
-		pin = LVT_LINT1;
+		pin = APIC_LVT_LINT1;
 	switch (intr->int_type) {
 	case INTENTRY_TYPE_INT:
 #if 1
@@ -902,8 +903,9 @@
 	/* Is this a pre-defined config? */
 	if (mpfps->config_type != 0) {
 		/* Configure LINT pins. */
-		lapic_set_lvt_mode(APIC_ID_ALL, LVT_LINT0, APIC_LVT_DM_EXTINT);
-		lapic_set_lvt_mode(APIC_ID_ALL, LVT_LINT1, APIC_LVT_DM_NMI);
+		lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT0,
+		    APIC_LVT_DM_EXTINT);
+		lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT1, APIC_LVT_DM_NMI);
 
 		/* Configure I/O APIC pins. */
 		mptable_parse_default_config_ints();

Modified: trunk/sys/x86/x86/mptable_pci.c
===================================================================
--- trunk/sys/x86/x86/mptable_pci.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/mptable_pci.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/mptable_pci.c 280970 2015-04-01 21:48:54Z jhb $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -46,7 +44,7 @@
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcib_private.h>
 #include <x86/mptable.h>
-#include <machine/legacyvar.h>
+#include <x86/legacyvar.h>
 #include <machine/pci_cfgreg.h>
 
 #include "pcib_if.h"
@@ -76,27 +74,6 @@
 	return (bus_generic_attach(dev));
 }
 
-/* Pass MSI requests up to the nexus. */
-static int
-mptable_hostb_alloc_msi(device_t pcib, device_t dev, int count, int maxcount,
-    int *irqs)
-{
-	device_t bus;
-
-	bus = device_get_parent(pcib);
-	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
-	    irqs));
-}
-
-static int
-mptable_hostb_alloc_msix(device_t pcib, device_t dev, int *irq)
-{
-	device_t bus;
-
-	bus = device_get_parent(pcib);
-	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
-}
-
 #ifdef NEW_PCIB
 static int
 mptable_is_isa_range(u_long start, u_long end)
@@ -129,6 +106,11 @@
 {
 	struct mptable_hostb_softc *sc;
 
+#ifdef PCI_RES_BUS
+	if (type == PCI_RES_BUS)
+		return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+		    flags));
+#endif
 	sc = device_get_softc(dev);
 	if (type == SYS_RES_IOPORT && start + count - 1 == end) {
 		if (mptable_is_isa_range(start, end)) {
@@ -165,6 +147,10 @@
 {
 	struct mptable_hostb_softc *sc;
 
+#ifdef PCI_RES_BUS
+	if (type == PCI_RES_BUS)
+		return (pci_domain_adjust_bus(0, child, r, start, end));
+#endif
 	sc = device_get_softc(dev);
 	return (pcib_host_res_adjust(&sc->sc_host_res, child, type, r, start,
 	    end));
@@ -189,7 +175,11 @@
 	DEVMETHOD(bus_alloc_resource,	legacy_pcib_alloc_resource),
 	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
 #endif
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	DEVMETHOD(bus_release_resource,	legacy_pcib_release_resource),
+#else
 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+#endif
 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
@@ -200,9 +190,9 @@
 	DEVMETHOD(pcib_read_config,	legacy_pcib_read_config),
 	DEVMETHOD(pcib_write_config,	legacy_pcib_write_config),
 	DEVMETHOD(pcib_route_interrupt,	mptable_pci_route_interrupt),
-	DEVMETHOD(pcib_alloc_msi,	mptable_hostb_alloc_msi),
+	DEVMETHOD(pcib_alloc_msi,	legacy_pcib_alloc_msi),
 	DEVMETHOD(pcib_release_msi,	pcib_release_msi),
-	DEVMETHOD(pcib_alloc_msix,	mptable_hostb_alloc_msix),
+	DEVMETHOD(pcib_alloc_msix,	legacy_pcib_alloc_msix),
 	DEVMETHOD(pcib_release_msix,	pcib_release_msix),
 	DEVMETHOD(pcib_map_msi,		legacy_pcib_map_msi),
 

Modified: trunk/sys/x86/x86/msi.c
===================================================================
--- trunk/sys/x86/x86/msi.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/msi.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2006 Yahoo!, Inc.
  * All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/msi.c 333126 2018-04-30 20:29:28Z jhb $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -44,6 +45,7 @@
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/sx.h>
+#include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <x86/apicreg.h>
 #include <machine/cputypes.h>
@@ -134,6 +136,22 @@
 		       msi_source_pending, NULL, NULL, msi_config_intr,
 		       msi_assign_cpu };
 
+#ifdef SMP
+/**
+ * Xen hypervisors prior to 4.6.0 do not properly handle updates to
+ * enabled MSI-X table entries.  Allow migration of MSI-X interrupts
+ * to be disabled via a tunable. Values have the following meaning:
+ *
+ * -1: automatic detection by FreeBSD
+ *  0: enable migration
+ *  1: disable migration
+ */
+int msix_disable_migration = -1;
+SYSCTL_INT(_machdep, OID_AUTO, disable_msix_migration, CTLFLAG_RDTUN,
+    &msix_disable_migration, 0,
+    "Disable migration of MSI-X interrupts between CPUs");
+#endif
+
 static int msi_enabled;
 static int msi_last_irq;
 static struct mtx msi_lock;
@@ -212,6 +230,11 @@
 	if (msi->msi_first != msi)
 		return (EINVAL);
 
+#ifdef SMP
+	if (msix_disable_migration && msi->msi_msix)
+		return (EINVAL);
+#endif
+
 	/* Store information to free existing irq. */
 	old_vector = msi->msi_vector;
 	old_id = msi->msi_cpu;
@@ -284,6 +307,13 @@
 		return;
 	}
 
+#ifdef SMP
+	if (msix_disable_migration == -1) {
+		/* The default is to allow migration of MSI-X interrupts. */
+		msix_disable_migration = 0;
+	}
+#endif
+
 	msi_enabled = 1;
 	intr_register_pic(&msi_pic);
 	mtx_init(&msi_lock, "msi", NULL, MTX_DEF);
@@ -352,7 +382,7 @@
 	/* Do we need to create some new sources? */
 	if (cnt < count) {
 		/* If we would exceed the max, give up. */
-		if (i + (count - cnt) > FIRST_MSI_INT + NUM_MSI_INTS) {
+		if (i + (count - cnt) >= FIRST_MSI_INT + NUM_MSI_INTS) {
 			mtx_unlock(&msi_lock);
 			free(mirqs, M_MSI);
 			return (ENXIO);
@@ -530,7 +560,7 @@
 	/* Do we need to create a new source? */
 	if (msi == NULL) {
 		/* If we would exceed the max, give up. */
-		if (i + 1 > FIRST_MSI_INT + NUM_MSI_INTS) {
+		if (i + 1 >= FIRST_MSI_INT + NUM_MSI_INTS) {
 			mtx_unlock(&msi_lock);
 			return (ENXIO);
 		}

Modified: trunk/sys/x86/x86/nexus.c
===================================================================
--- trunk/sys/x86/x86/nexus.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/nexus.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright 1998 Massachusetts Institute of Technology
  *
@@ -28,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/nexus.c 221324 2011-05-02 14:13:12Z jhb $");
 
 /*
  * This code implements a `root nexus' for Intel Architecture

Modified: trunk/sys/x86/x86/tsc.c
===================================================================
--- trunk/sys/x86/x86/tsc.c	2018-05-24 22:23:18 UTC (rev 9894)
+++ trunk/sys/x86/x86/tsc.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1998-2003 Poul-Henning Kamp
  * All rights reserved.
@@ -25,8 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-/* $FreeBSD: release/9.2.0/sys/x86/x86/tsc.c 250772 2013-05-18 13:19:31Z mav $ */
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/x86/x86/tsc.c 280973 2015-04-02 01:02:42Z jhb $");
 
 #include "opt_compat.h"
 #include "opt_clock.h"
@@ -48,6 +48,7 @@
 #include <machine/cputypes.h>
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
+#include <x86/vmware.h>
 
 #include "cpufreq_if.h"
 
@@ -62,7 +63,7 @@
 TUNABLE_INT("kern.timecounter.invariant_tsc", &tsc_is_invariant);
 
 #ifdef SMP
-static int	smp_tsc;
+int	smp_tsc;
 SYSCTL_INT(_kern_timecounter, OID_AUTO, smp_tsc, CTLFLAG_RDTUN, &smp_tsc, 0,
     "Indicates whether the TSC is safe to use in SMP mode");
 TUNABLE_INT("kern.timecounter.smp_tsc", &smp_tsc);
@@ -109,72 +110,11 @@
 	800,			/* quality (adjusted in code) */
 };
 
-#define	VMW_HVMAGIC		0x564d5868
-#define	VMW_HVPORT		0x5658
-#define	VMW_HVCMD_GETVERSION	10
-#define	VMW_HVCMD_GETHZ		45
-
-static __inline void
-vmware_hvcall(u_int cmd, u_int *p)
-{
-
-	__asm __volatile("inl %w3, %0"
-	: "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
-	: "0" (VMW_HVMAGIC), "1" (UINT_MAX), "2" (cmd), "3" (VMW_HVPORT)
-	: "memory");
-}
-
-static int
+static void
 tsc_freq_vmware(void)
 {
-	char hv_sig[13];
 	u_int regs[4];
-	char *p;
-	u_int hv_high;
-	int i;
 
-	/*
-	 * [RFC] CPUID usage for interaction between Hypervisors and Linux.
-	 * http://lkml.org/lkml/2008/10/1/246
-	 *
-	 * KB1009458: Mechanisms to determine if software is running in
-	 * a VMware virtual machine
-	 * http://kb.vmware.com/kb/1009458
-	 */
-	hv_high = 0;
-	if ((cpu_feature2 & CPUID2_HV) != 0) {
-		do_cpuid(0x40000000, regs);
-		hv_high = regs[0];
-		for (i = 1, p = hv_sig; i < 4; i++, p += sizeof(regs) / 4)
-			memcpy(p, &regs[i], sizeof(regs[i]));
-		*p = '\0';
-		if (bootverbose) {
-			/*
-			 * HV vendor	ID string
-			 * ------------+--------------
-			 * KVM		"KVMKVMKVM"
-			 * Microsoft	"Microsoft Hv"
-			 * VMware	"VMwareVMware"
-			 * Xen		"XenVMMXenVMM"
-			 */
-			printf("Hypervisor: Origin = \"%s\"\n", hv_sig);
-		}
-		if (strncmp(hv_sig, "VMwareVMware", 12) != 0)
-			return (0);
-	} else {
-		p = getenv("smbios.system.serial");
-		if (p == NULL)
-			return (0);
-		if (strncmp(p, "VMware-", 7) != 0 &&
-		    strncmp(p, "VMW", 3) != 0) {
-			freeenv(p);
-			return (0);
-		}
-		freeenv(p);
-		vmware_hvcall(VMW_HVCMD_GETVERSION, regs);
-		if (regs[1] != VMW_HVMAGIC)
-			return (0);
-	}
 	if (hv_high >= 0x40000010) {
 		do_cpuid(0x40000010, regs);
 		tsc_freq = regs[0] * 1000;
@@ -184,7 +124,6 @@
 			tsc_freq = regs[0] | ((uint64_t)regs[1] << 32);
 	}
 	tsc_is_invariant = 1;
-	return (1);
 }
 
 static void
@@ -268,8 +207,10 @@
 		}
 	}
 
-	if (tsc_freq_vmware())
+	if (vm_guest == VM_GUEST_VMWARE) {
+		tsc_freq_vmware();
 		return;
+	}
 
 	switch (cpu_vendor_id) {
 	case CPU_VENDOR_AMD:
@@ -331,6 +272,39 @@
 	if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
 		return;
 
+#ifdef __i386__
+	/* The TSC is known to be broken on certain CPUs. */
+	switch (cpu_vendor_id) {
+	case CPU_VENDOR_AMD:
+		switch (cpu_id & 0xFF0) {
+		case 0x500:
+			/* K5 Model 0 */
+			return;
+		}
+		break;
+	case CPU_VENDOR_CENTAUR:
+		switch (cpu_id & 0xff0) {
+		case 0x540:
+			/*
+			 * http://www.centtech.com/c6_data_sheet.pdf
+			 *
+			 * I-12 RDTSC may return incoherent values in EDX:EAX
+			 * I-13 RDTSC hangs when certain event counters are used
+			 */
+			return;
+		}
+		break;
+	case CPU_VENDOR_NSC:
+		switch (cpu_id & 0xff0) {
+		case 0x540:
+			if ((cpu_id & CPUID_STEPPING) == 0)
+				return;
+			break;
+		}
+		break;
+	}
+#endif
+		
 	probe_tsc_freq();
 
 	/*
@@ -374,11 +348,11 @@
 static void								\
 tsc_read_##x(void *arg)							\
 {									\
-	uint32_t *tsc = arg;						\
+	uint64_t *tsc = arg;						\
 	u_int cpu = PCPU_GET(cpuid);					\
 									\
 	__asm __volatile("cpuid" : : : "eax", "ebx", "ecx", "edx");	\
-	tsc[cpu * 3 + x] = rdtsc32();					\
+	tsc[cpu * 3 + x] = rdtsc();					\
 }
 TSC_READ(0)
 TSC_READ(1)
@@ -390,8 +364,8 @@
 static void
 comp_smp_tsc(void *arg)
 {
-	uint32_t *tsc;
-	int32_t d1, d2;
+	uint64_t *tsc;
+	int64_t d1, d2;
 	u_int cpu = PCPU_GET(cpuid);
 	u_int i, j, size;
 
@@ -455,7 +429,7 @@
 static int
 test_tsc(void)
 {
-	uint32_t *data, *tsc;
+	uint64_t *data, *tsc;
 	u_int i, size, adj;
 
 	if ((!smp_tsc && !tsc_is_invariant) || vm_guest)
@@ -555,16 +529,16 @@
 	}
 
 	/*
-	 * We cannot use the TSC if it stops incrementing in deep sleep.
-	 * Currently only Intel CPUs are known for this problem unless
-	 * the invariant TSC bit is set.
+	 * We cannot use the TSC if it stops incrementing while idle.
+	 * Intel CPUs without a C-state invariant TSC can stop the TSC
+	 * in either C2 or C3.
 	 */
-	if (cpu_can_deep_sleep && cpu_vendor_id == CPU_VENDOR_INTEL &&
+	if (cpu_deepest_sleep >= 2 && cpu_vendor_id == CPU_VENDOR_INTEL &&
 	    (amd_pminfo & AMDPM_TSC_INVARIANT) == 0) {
 		tsc_timecounter.tc_quality = -1000;
 		tsc_timecounter.tc_flags |= TC_FLAGS_C2STOP;
 		if (bootverbose)
-			printf("TSC timecounter disabled: C3 enabled.\n");
+			printf("TSC timecounter disabled: C2/C3 may halt it.\n");
 		goto init;
 	}
 

Added: trunk/sys/x86/xen/hvm.c
===================================================================
--- trunk/sys/x86/xen/hvm.c	                        (rev 0)
+++ trunk/sys/x86/xen/hvm.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,652 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 2008, 2013 Citrix Systems, Inc.
+ * Copyright (c) 2012 Spectra Logic Corporation
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/xen/hvm.c 305672 2016-09-09 19:57:32Z jhb $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+#include <machine/smp.h>
+
+#include <x86/apicreg.h>
+
+#include <xen/xen-os.h>
+#include <xen/features.h>
+#include <xen/gnttab.h>
+#include <xen/hypervisor.h>
+#include <xen/hvm.h>
+#include <xen/xen_intr.h>
+
+#include <xen/interface/hvm/params.h>
+#include <xen/interface/vcpu.h>
+
+/*--------------------------- Forward Declarations ---------------------------*/
+#ifdef SMP
+static driver_filter_t xen_smp_rendezvous_action;
+static driver_filter_t xen_invltlb;
+static driver_filter_t xen_invlpg;
+static driver_filter_t xen_invlrng;
+static driver_filter_t xen_invlcache;
+#ifdef __i386__
+static driver_filter_t xen_lazypmap;
+#endif
+static driver_filter_t xen_ipi_bitmap_handler;
+static driver_filter_t xen_cpustop_handler;
+static driver_filter_t xen_cpususpend_handler;
+static driver_filter_t xen_cpustophard_handler;
+static void xen_ipi_vectored(u_int vector, int dest);
+#endif
+static void xen_hvm_cpu_init(void);
+
+/*---------------------------- Extern Declarations ---------------------------*/
+#ifdef __i386__
+extern void pmap_lazyfix_action(void);
+#endif
+#ifdef __amd64__
+extern int pmap_pcid_enabled;
+#endif
+
+/*---------------------------------- Macros ----------------------------------*/
+#define	IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
+
+/*-------------------------------- Local Types -------------------------------*/
+enum xen_hvm_init_type {
+	XEN_HVM_INIT_COLD,
+	XEN_HVM_INIT_CANCELLED_SUSPEND,
+	XEN_HVM_INIT_RESUME
+};
+
+struct xen_ipi_handler
+{
+	driver_filter_t	*filter;
+	const char	*description;
+};
+
+/*-------------------------------- Global Data -------------------------------*/
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+
+#ifdef SMP
+struct cpu_ops xen_hvm_cpu_ops = {
+	.ipi_vectored	= lapic_ipi_vectored,
+	.cpu_init	= xen_hvm_cpu_init,
+	.cpu_resume	= xen_hvm_cpu_init
+};
+#endif
+
+static MALLOC_DEFINE(M_XENHVM, "xen_hvm", "Xen HVM PV Support");
+
+#ifdef SMP
+static struct xen_ipi_handler xen_ipis[] = 
+{
+	[IPI_TO_IDX(IPI_RENDEZVOUS)]	= { xen_smp_rendezvous_action,	"r"   },
+	[IPI_TO_IDX(IPI_INVLTLB)]	= { xen_invltlb,		"itlb"},
+	[IPI_TO_IDX(IPI_INVLPG)]	= { xen_invlpg,			"ipg" },
+	[IPI_TO_IDX(IPI_INVLRNG)]	= { xen_invlrng,		"irg" },
+	[IPI_TO_IDX(IPI_INVLCACHE)]	= { xen_invlcache,		"ic"  },
+#ifdef __i386__
+	[IPI_TO_IDX(IPI_LAZYPMAP)]	= { xen_lazypmap,		"lp"  },
+#endif
+	[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler,	"b"   },
+	[IPI_TO_IDX(IPI_STOP)]		= { xen_cpustop_handler,	"st"  },
+	[IPI_TO_IDX(IPI_SUSPEND)]	= { xen_cpususpend_handler,	"sp"  },
+	[IPI_TO_IDX(IPI_STOP_HARD)]	= { xen_cpustophard_handler,	"sth" },
+};
+#endif
+
+/**
+ * If non-zero, the hypervisor has been configured to use a direct
+ * IDT event callback for interrupt injection.
+ */
+int xen_vector_callback_enabled;
+
+/*------------------------------- Per-CPU Data -------------------------------*/
+DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
+DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
+#ifdef SMP
+DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
+#endif
+
+/*------------------ Hypervisor Access Shared Memory Regions -----------------*/
+/** Hypercall table accessed via HYPERVISOR_*_op() methods. */
+char *hypercall_stubs;
+shared_info_t *HYPERVISOR_shared_info;
+
+
+/*------------------------------ Sysctl tunables -----------------------------*/
+int xen_disable_pv_disks = 0;
+int xen_disable_pv_nics = 0;
+TUNABLE_INT("hw.xen.disable_pv_disks", &xen_disable_pv_disks);
+TUNABLE_INT("hw.xen.disable_pv_nics", &xen_disable_pv_nics);
+
+#ifdef SMP
+/*---------------------------- XEN PV IPI Handlers ---------------------------*/
+/*
+ * This are C clones of the ASM functions found in apic_vector.s
+ */
+static int
+xen_ipi_bitmap_handler(void *arg)
+{
+	struct trapframe *frame;
+
+	frame = arg;
+	ipi_bitmap_handler(*frame);
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_smp_rendezvous_action(void *arg)
+{
+#ifdef COUNT_IPIS
+	(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
+#endif /* COUNT_IPIS */
+
+	smp_rendezvous_action();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_invltlb(void *arg)
+{
+
+	invltlb_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invltlb_pcid(void *arg)
+{
+
+	invltlb_pcid_handler();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_invlpg(void *arg)
+{
+
+	invlpg_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invlpg_pcid(void *arg)
+{
+
+	invlpg_pcid_handler();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_invlrng(void *arg)
+{
+
+	invlrng_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_invlcache(void *arg)
+{
+
+	invlcache_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __i386__
+static int
+xen_lazypmap(void *arg)
+{
+
+	pmap_lazyfix_action();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_cpustop_handler(void *arg)
+{
+
+	cpustop_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_cpususpend_handler(void *arg)
+{
+
+	cpususpend_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_cpustophard_handler(void *arg)
+{
+
+	ipi_nmi_handler();
+	return (FILTER_HANDLED);
+}
+
+/* Xen PV IPI sender */
+static void
+xen_ipi_vectored(u_int vector, int dest)
+{
+	xen_intr_handle_t *ipi_handle;
+	int ipi_idx, to_cpu, self;
+
+	ipi_idx = IPI_TO_IDX(vector);
+	if (ipi_idx > nitems(xen_ipis))
+		panic("IPI out of range");
+
+	switch(dest) {
+	case APIC_IPI_DEST_SELF:
+		ipi_handle = DPCPU_GET(ipi_handle);
+		xen_intr_signal(ipi_handle[ipi_idx]);
+		break;
+	case APIC_IPI_DEST_ALL:
+		CPU_FOREACH(to_cpu) {
+			ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+			xen_intr_signal(ipi_handle[ipi_idx]);
+		}
+		break;
+	case APIC_IPI_DEST_OTHERS:
+		self = PCPU_GET(cpuid);
+		CPU_FOREACH(to_cpu) {
+			if (to_cpu != self) {
+				ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+				xen_intr_signal(ipi_handle[ipi_idx]);
+			}
+		}
+		break;
+	default:
+		to_cpu = apic_cpuid(dest);
+		ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+		xen_intr_signal(ipi_handle[ipi_idx]);
+		break;
+	}
+}
+
+/*---------------------- XEN diverged cpu operations -------------------------*/
+static void
+xen_cpu_ipi_init(int cpu)
+{
+	xen_intr_handle_t *ipi_handle;
+	const struct xen_ipi_handler *ipi;
+	device_t dev;
+	int idx, rc;
+
+	ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
+	dev = pcpu_find(cpu)->pc_device;
+	KASSERT((dev != NULL), ("NULL pcpu device_t"));
+
+	for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
+
+		if (ipi->filter == NULL) {
+			ipi_handle[idx] = NULL;
+			continue;
+		}
+
+		rc = xen_intr_alloc_and_bind_ipi(dev, cpu, ipi->filter,
+		    INTR_TYPE_TTY, &ipi_handle[idx]);
+		if (rc != 0)
+			panic("Unable to allocate a XEN IPI port");
+		xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
+	}
+}
+
+static void
+xen_setup_cpus(void)
+{
+	int i;
+
+	if (!xen_hvm_domain() || !xen_vector_callback_enabled)
+		return;
+
+#ifdef __amd64__
+	if (pmap_pcid_enabled) {
+		xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = xen_invltlb_pcid;
+		xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = xen_invlpg_pcid;
+	}
+#endif
+	CPU_FOREACH(i)
+		xen_cpu_ipi_init(i);
+
+	/* Set the xen pv ipi ops to replace the native ones */
+	cpu_ops.ipi_vectored = xen_ipi_vectored;
+}
+#endif
+
+/*---------------------- XEN Hypervisor Probe and Setup ----------------------*/
+static uint32_t
+xen_hvm_cpuid_base(void)
+{
+	uint32_t base, regs[4];
+
+	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+		do_cpuid(base, regs);
+		if (!memcmp("XenVMMXenVMM", &regs[1], 12)
+		    && (regs[0] - base) >= 2)
+			return (base);
+	}
+	return (0);
+}
+
+/*
+ * Allocate and fill in the hypcall page.
+ */
+static int
+xen_hvm_init_hypercall_stubs(void)
+{
+	uint32_t base, regs[4];
+	int i;
+
+	base = xen_hvm_cpuid_base();
+	if (base == 0)
+		return (ENXIO);
+
+	if (hypercall_stubs == NULL) {
+		int major, minor;
+
+		do_cpuid(base + 1, regs);
+
+		major = regs[0] >> 16;
+		minor = regs[0] & 0xffff;
+		printf("XEN: Hypervisor version %d.%d detected.\n", major,
+			minor);
+
+#ifdef SMP
+		if (((major < 4) || (major == 4 && minor <= 5)) &&
+		    msix_disable_migration == -1) {
+			/*
+			 * Xen hypervisors prior to 4.6.0 do not properly
+			 * handle updates to enabled MSI-X table entries,
+			 * so disable MSI-X interrupt migration in that
+			 * case.
+			 */
+			if (bootverbose)
+				printf(
+"Disabling MSI-X interrupt migration due to Xen hypervisor bug.\n"
+"Set machdep.msix_disable_migration=0 to forcefully enable it.\n");
+			msix_disable_migration = 1;
+		}
+#endif
+	}
+
+	/*
+	 * Find the hypercall pages.
+	 */
+	do_cpuid(base + 2, regs);
+	
+	if (hypercall_stubs == NULL) {
+		size_t call_region_size;
+
+		call_region_size = regs[0] * PAGE_SIZE;
+		hypercall_stubs = malloc(call_region_size, M_XENHVM, M_NOWAIT);
+		if (hypercall_stubs == NULL)
+			panic("Unable to allocate Xen hypercall region");
+	}
+
+	for (i = 0; i < regs[0]; i++)
+		wrmsr(regs[1], vtophys(hypercall_stubs + i * PAGE_SIZE) + i);
+
+	return (0);
+}
+
+static void
+xen_hvm_init_shared_info_page(void)
+{
+	struct xen_add_to_physmap xatp;
+
+	if (HYPERVISOR_shared_info == NULL) {
+		HYPERVISOR_shared_info = malloc(PAGE_SIZE, M_XENHVM, M_NOWAIT);
+		if (HYPERVISOR_shared_info == NULL)
+			panic("Unable to allocate Xen shared info page");
+	}
+
+	xatp.domid = DOMID_SELF;
+	xatp.idx = 0;
+	xatp.space = XENMAPSPACE_shared_info;
+	xatp.gpfn = vtophys(HYPERVISOR_shared_info) >> PAGE_SHIFT;
+	if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+		panic("HYPERVISOR_memory_op failed");
+}
+
+/*
+ * Tell the hypervisor how to contact us for event channel callbacks.
+ */
+void
+xen_hvm_set_callback(device_t dev)
+{
+	struct xen_hvm_param xhp;
+	int irq;
+
+	if (xen_vector_callback_enabled)
+		return;
+
+	xhp.domid = DOMID_SELF;
+	xhp.index = HVM_PARAM_CALLBACK_IRQ;
+	if (xen_feature(XENFEAT_hvm_callback_vector) != 0) {
+		int error;
+
+		xhp.value = HVM_CALLBACK_VECTOR(IDT_EVTCHN);
+		error = HYPERVISOR_hvm_op(HVMOP_set_param, &xhp);
+		if (error == 0) {
+			xen_vector_callback_enabled = 1;
+			return;
+		}
+		printf("Xen HVM callback vector registration failed (%d). "
+		    "Falling back to emulated device interrupt\n", error);
+	}
+	xen_vector_callback_enabled = 0;
+	if (dev == NULL) {
+		/*
+		 * Called from early boot or resume.
+		 * xenpci will invoke us again later.
+		 */
+		return;
+	}
+
+	irq = pci_get_irq(dev);
+	if (irq < 16) {
+		xhp.value = HVM_CALLBACK_GSI(irq);
+	} else {
+		u_int slot;
+		u_int pin;
+
+		slot = pci_get_slot(dev);
+		pin = pci_get_intpin(dev) - 1;
+		xhp.value = HVM_CALLBACK_PCI_INTX(slot, pin);
+	}
+
+	if (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp) != 0)
+		panic("Can't set evtchn callback");
+}
+
+#define	XEN_MAGIC_IOPORT 0x10
+enum {
+	XMI_MAGIC			 = 0x49d2,
+	XMI_UNPLUG_IDE_DISKS		 = 0x01,
+	XMI_UNPLUG_NICS			 = 0x02,
+	XMI_UNPLUG_IDE_EXCEPT_PRI_MASTER = 0x04
+};
+
+static void
+xen_hvm_disable_emulated_devices(void)
+{
+	u_short disable_devs = 0;
+
+	if (inw(XEN_MAGIC_IOPORT) != XMI_MAGIC)
+		return;
+
+	if (xen_disable_pv_disks == 0) {
+		if (bootverbose)
+			printf("XEN: disabling emulated disks\n");
+		disable_devs |= XMI_UNPLUG_IDE_DISKS;
+	}
+	if (xen_disable_pv_nics == 0) {
+		if (bootverbose)
+			printf("XEN: disabling emulated nics\n");
+		disable_devs |= XMI_UNPLUG_NICS;
+	}
+
+	if (disable_devs != 0)
+		outw(XEN_MAGIC_IOPORT, disable_devs);
+}
+
+static void
+xen_hvm_init(enum xen_hvm_init_type init_type)
+{
+	int error;
+	int i;
+
+	if (init_type == XEN_HVM_INIT_CANCELLED_SUSPEND)
+		return;
+
+	error = xen_hvm_init_hypercall_stubs();
+
+	switch (init_type) {
+	case XEN_HVM_INIT_COLD:
+		if (error != 0)
+			return;
+
+		setup_xen_features();
+#ifdef SMP
+		cpu_ops = xen_hvm_cpu_ops;
+#endif
+ 		vm_guest = VM_GUEST_XEN;
+		break;
+	case XEN_HVM_INIT_RESUME:
+		if (error != 0)
+			panic("Unable to init Xen hypercall stubs on resume");
+
+		/* Clear stale vcpu_info. */
+		CPU_FOREACH(i)
+			DPCPU_ID_SET(i, vcpu_info, NULL);
+		break;
+	default:
+		panic("Unsupported HVM initialization type");
+	}
+
+	xen_vector_callback_enabled = 0;
+	xen_domain_type = XEN_HVM_DOMAIN;
+	xen_hvm_init_shared_info_page();
+	xen_hvm_set_callback(NULL);
+	xen_hvm_disable_emulated_devices();
+} 
+
+void
+xen_hvm_suspend(void)
+{
+}
+
+void
+xen_hvm_resume(bool suspend_cancelled)
+{
+
+	xen_hvm_init(suspend_cancelled ?
+	    XEN_HVM_INIT_CANCELLED_SUSPEND : XEN_HVM_INIT_RESUME);
+
+	/* Register vcpu_info area for CPU#0. */
+	xen_hvm_cpu_init();
+}
+ 
+static void
+xen_hvm_sysinit(void *arg __unused)
+{
+	xen_hvm_init(XEN_HVM_INIT_COLD);
+}
+
+static void
+xen_set_vcpu_id(void)
+{
+	struct pcpu *pc;
+	int i;
+
+	/* Set vcpu_id to acpi_id */
+	CPU_FOREACH(i) {
+		pc = pcpu_find(i);
+		pc->pc_vcpu_id = pc->pc_acpi_id;
+		if (bootverbose)
+			printf("XEN: CPU %u has VCPU ID %u\n",
+			       i, pc->pc_vcpu_id);
+	}
+}
+
+static void
+xen_hvm_cpu_init(void)
+{
+	struct vcpu_register_vcpu_info info;
+	struct vcpu_info *vcpu_info;
+	int cpu, rc;
+
+	if (!xen_domain())
+		return;
+
+	if (DPCPU_GET(vcpu_info) != NULL) {
+		/*
+		 * vcpu_info is already set.  We're resuming
+		 * from a failed migration and our pre-suspend
+		 * configuration is still valid.
+		 */
+		return;
+	}
+
+	vcpu_info = DPCPU_PTR(vcpu_local_info);
+	cpu = PCPU_GET(vcpu_id);
+	info.mfn = vtophys(vcpu_info) >> PAGE_SHIFT;
+	info.offset = vtophys(vcpu_info) - trunc_page(vtophys(vcpu_info));
+
+	rc = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+	if (rc != 0)
+		DPCPU_SET(vcpu_info, &HYPERVISOR_shared_info->vcpu_info[cpu]);
+	else
+		DPCPU_SET(vcpu_info, vcpu_info);
+}
+
+SYSINIT(xen_hvm_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, xen_hvm_sysinit, NULL);
+#ifdef SMP
+SYSINIT(xen_setup_cpus, SI_SUB_SMP, SI_ORDER_FIRST, xen_setup_cpus, NULL);
+#endif
+SYSINIT(xen_hvm_cpu_init, SI_SUB_INTR, SI_ORDER_FIRST, xen_hvm_cpu_init, NULL);
+SYSINIT(xen_set_vcpu_id, SI_SUB_CPU, SI_ORDER_ANY, xen_set_vcpu_id, NULL);


Property changes on: trunk/sys/x86/xen/hvm.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/x86/xen/xen_intr.c
===================================================================
--- trunk/sys/x86/xen/xen_intr.c	                        (rev 0)
+++ trunk/sys/x86/xen/xen_intr.c	2018-05-24 22:26:03 UTC (rev 9895)
@@ -0,0 +1,1242 @@
+/* $MidnightBSD$ */
+/******************************************************************************
+ * xen_intr.c
+ *
+ * Xen event and interrupt services for x86 PV and HVM guests.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, Intel Corporation <xiaofeng.ling at intel.com>
+ * Copyright (c) 2012, Spectra Logic Corporation
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/x86/xen/xen_intr.c 291647 2015-12-02 12:58:20Z royger $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/interrupt.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/intr_machdep.h>
+#include <machine/apicvar.h>
+#include <machine/smp.h>
+#include <machine/stdarg.h>
+
+#include <machine/xen/synch_bitops.h>
+#include <machine/xen/xen-os.h>
+#include <machine/xen/xenvar.h>
+
+#include <xen/hypervisor.h>
+#include <xen/xen_intr.h>
+#include <xen/evtchn/evtchnvar.h>
+
+#include <dev/xen/xenpci/xenpcivar.h>
+
+static MALLOC_DEFINE(M_XENINTR, "xen_intr", "Xen Interrupt Services");
+
+/**
+ * Per-cpu event channel processing state.
+ */
+struct xen_intr_pcpu_data {
+	/**
+	 * The last event channel bitmap section (level one bit) processed.
+	 * This is used to ensure we scan all ports before
+	 * servicing an already servied port again.
+	 */
+	u_int	last_processed_l1i;
+
+	/**
+	 * The last event channel processed within the event channel
+	 * bitmap being scanned.
+	 */
+	u_int	last_processed_l2i;
+
+	/** Pointer to this CPU's interrupt statistic counter. */
+	u_long *evtchn_intrcnt;
+
+	/**
+	 * A bitmap of ports that can be serviced from this CPU.
+	 * A set bit means interrupt handling is enabled.
+	 */
+	u_long	evtchn_enabled[sizeof(u_long) * 8];
+};
+
+/*
+ * Start the scan at port 0 by initializing the last scanned
+ * location as the highest numbered event channel port.
+ */
+DPCPU_DEFINE(struct xen_intr_pcpu_data, xen_intr_pcpu) = {
+	.last_processed_l1i = LONG_BIT - 1,
+	.last_processed_l2i = LONG_BIT - 1
+};
+
+DPCPU_DECLARE(struct vcpu_info *, vcpu_info);
+
+#define is_valid_evtchn(x)	((x) != 0)
+
+struct xenisrc {
+	struct intsrc	xi_intsrc;
+	enum evtchn_type xi_type;
+	int		xi_cpu;		/* VCPU for delivery. */
+	int		xi_vector;	/* Global isrc vector number. */
+	evtchn_port_t	xi_port;
+	int		xi_pirq;
+	int		xi_virq;
+	u_int		xi_close:1;	/* close on unbind? */
+	u_int		xi_needs_eoi:1;
+	u_int		xi_shared:1;	/* Shared with other domains. */
+};
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+static void	xen_intr_suspend(struct pic *);
+static void	xen_intr_resume(struct pic *, bool suspend_cancelled);
+static void	xen_intr_enable_source(struct intsrc *isrc);
+static void	xen_intr_disable_source(struct intsrc *isrc, int eoi);
+static void	xen_intr_eoi_source(struct intsrc *isrc);
+static void	xen_intr_enable_intr(struct intsrc *isrc);
+static void	xen_intr_disable_intr(struct intsrc *isrc);
+static int	xen_intr_vector(struct intsrc *isrc);
+static int	xen_intr_source_pending(struct intsrc *isrc);
+static int	xen_intr_config_intr(struct intsrc *isrc,
+		     enum intr_trigger trig, enum intr_polarity pol);
+static int	xen_intr_assign_cpu(struct intsrc *isrc, u_int apic_id);
+
+static void	xen_intr_pirq_enable_source(struct intsrc *isrc);
+static void	xen_intr_pirq_disable_source(struct intsrc *isrc, int eoi);
+static void	xen_intr_pirq_eoi_source(struct intsrc *isrc);
+static void	xen_intr_pirq_enable_intr(struct intsrc *isrc);
+
+/**
+ * PIC interface for all event channel port types except physical IRQs.
+ */
+struct pic xen_intr_pic = {
+	.pic_enable_source  = xen_intr_enable_source,
+	.pic_disable_source = xen_intr_disable_source,
+	.pic_eoi_source     = xen_intr_eoi_source,
+	.pic_enable_intr    = xen_intr_enable_intr,
+	.pic_disable_intr   = xen_intr_disable_intr,
+	.pic_vector         = xen_intr_vector,
+	.pic_source_pending = xen_intr_source_pending,
+	.pic_suspend        = xen_intr_suspend,
+	.pic_resume         = xen_intr_resume,
+	.pic_config_intr    = xen_intr_config_intr,
+	.pic_assign_cpu     = xen_intr_assign_cpu
+};
+
+/**
+ * PIC interface for all event channel representing
+ * physical interrupt sources.
+ */
+struct pic xen_intr_pirq_pic = {
+	.pic_enable_source  = xen_intr_pirq_enable_source,
+	.pic_disable_source = xen_intr_pirq_disable_source,
+	.pic_eoi_source     = xen_intr_pirq_eoi_source,
+	.pic_enable_intr    = xen_intr_pirq_enable_intr,
+	.pic_disable_intr   = xen_intr_disable_intr,
+	.pic_vector         = xen_intr_vector,
+	.pic_source_pending = xen_intr_source_pending,
+	.pic_suspend        = xen_intr_suspend,
+	.pic_resume         = xen_intr_resume,
+	.pic_config_intr    = xen_intr_config_intr,
+	.pic_assign_cpu     = xen_intr_assign_cpu
+};
+
+static struct mtx	xen_intr_isrc_lock;
+static int		xen_intr_isrc_count;
+static struct xenisrc  *xen_intr_port_to_isrc[NR_EVENT_CHANNELS];
+
+/*------------------------- Private Functions --------------------------------*/
+/**
+ * Disable signal delivery for an event channel port on the
+ * specified CPU.
+ *
+ * \param port  The event channel port to mask.
+ *
+ * This API is used to manage the port<=>CPU binding of event
+ * channel handlers.
+ *
+ * \note  This operation does not preclude reception of an event
+ *        for this event channel on another CPU.  To mask the
+ *        event channel globally, use evtchn_mask().
+ */
+static inline void
+evtchn_cpu_mask_port(u_int cpu, evtchn_port_t port)
+{
+	struct xen_intr_pcpu_data *pcpu;
+
+	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
+	clear_bit(port, pcpu->evtchn_enabled);
+}
+
+/**
+ * Enable signal delivery for an event channel port on the
+ * specified CPU.
+ *
+ * \param port  The event channel port to unmask.
+ *
+ * This API is used to manage the port<=>CPU binding of event
+ * channel handlers.
+ *
+ * \note  This operation does not guarantee that event delivery
+ *        is enabled for this event channel port.  The port must
+ *        also be globally enabled.  See evtchn_unmask().
+ */
+static inline void
+evtchn_cpu_unmask_port(u_int cpu, evtchn_port_t port)
+{
+	struct xen_intr_pcpu_data *pcpu;
+
+	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
+	set_bit(port, pcpu->evtchn_enabled);
+}
+
+/**
+ * Allocate and register a per-cpu Xen upcall interrupt counter.
+ *
+ * \param cpu  The cpu for which to register this interrupt count.
+ */
+static void
+xen_intr_intrcnt_add(u_int cpu)
+{
+	char buf[MAXCOMLEN + 1];
+	struct xen_intr_pcpu_data *pcpu;
+
+	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
+	if (pcpu->evtchn_intrcnt != NULL)
+		return;
+
+	snprintf(buf, sizeof(buf), "cpu%d:xen", cpu);
+	intrcnt_add(buf, &pcpu->evtchn_intrcnt);
+}
+
+/**
+ * Search for an already allocated but currently unused Xen interrupt
+ * source object.
+ *
+ * \param type  Restrict the search to interrupt sources of the given
+ *              type.
+ *
+ * \return  A pointer to a free Xen interrupt source object or NULL.
+ */
+static struct xenisrc *
+xen_intr_find_unused_isrc(enum evtchn_type type)
+{
+	int isrc_idx;
+
+	KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn isrc lock not held"));
+
+	for (isrc_idx = 0; isrc_idx < xen_intr_isrc_count; isrc_idx ++) {
+		struct xenisrc *isrc;
+		u_int vector;
+
+		vector = FIRST_EVTCHN_INT + isrc_idx;
+		isrc = (struct xenisrc *)intr_lookup_source(vector);
+		if (isrc != NULL
+		 && isrc->xi_type == EVTCHN_TYPE_UNBOUND) {
+			KASSERT(isrc->xi_intsrc.is_handlers == 0,
+			    ("Free evtchn still has handlers"));
+			isrc->xi_type = type;
+			return (isrc);
+		}
+	}
+	return (NULL);
+}
+
+/**
+ * Allocate a Xen interrupt source object.
+ *
+ * \param type  The type of interrupt source to create.
+ *
+ * \return  A pointer to a newly allocated Xen interrupt source
+ *          object or NULL.
+ */
+static struct xenisrc *
+xen_intr_alloc_isrc(enum evtchn_type type)
+{
+	static int warned;
+	struct xenisrc *isrc;
+	int vector;
+
+	KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn alloc lock not held"));
+
+	if (xen_intr_isrc_count > NR_EVENT_CHANNELS) {
+		if (!warned) {
+			warned = 1;
+			printf("xen_intr_alloc: Event channels exhausted.\n");
+		}
+		return (NULL);
+	}
+	vector = FIRST_EVTCHN_INT + xen_intr_isrc_count;
+	xen_intr_isrc_count++;
+
+	mtx_unlock(&xen_intr_isrc_lock);
+	isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO);
+	isrc->xi_intsrc.is_pic = &xen_intr_pic;
+	isrc->xi_vector = vector;
+	isrc->xi_type = type;
+	intr_register_source(&isrc->xi_intsrc);
+	mtx_lock(&xen_intr_isrc_lock);
+
+	return (isrc);
+}
+
+/**
+ * Attempt to free an active Xen interrupt source object.
+ *
+ * \param isrc  The interrupt source object to release.
+ *
+ * \returns  EBUSY if the source is still in use, otherwise 0.
+ */
+static int
+xen_intr_release_isrc(struct xenisrc *isrc)
+{
+
+	mtx_lock(&xen_intr_isrc_lock);
+	if (isrc->xi_intsrc.is_handlers != 0) {
+		mtx_unlock(&xen_intr_isrc_lock);
+		return (EBUSY);
+	}
+	evtchn_mask_port(isrc->xi_port);
+	evtchn_clear_port(isrc->xi_port);
+
+	/* Rebind port to CPU 0. */
+	evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
+	evtchn_cpu_unmask_port(0, isrc->xi_port);
+
+	if (isrc->xi_close != 0 && is_valid_evtchn(isrc->xi_port)) {
+		struct evtchn_close close = { .port = isrc->xi_port };
+		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
+			panic("EVTCHNOP_close failed");
+	}
+
+	xen_intr_port_to_isrc[isrc->xi_port] = NULL;
+	isrc->xi_cpu = 0;
+	isrc->xi_type = EVTCHN_TYPE_UNBOUND;
+	isrc->xi_port = 0;
+	mtx_unlock(&xen_intr_isrc_lock);
+	return (0);
+}
+
+/**
+ * Associate an interrupt handler with an already allocated local Xen
+ * event channel port.
+ *
+ * \param isrcp       The returned Xen interrupt object associated with
+ *                    the specified local port.
+ * \param local_port  The event channel to bind.
+ * \param type        The event channel type of local_port.
+ * \param intr_owner  The device making this bind request.
+ * \param filter      An interrupt filter handler.  Specify NULL
+ *                    to always dispatch to the ithread handler.
+ * \param handler     An interrupt ithread handler.  Optional (can
+ *                    specify NULL) if all necessary event actions
+ *                    are performed by filter.
+ * \param arg         Argument to present to both filter and handler.
+ * \param irqflags    Interrupt handler flags.  See sys/bus.h.
+ * \param handlep     Pointer to an opaque handle used to manage this
+ *                    registration.
+ *
+ * \returns  0 on success, otherwise an errno.
+ */
+static int
+xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port,
+    enum evtchn_type type, device_t intr_owner, driver_filter_t filter,
+    driver_intr_t handler, void *arg, enum intr_type flags,
+    xen_intr_handle_t *port_handlep)
+{
+	struct xenisrc *isrc;
+	int error;
+
+	*isrcp = NULL;
+	if (port_handlep == NULL) {
+		device_printf(intr_owner,
+			      "xen_intr_bind_isrc: Bad event handle\n");
+		return (EINVAL);
+	}
+
+	mtx_lock(&xen_intr_isrc_lock);
+	isrc = xen_intr_find_unused_isrc(type);
+	if (isrc == NULL) {
+		isrc = xen_intr_alloc_isrc(type);
+		if (isrc == NULL) {
+			mtx_unlock(&xen_intr_isrc_lock);
+			return (ENOSPC);
+		}
+	}
+	isrc->xi_port = local_port;
+	xen_intr_port_to_isrc[local_port] = isrc;
+	mtx_unlock(&xen_intr_isrc_lock);
+
+	error = intr_add_handler(device_get_nameunit(intr_owner),
+				 isrc->xi_vector, filter, handler, arg,
+				 flags|INTR_EXCL, port_handlep);
+	if (error != 0) {
+		device_printf(intr_owner,
+			      "xen_intr_bind_irq: intr_add_handler failed\n");
+		xen_intr_release_isrc(isrc);
+		return (error);
+	}
+	*isrcp = isrc;
+	evtchn_unmask_port(local_port);
+	return (0);
+}
+
+/**
+ * Lookup a Xen interrupt source object given an interrupt binding handle.
+ * 
+ * \param handle  A handle initialized by a previous call to
+ *                xen_intr_bind_isrc().
+ *
+ * \returns  A pointer to the Xen interrupt source object associated
+ *           with the given interrupt handle.  NULL if no association
+ *           currently exists.
+ */
+static struct xenisrc *
+xen_intr_isrc(xen_intr_handle_t handle)
+{
+	struct intr_handler *ih;
+
+	ih = handle;
+	if (ih == NULL || ih->ih_event == NULL)
+		return (NULL);
+
+	return (ih->ih_event->ie_source);
+}
+
+/**
+ * Determine the event channel ports at the given section of the
+ * event port bitmap which have pending events for the given cpu.
+ * 
+ * \param pcpu  The Xen interrupt pcpu data for the cpu being querried.
+ * \param sh    The Xen shared info area.
+ * \param idx   The index of the section of the event channel bitmap to
+ *              inspect.
+ *
+ * \returns  A u_long with bits set for every event channel with pending
+ *           events.
+ */
+static inline u_long
+xen_intr_active_ports(struct xen_intr_pcpu_data *pcpu, shared_info_t *sh,
+    u_int idx)
+{
+	return (sh->evtchn_pending[idx]
+	      & ~sh->evtchn_mask[idx]
+	      & pcpu->evtchn_enabled[idx]);
+}
+
+/**
+ * Interrupt handler for processing all Xen event channel events.
+ * 
+ * \param trap_frame  The trap frame context for the current interrupt.
+ */
+void
+xen_intr_handle_upcall(struct trapframe *trap_frame)
+{
+	u_int l1i, l2i, port, cpu;
+	u_long masked_l1, masked_l2;
+	struct xenisrc *isrc;
+	shared_info_t *s;
+	vcpu_info_t *v;
+	struct xen_intr_pcpu_data *pc;
+	u_long l1, l2;
+
+	/*
+	 * Disable preemption in order to always check and fire events
+	 * on the right vCPU
+	 */
+	critical_enter();
+
+	cpu = PCPU_GET(cpuid);
+	pc  = DPCPU_PTR(xen_intr_pcpu);
+	s   = HYPERVISOR_shared_info;
+	v   = DPCPU_GET(vcpu_info);
+
+	if (xen_hvm_domain() && !xen_vector_callback_enabled) {
+		KASSERT((cpu == 0), ("Fired PCI event callback on wrong CPU"));
+	}
+
+	v->evtchn_upcall_pending = 0;
+
+#if 0
+#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
+	/* Clear master flag /before/ clearing selector flag. */
+	wmb();
+#endif
+#endif
+
+	l1 = atomic_readandclear_long(&v->evtchn_pending_sel);
+
+	l1i = pc->last_processed_l1i;
+	l2i = pc->last_processed_l2i;
+	(*pc->evtchn_intrcnt)++;
+
+	while (l1 != 0) {
+
+		l1i = (l1i + 1) % LONG_BIT;
+		masked_l1 = l1 & ((~0UL) << l1i);
+
+		if (masked_l1 == 0) {
+			/*
+			 * if we masked out all events, wrap around
+			 * to the beginning.
+			 */
+			l1i = LONG_BIT - 1;
+			l2i = LONG_BIT - 1;
+			continue;
+		}
+		l1i = ffsl(masked_l1) - 1;
+
+		do {
+			l2 = xen_intr_active_ports(pc, s, l1i);
+
+			l2i = (l2i + 1) % LONG_BIT;
+			masked_l2 = l2 & ((~0UL) << l2i);
+
+			if (masked_l2 == 0) {
+				/* if we masked out all events, move on */
+				l2i = LONG_BIT - 1;
+				break;
+			}
+			l2i = ffsl(masked_l2) - 1;
+
+			/* process port */
+			port = (l1i * LONG_BIT) + l2i;
+			synch_clear_bit(port, &s->evtchn_pending[0]);
+
+			isrc = xen_intr_port_to_isrc[port];
+			if (__predict_false(isrc == NULL))
+				continue;
+
+			/* Make sure we are firing on the right vCPU */
+			KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)),
+				("Received unexpected event on vCPU#%d, event bound to vCPU#%d",
+				PCPU_GET(cpuid), isrc->xi_cpu));
+
+			intr_execute_handlers(&isrc->xi_intsrc, trap_frame);
+
+			/*
+			 * If this is the final port processed,
+			 * we'll pick up here+1 next time.
+			 */
+			pc->last_processed_l1i = l1i;
+			pc->last_processed_l2i = l2i;
+
+		} while (l2i != LONG_BIT - 1);
+
+		l2 = xen_intr_active_ports(pc, s, l1i);
+		if (l2 == 0) {
+			/*
+			 * We handled all ports, so we can clear the
+			 * selector bit.
+			 */
+			l1 &= ~(1UL << l1i);
+		}
+	}
+	critical_exit();
+}
+
+static int
+xen_intr_init(void *dummy __unused)
+{
+	struct xen_intr_pcpu_data *pcpu;
+	int i;
+
+	if (!xen_domain())
+		return (0);
+
+	mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF);
+
+	/*
+	 * Register interrupt count manually as we aren't
+	 * guaranteed to see a call to xen_intr_assign_cpu()
+	 * before our first interrupt. Also set the per-cpu
+	 * mask of CPU#0 to enable all, since by default
+	 * all event channels are bound to CPU#0.
+	 */
+	CPU_FOREACH(i) {
+		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
+		memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0,
+		       sizeof(pcpu->evtchn_enabled));
+		xen_intr_intrcnt_add(i);
+	}
+
+	intr_register_pic(&xen_intr_pic);
+
+	return (0);
+}
+SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_MIDDLE, xen_intr_init, NULL);
+
+/*--------------------------- Common PIC Functions ---------------------------*/
+/**
+ * Prepare this PIC for system suspension.
+ */
+static void
+xen_intr_suspend(struct pic *unused)
+{
+}
+
+static void
+xen_rebind_ipi(struct xenisrc *isrc)
+{
+#ifdef SMP
+	int cpu = isrc->xi_cpu;
+	int vcpu_id = pcpu_find(cpu)->pc_vcpu_id;
+	int error;
+	struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id };
+
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+	                                    &bind_ipi);
+	if (error != 0)
+		panic("unable to rebind xen IPI: %d", error);
+
+	isrc->xi_port = bind_ipi.port;
+	isrc->xi_cpu = 0;
+	xen_intr_port_to_isrc[bind_ipi.port] = isrc;
+
+	error = xen_intr_assign_cpu(&isrc->xi_intsrc,
+	                            cpu_apic_ids[cpu]);
+	if (error)
+		panic("unable to bind xen IPI to CPU#%d: %d",
+		      cpu, error);
+
+	evtchn_unmask_port(bind_ipi.port);
+#else
+	panic("Resume IPI event channel on UP");
+#endif
+}
+
+static void
+xen_rebind_virq(struct xenisrc *isrc)
+{
+	int cpu = isrc->xi_cpu;
+	int vcpu_id = pcpu_find(cpu)->pc_vcpu_id;
+	int error;
+	struct evtchn_bind_virq bind_virq = { .virq = isrc->xi_virq,
+	                                      .vcpu = vcpu_id };
+
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+	                                    &bind_virq);
+	if (error != 0)
+		panic("unable to rebind xen VIRQ#%d: %d", isrc->xi_virq, error);
+
+	isrc->xi_port = bind_virq.port;
+	isrc->xi_cpu = 0;
+	xen_intr_port_to_isrc[bind_virq.port] = isrc;
+
+#ifdef SMP
+	error = xen_intr_assign_cpu(&isrc->xi_intsrc,
+	                            cpu_apic_ids[cpu]);
+	if (error)
+		panic("unable to bind xen VIRQ#%d to CPU#%d: %d",
+		      isrc->xi_virq, cpu, error);
+#endif
+
+	evtchn_unmask_port(bind_virq.port);
+}
+
+/**
+ * Return this PIC to service after being suspended.
+ */
+static void
+xen_intr_resume(struct pic *unused, bool suspend_cancelled)
+{
+	shared_info_t *s = HYPERVISOR_shared_info;
+	struct xenisrc *isrc;
+	u_int isrc_idx;
+	int i;
+
+	if (suspend_cancelled)
+		return;
+
+	/* Reset the per-CPU masks */
+	CPU_FOREACH(i) {
+		struct xen_intr_pcpu_data *pcpu;
+
+		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
+		memset(pcpu->evtchn_enabled,
+		       i == 0 ? ~0 : 0, sizeof(pcpu->evtchn_enabled));
+	}
+
+	/* Mask all event channels. */
+	for (i = 0; i < nitems(s->evtchn_mask); i++)
+		atomic_store_rel_long(&s->evtchn_mask[i], ~0);
+
+	/* Remove port -> isrc mappings */
+	memset(xen_intr_port_to_isrc, 0, sizeof(xen_intr_port_to_isrc));
+
+	/* Free unused isrcs and rebind VIRQs and IPIs */
+	for (isrc_idx = 0; isrc_idx < xen_intr_isrc_count; isrc_idx++) {
+		u_int vector;
+
+		vector = FIRST_EVTCHN_INT + isrc_idx;
+		isrc = (struct xenisrc *)intr_lookup_source(vector);
+		if (isrc != NULL) {
+			isrc->xi_port = 0;
+			switch (isrc->xi_type) {
+			case EVTCHN_TYPE_IPI:
+				xen_rebind_ipi(isrc);
+				break;
+			case EVTCHN_TYPE_VIRQ:
+				xen_rebind_virq(isrc);
+				break;
+			default:
+				isrc->xi_cpu = 0;
+				break;
+			}
+		}
+	}
+}
+
+/**
+ * Disable a Xen interrupt source.
+ *
+ * \param isrc  The interrupt source to disable.
+ */
+static void
+xen_intr_disable_intr(struct intsrc *base_isrc)
+{
+	struct xenisrc *isrc = (struct xenisrc *)base_isrc;
+
+	evtchn_mask_port(isrc->xi_port);
+}
+
+/**
+ * Determine the global interrupt vector number for
+ * a Xen interrupt source.
+ *
+ * \param isrc  The interrupt source to query.
+ *
+ * \return  The vector number corresponding to the given interrupt source.
+ */
+static int
+xen_intr_vector(struct intsrc *base_isrc)
+{
+	struct xenisrc *isrc = (struct xenisrc *)base_isrc;
+
+	return (isrc->xi_vector);
+}
+
+/**
+ * Determine whether or not interrupt events are pending on the
+ * the given interrupt source.
+ *
+ * \param isrc  The interrupt source to query.
+ *
+ * \returns  0 if no events are pending, otherwise non-zero.
+ */
+static int
+xen_intr_source_pending(struct intsrc *isrc)
+{
+	/*
+	 * EventChannels are edge triggered and never masked.
+	 * There can be no pending events.
+	 */
+	return (0);
+}
+
+/**
+ * Perform configuration of an interrupt source.
+ *
+ * \param isrc  The interrupt source to configure.
+ * \param trig  Edge or level.
+ * \param pol   Active high or low.
+ *
+ * \returns  0 if no events are pending, otherwise non-zero.
+ */
+static int
+xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+	/* Configuration is only possible via the evtchn apis. */
+	return (ENODEV);
+}
+
+/**
+ * Configure CPU affinity for interrupt source event delivery.
+ *
+ * \param isrc     The interrupt source to configure.
+ * \param apic_id  The apic id of the CPU for handling future events.
+ *
+ * \returns  0 if successful, otherwise an errno.
+ */
+static int
+xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
+{
+#ifdef SMP
+	struct evtchn_bind_vcpu bind_vcpu;
+	struct xenisrc *isrc;
+	u_int to_cpu, vcpu_id;
+	int error;
+
+#ifdef XENHVM
+	if (xen_vector_callback_enabled == 0)
+		return (EOPNOTSUPP);
+#endif
+
+	to_cpu = apic_cpuid(apic_id);
+	vcpu_id = pcpu_find(to_cpu)->pc_vcpu_id;
+	xen_intr_intrcnt_add(to_cpu);
+
+	mtx_lock(&xen_intr_isrc_lock);
+	isrc = (struct xenisrc *)base_isrc;
+	if (!is_valid_evtchn(isrc->xi_port)) {
+		mtx_unlock(&xen_intr_isrc_lock);
+		return (EINVAL);
+	}
+
+	if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
+		(isrc->xi_type == EVTCHN_TYPE_IPI)) {
+		/*
+		 * Virtual IRQs are associated with a cpu by
+		 * the Hypervisor at evtchn_bind_virq time, so
+		 * all we need to do is update the per-CPU masks.
+		 */
+		evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
+		isrc->xi_cpu = to_cpu;
+		evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
+		mtx_unlock(&xen_intr_isrc_lock);
+		return (0);
+	}
+
+	bind_vcpu.port = isrc->xi_port;
+	bind_vcpu.vcpu = vcpu_id;
+
+	/*
+	 * Allow interrupts to be fielded on the new VCPU before
+	 * we ask the hypervisor to deliver them there.
+	 */
+	evtchn_cpu_unmask_port(to_cpu, isrc->xi_port);
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
+	if (isrc->xi_cpu != to_cpu) {
+		if (error == 0) {
+			/* Commit to new binding by removing the old one. */
+			evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
+			isrc->xi_cpu = to_cpu;
+		} else {
+			/* Roll-back to previous binding. */
+			evtchn_cpu_mask_port(to_cpu, isrc->xi_port);
+		}
+	}
+	mtx_unlock(&xen_intr_isrc_lock);
+	return (0);
+#else
+	return (EOPNOTSUPP);
+#endif
+}
+
+/*------------------- Virtual Interrupt Source PIC Functions -----------------*/
+/*
+ * Mask a level triggered interrupt source.
+ *
+ * \param isrc  The interrupt source to mask (if necessary).
+ * \param eoi   If non-zero, perform any necessary end-of-interrupt
+ *              acknowledgements.
+ */
+static void
+xen_intr_disable_source(struct intsrc *isrc, int eoi)
+{
+}
+
+/*
+ * Unmask a level triggered interrupt source.
+ *
+ * \param isrc  The interrupt source to unmask (if necessary).
+ */
+static void
+xen_intr_enable_source(struct intsrc *isrc)
+{
+}
+
+/*
+ * Perform any necessary end-of-interrupt acknowledgements.
+ *
+ * \param isrc  The interrupt source to EOI.
+ */
+static void
+xen_intr_eoi_source(struct intsrc *isrc)
+{
+}
+
+/*
+ * Enable and unmask the interrupt source.
+ *
+ * \param isrc  The interrupt source to enable.
+ */
+static void
+xen_intr_enable_intr(struct intsrc *base_isrc)
+{
+	struct xenisrc *isrc = (struct xenisrc *)base_isrc;
+
+	evtchn_unmask_port(isrc->xi_port);
+}
+
+/*------------------ Physical Interrupt Source PIC Functions -----------------*/
+/*
+ * Mask a level triggered interrupt source.
+ *
+ * \param isrc  The interrupt source to mask (if necessary).
+ * \param eoi   If non-zero, perform any necessary end-of-interrupt
+ *              acknowledgements.
+ */
+static void
+xen_intr_pirq_disable_source(struct intsrc *base_isrc, int eoi)
+{
+	struct xenisrc *isrc;
+
+	isrc = (struct xenisrc *)base_isrc;
+	evtchn_mask_port(isrc->xi_port);
+}
+
+/*
+ * Unmask a level triggered interrupt source.
+ *
+ * \param isrc  The interrupt source to unmask (if necessary).
+ */
+static void
+xen_intr_pirq_enable_source(struct intsrc *base_isrc)
+{
+	struct xenisrc *isrc;
+
+	isrc = (struct xenisrc *)base_isrc;
+	evtchn_unmask_port(isrc->xi_port);
+}
+
+/*
+ * Perform any necessary end-of-interrupt acknowledgements.
+ *
+ * \param isrc  The interrupt source to EOI.
+ */
+static void
+xen_intr_pirq_eoi_source(struct intsrc *base_isrc)
+{
+	struct xenisrc *isrc;
+
+	/* XXX Use shared page of flags for this. */
+	isrc = (struct xenisrc *)base_isrc;
+	if (isrc->xi_needs_eoi != 0) {
+		struct physdev_eoi eoi = { .irq = isrc->xi_pirq };
+
+		(void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
+	}
+}
+
+/*
+ * Enable and unmask the interrupt source.
+ *
+ * \param isrc  The interrupt source to enable.
+ */
+static void
+xen_intr_pirq_enable_intr(struct intsrc *isrc)
+{
+}
+
+/*--------------------------- Public Functions -------------------------------*/
+/*------- API comments for these methods can be found in xen/xenintr.h -------*/
+int
+xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port,
+    driver_filter_t filter, driver_intr_t handler, void *arg,
+    enum intr_type flags, xen_intr_handle_t *port_handlep)
+{
+	struct xenisrc *isrc;
+	int error;
+
+	error = xen_intr_bind_isrc(&isrc, local_port, EVTCHN_TYPE_PORT, dev,
+		    filter, handler, arg, flags, port_handlep);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * The Event Channel API didn't open this port, so it is not
+	 * responsible for closing it automatically on unbind.
+	 */
+	isrc->xi_close = 0;
+	return (0);
+}
+
+int
+xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain,
+    driver_filter_t filter, driver_intr_t handler, void *arg,
+    enum intr_type flags, xen_intr_handle_t *port_handlep)
+{
+	struct xenisrc *isrc;
+	struct evtchn_alloc_unbound alloc_unbound;
+	int error;
+
+	alloc_unbound.dom        = DOMID_SELF;
+	alloc_unbound.remote_dom = remote_domain;
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+		    &alloc_unbound);
+	if (error != 0) {
+		/*
+		 * XXX Trap Hypercall error code Linuxisms in
+		 *     the HYPERCALL layer.
+		 */
+		return (-error);
+	}
+
+	error = xen_intr_bind_isrc(&isrc, alloc_unbound.port, EVTCHN_TYPE_PORT,
+				 dev, filter, handler, arg, flags,
+				 port_handlep);
+	if (error != 0) {
+		evtchn_close_t close = { .port = alloc_unbound.port };
+		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
+			panic("EVTCHNOP_close failed");
+		return (error);
+	}
+
+	isrc->xi_close = 1;
+	return (0);
+}
+
+int 
+xen_intr_bind_remote_port(device_t dev, u_int remote_domain,
+    u_int remote_port, driver_filter_t filter, driver_intr_t handler,
+    void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep)
+{
+	struct xenisrc *isrc;
+	struct evtchn_bind_interdomain bind_interdomain;
+	int error;
+
+	bind_interdomain.remote_dom  = remote_domain;
+	bind_interdomain.remote_port = remote_port;
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+					    &bind_interdomain);
+	if (error != 0) {
+		/*
+		 * XXX Trap Hypercall error code Linuxisms in
+		 *     the HYPERCALL layer.
+		 */
+		return (-error);
+	}
+
+	error = xen_intr_bind_isrc(&isrc, bind_interdomain.local_port,
+				 EVTCHN_TYPE_PORT, dev, filter, handler,
+				 arg, flags, port_handlep);
+	if (error) {
+		evtchn_close_t close = { .port = bind_interdomain.local_port };
+		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
+			panic("EVTCHNOP_close failed");
+		return (error);
+	}
+
+	/*
+	 * The Event Channel API opened this port, so it is
+	 * responsible for closing it automatically on unbind.
+	 */
+	isrc->xi_close = 1;
+	return (0);
+}
+
+int 
+xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
+    driver_filter_t filter, driver_intr_t handler, void *arg,
+    enum intr_type flags, xen_intr_handle_t *port_handlep)
+{
+	int vcpu_id = pcpu_find(cpu)->pc_vcpu_id;
+	struct xenisrc *isrc;
+	struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id };
+	int error;
+
+	/* Ensure the target CPU is ready to handle evtchn interrupts. */
+	xen_intr_intrcnt_add(cpu);
+
+	isrc = NULL;
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq);
+	if (error != 0) {
+		/*
+		 * XXX Trap Hypercall error code Linuxisms in
+		 *     the HYPERCALL layer.
+		 */
+		return (-error);
+	}
+
+	error = xen_intr_bind_isrc(&isrc, bind_virq.port, EVTCHN_TYPE_VIRQ, dev,
+				 filter, handler, arg, flags, port_handlep);
+
+#ifdef SMP
+	if (error == 0)
+		error = intr_event_bind(isrc->xi_intsrc.is_event, cpu);
+#endif
+
+	if (error != 0) {
+		evtchn_close_t close = { .port = bind_virq.port };
+
+		xen_intr_unbind(*port_handlep);
+		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
+			panic("EVTCHNOP_close failed");
+		return (error);
+	}
+
+#ifdef SMP
+	if (isrc->xi_cpu != cpu) {
+		/*
+		 * Too early in the boot process for the generic interrupt
+		 * code to perform the binding.  Update our event channel
+		 * masks manually so events can't fire on the wrong cpu
+		 * during AP startup.
+		 */
+		xen_intr_assign_cpu(&isrc->xi_intsrc, cpu_apic_ids[cpu]);
+	}
+#endif
+
+	/*
+	 * The Event Channel API opened this port, so it is
+	 * responsible for closing it automatically on unbind.
+	 */
+	isrc->xi_close = 1;
+	isrc->xi_virq = virq;
+
+	return (0);
+}
+
+int
+xen_intr_alloc_and_bind_ipi(device_t dev, u_int cpu,
+    driver_filter_t filter, enum intr_type flags,
+    xen_intr_handle_t *port_handlep)
+{
+#ifdef SMP
+	int vcpu_id = pcpu_find(cpu)->pc_vcpu_id;
+	struct xenisrc *isrc;
+	struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id };
+	int error;
+
+	/* Ensure the target CPU is ready to handle evtchn interrupts. */
+	xen_intr_intrcnt_add(cpu);
+
+	isrc = NULL;
+	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi);
+	if (error != 0) {
+		/*
+		 * XXX Trap Hypercall error code Linuxisms in
+		 *     the HYPERCALL layer.
+		 */
+		return (-error);
+	}
+
+	error = xen_intr_bind_isrc(&isrc, bind_ipi.port, EVTCHN_TYPE_IPI,
+	                           dev, filter, NULL, NULL, flags,
+	                           port_handlep);
+	if (error == 0)
+		error = intr_event_bind(isrc->xi_intsrc.is_event, cpu);
+
+	if (error != 0) {
+		evtchn_close_t close = { .port = bind_ipi.port };
+
+		xen_intr_unbind(*port_handlep);
+		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
+			panic("EVTCHNOP_close failed");
+		return (error);
+	}
+
+	if (isrc->xi_cpu != cpu) {
+		/*
+		 * Too early in the boot process for the generic interrupt
+		 * code to perform the binding.  Update our event channel
+		 * masks manually so events can't fire on the wrong cpu
+		 * during AP startup.
+		 */
+		xen_intr_assign_cpu(&isrc->xi_intsrc, cpu_apic_ids[cpu]);
+	}
+
+	/*
+	 * The Event Channel API opened this port, so it is
+	 * responsible for closing it automatically on unbind.
+	 */
+	isrc->xi_close = 1;
+	return (0);
+#else
+	return (EOPNOTSUPP);
+#endif
+}
+
+int
+xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...)
+{
+	char descr[MAXCOMLEN + 1];
+	struct xenisrc *isrc;
+	va_list ap;
+
+	isrc = xen_intr_isrc(port_handle);
+	if (isrc == NULL)
+		return (EINVAL);
+
+	va_start(ap, fmt);
+	vsnprintf(descr, sizeof(descr), fmt, ap);
+	va_end(ap);
+	return (intr_describe(isrc->xi_vector, port_handle, descr));
+}
+
+void
+xen_intr_unbind(xen_intr_handle_t *port_handlep)
+{
+	struct intr_handler *handler;
+	struct xenisrc *isrc;
+
+	handler = *port_handlep;
+	*port_handlep = NULL;
+	isrc = xen_intr_isrc(handler);
+	if (isrc == NULL)
+		return;
+
+	intr_remove_handler(handler);
+	xen_intr_release_isrc(isrc);
+}
+
+void
+xen_intr_signal(xen_intr_handle_t handle)
+{
+	struct xenisrc *isrc;
+
+	isrc = xen_intr_isrc(handle);
+	if (isrc != NULL) {
+		KASSERT(isrc->xi_type == EVTCHN_TYPE_PORT ||
+			isrc->xi_type == EVTCHN_TYPE_IPI,
+			("evtchn_signal on something other than a local port"));
+		struct evtchn_send send = { .port = isrc->xi_port };
+		(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+	}
+}
+
+evtchn_port_t
+xen_intr_port(xen_intr_handle_t handle)
+{
+	struct xenisrc *isrc;
+
+	isrc = xen_intr_isrc(handle);
+	if (isrc == NULL)
+		return (0);
+	
+	return (isrc->xi_port);
+}


Property changes on: trunk/sys/x86/xen/xen_intr.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list