[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, ®s[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", ®s[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