Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2013 The FreeBSD Foundation
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This software was developed by Konstantin Belousov <kib@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$");
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2013-11-01 17:38:52 +00:00
|
|
|
#define DMAR_FAULT_IRQ_RID 0
|
|
|
|
#define DMAR_QI_IRQ_RID 1
|
|
|
|
#define DMAR_REG_RID 2
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
|
|
|
|
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");
|
2013-11-01 17:16:44 +00:00
|
|
|
return (BUS_PROBE_NOWILDCARD);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
}
|
|
|
|
|
2013-11-01 17:38:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
static void
|
|
|
|
dmar_release_resources(device_t dev, struct dmar_unit *unit)
|
|
|
|
{
|
2013-11-01 17:38:52 +00:00
|
|
|
int i;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
|
|
|
|
dmar_fini_busdma(unit);
|
2013-11-01 17:38:52 +00:00
|
|
|
dmar_fini_qi(unit);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
dmar_fini_fault_log(unit);
|
2013-11-01 17:38:52 +00:00
|
|
|
for (i = 0; i < DMAR_INTR_TOTAL; i++)
|
|
|
|
dmar_release_intr(dev, unit, i);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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
|
2013-11-01 17:38:52 +00:00
|
|
|
dmar_alloc_irq(device_t dev, struct dmar_unit *unit, int idx)
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
{
|
|
|
|
device_t pcib;
|
2013-11-01 17:38:52 +00:00
|
|
|
struct dmar_msi_data *dmd;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
uint64_t msi_addr;
|
|
|
|
uint32_t msi_data;
|
|
|
|
int error;
|
|
|
|
|
2013-11-01 17:38:52 +00:00
|
|
|
dmd = &unit->intrs[idx];
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
pcib = device_get_parent(device_get_parent(dev)); /* Really not pcib */
|
2013-11-01 17:38:52 +00:00
|
|
|
error = PCIB_ALLOC_MSIX(pcib, dev, &dmd->irq);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
if (error != 0) {
|
2013-11-01 17:38:52 +00:00
|
|
|
device_printf(dev, "cannot allocate %s interrupt, %d\n",
|
|
|
|
dmd->name, error);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
goto err1;
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
error = bus_set_resource(dev, SYS_RES_IRQ, dmd->irq_rid,
|
|
|
|
dmd->irq, 1);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
if (error != 0) {
|
2013-11-01 17:38:52 +00:00
|
|
|
device_printf(dev, "cannot set %s interrupt resource, %d\n",
|
|
|
|
dmd->name, error);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
goto err2;
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
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);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
error = ENXIO;
|
|
|
|
goto err3;
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
error = bus_setup_intr(dev, dmd->irq_res, INTR_TYPE_MISC,
|
|
|
|
dmd->handler, NULL, unit, &dmd->intr_handle);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
if (error != 0) {
|
2013-11-01 17:38:52 +00:00
|
|
|
device_printf(dev, "cannot setup %s interrupt, %d\n",
|
|
|
|
dmd->name, error);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
goto err4;
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
bus_describe_intr(dev, dmd->irq_res, dmd->intr_handle, dmd->name);
|
|
|
|
error = PCIB_MAP_MSI(pcib, dev, dmd->irq, &msi_addr, &msi_data);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
if (error != 0) {
|
2013-11-01 17:38:52 +00:00
|
|
|
device_printf(dev, "cannot map %s interrupt, %d\n",
|
|
|
|
dmd->name, error);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
goto err5;
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
dmar_write4(unit, dmd->msi_data_reg, msi_data);
|
|
|
|
dmar_write4(unit, dmd->msi_addr_reg, msi_addr);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
/* Only for xAPIC mode */
|
2013-11-01 17:38:52 +00:00
|
|
|
dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
err5:
|
2013-11-01 17:38:52 +00:00
|
|
|
bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
err4:
|
2013-11-01 17:38:52 +00:00
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
err3:
|
2013-11-01 17:38:52 +00:00
|
|
|
bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
err2:
|
2013-11-01 17:38:52 +00:00
|
|
|
PCIB_RELEASE_MSIX(pcib, dev, dmd->irq);
|
|
|
|
dmd->irq = -1;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
err1:
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEV_APIC
|
|
|
|
static int
|
|
|
|
dmar_remap_intr(device_t dev, device_t child, u_int irq)
|
|
|
|
{
|
|
|
|
struct dmar_unit *unit;
|
2013-11-01 17:38:52 +00:00
|
|
|
struct dmar_msi_data *dmd;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
uint64_t msi_addr;
|
|
|
|
uint32_t msi_data;
|
2013-11-01 17:38:52 +00:00
|
|
|
int i, error;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
|
|
|
|
unit = device_get_softc(dev);
|
2013-11-01 17:38:52 +00:00
|
|
|
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);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
}
|
|
|
|
#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@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");
|
|
|
|
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");
|
|
|
|
printf("%b, ", ecaphi, "\020");
|
|
|
|
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;
|
2013-11-01 17:38:52 +00:00
|
|
|
int i, error;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-11-01 17:38:52 +00:00
|
|
|
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);
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
if (error != 0) {
|
|
|
|
dmar_release_resources(dev, unit);
|
|
|
|
return (error);
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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);
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
error = dmar_init_qi(unit);
|
|
|
|
if (error != 0) {
|
|
|
|
dmar_release_resources(dev, unit);
|
|
|
|
return (error);
|
|
|
|
}
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-11-09 20:09:02 +00:00
|
|
|
ptr = (const char *)resmem + sizeof(*resmem);
|
|
|
|
ptrend = (const char *)resmem + resmem->Header.Length;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
for (;;) {
|
|
|
|
if (ptr >= ptrend)
|
|
|
|
break;
|
2013-11-09 20:09:02 +00:00
|
|
|
devscope = (const ACPI_DMAR_DEVICE_SCOPE *)ptr;
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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,
|
2013-11-09 20:09:02 +00:00
|
|
|
(const ACPI_DMAR_PCI_PATH *)(devscope + 1));
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
}
|
|
|
|
dev = dmar_path_dev(resmem->Segment, (devscope->Length -
|
|
|
|
sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2, devscope->Bus,
|
2013-11-09 20:09:02 +00:00
|
|
|
(const ACPI_DMAR_PCI_PATH *)(devscope + 1));
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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, ctx->bus, ctx->slot, ctx->func, 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();
|
|
|
|
}
|
|
|
|
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 == ctx->bus &&
|
|
|
|
device == ctx->slot && function == ctx->func) {
|
|
|
|
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));
|
|
|
|
}
|
2013-11-01 17:38:52 +00:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
Import the driver for VT-d DMAR hardware, as specified in the revision
1.3 of Intelб╝ Virtualization Technology for Directed I/O Architecture
Specification. The Extended Context and PASIDs from the rev. 2.2 are
not supported, but I am not aware of any released hardware which
implements them. Code does not use queued invalidation, see comments
for the reason, and does not provide interrupt remapping services.
Code implements the management of the guest address space per domain
and allows to establish and tear down arbitrary mappings, but not
partial unmapping. The superpages are created as needed, but not
promoted. Faults are recorded, fault records could be obtained
programmatically, and printed on the console.
Implement the busdma(9) using DMARs. This busdma backend avoids
bouncing and provides security against misbehaving hardware and driver
bad programming, preventing leaks and corruption of the memory by wild
DMA accesses.
By default, the implementation is compiled into amd64 GENERIC kernel
but disabled; to enable, set hw.dmar.enable=1 loader tunable. Code is
written to work on i386, but testing there was low priority, and
driver is not enabled in GENERIC. Even with the DMAR turned on,
individual devices could be directed to use the bounce busdma with the
hw.busdma.pci<domain>:<bus>:<device>:<function>.bounce=1 tunable. If
DMARs are capable of the pass-through translations, it is used,
otherwise, an identity-mapping page table is constructed.
The driver was tested on Xeon 5400/5500 chipset legacy machine,
Haswell desktop and E5 SandyBridge dual-socket boxes, with ahci(4),
ata(4), bce(4), ehci(4), mfi(4), uhci(4), xhci(4) devices. It also
works with em(4) and igb(4), but there some fixes are needed for
drivers, which are not committed yet. Intel GPUs do not work with
DMAR (yet).
Many thanks to John Baldwin, who explained me the newbus integration;
Peter Holm, who did all testing and helped me to discover and
understand several incredible bugs; and to Jim Harris for the access
to the EDS and BWG and for listening when I have to explain my
findings to somebody.
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
2013-10-28 13:33:29 +00:00
|
|
|
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
|