xref: /freebsd/sys/amd64/vmm/intel/vtd.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 NetApp, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41 
42 #include <dev/pci/pcireg.h>
43 
44 #include <machine/vmparam.h>
45 #include <contrib/dev/acpica/include/acpi.h>
46 
47 #include "io/iommu.h"
48 
49 /*
50  * Documented in the "Intel Virtualization Technology for Directed I/O",
51  * Architecture Spec, September 2008.
52  */
53 
54 /* Section 10.4 "Register Descriptions" */
55 struct vtdmap {
56 	volatile uint32_t	version;
57 	volatile uint32_t	res0;
58 	volatile uint64_t	cap;
59 	volatile uint64_t	ext_cap;
60 	volatile uint32_t	gcr;
61 	volatile uint32_t	gsr;
62 	volatile uint64_t	rta;
63 	volatile uint64_t	ccr;
64 };
65 
66 #define	VTD_CAP_SAGAW(cap)	(((cap) >> 8) & 0x1F)
67 #define	VTD_CAP_ND(cap)		((cap) & 0x7)
68 #define	VTD_CAP_CM(cap)		(((cap) >> 7) & 0x1)
69 #define	VTD_CAP_SPS(cap)	(((cap) >> 34) & 0xF)
70 #define	VTD_CAP_RWBF(cap)	(((cap) >> 4) & 0x1)
71 
72 #define	VTD_ECAP_DI(ecap)	(((ecap) >> 2) & 0x1)
73 #define	VTD_ECAP_COHERENCY(ecap) ((ecap) & 0x1)
74 #define	VTD_ECAP_IRO(ecap)	(((ecap) >> 8) & 0x3FF)
75 
76 #define	VTD_GCR_WBF		(1 << 27)
77 #define	VTD_GCR_SRTP		(1 << 30)
78 #define	VTD_GCR_TE		(1U << 31)
79 
80 #define	VTD_GSR_WBFS		(1 << 27)
81 #define	VTD_GSR_RTPS		(1 << 30)
82 #define	VTD_GSR_TES		(1U << 31)
83 
84 #define	VTD_CCR_ICC		(1UL << 63)	/* invalidate context cache */
85 #define	VTD_CCR_CIRG_GLOBAL	(1UL << 61)	/* global invalidation */
86 
87 #define	VTD_IIR_IVT		(1UL << 63)	/* invalidation IOTLB */
88 #define	VTD_IIR_IIRG_GLOBAL	(1ULL << 60)	/* global IOTLB invalidation */
89 #define	VTD_IIR_IIRG_DOMAIN	(2ULL << 60)	/* domain IOTLB invalidation */
90 #define	VTD_IIR_IIRG_PAGE	(3ULL << 60)	/* page IOTLB invalidation */
91 #define	VTD_IIR_DRAIN_READS	(1ULL << 49)	/* drain pending DMA reads */
92 #define	VTD_IIR_DRAIN_WRITES	(1ULL << 48)	/* drain pending DMA writes */
93 #define	VTD_IIR_DOMAIN_P	32
94 
95 #define	VTD_ROOT_PRESENT	0x1
96 #define	VTD_CTX_PRESENT		0x1
97 #define	VTD_CTX_TT_ALL		(1UL << 2)
98 
99 #define	VTD_PTE_RD		(1UL << 0)
100 #define	VTD_PTE_WR		(1UL << 1)
101 #define	VTD_PTE_SUPERPAGE	(1UL << 7)
102 #define	VTD_PTE_ADDR_M		(0x000FFFFFFFFFF000UL)
103 
104 #define VTD_RID2IDX(rid)	(((rid) & 0xff) * 2)
105 
106 struct domain {
107 	uint64_t	*ptp;		/* first level page table page */
108 	int		pt_levels;	/* number of page table levels */
109 	int		addrwidth;	/* 'AW' field in context entry */
110 	int		spsmask;	/* supported super page sizes */
111 	u_int		id;		/* domain id */
112 	vm_paddr_t	maxaddr;	/* highest address to be mapped */
113 	SLIST_ENTRY(domain) next;
114 };
115 
116 static SLIST_HEAD(, domain) domhead;
117 
118 #define	DRHD_MAX_UNITS	8
119 static int		drhd_num;
120 static struct vtdmap	*vtdmaps[DRHD_MAX_UNITS];
121 static int		max_domains;
122 typedef int		(*drhd_ident_func_t)(void);
123 
124 static uint64_t root_table[PAGE_SIZE / sizeof(uint64_t)] __aligned(4096);
125 static uint64_t ctx_tables[256][PAGE_SIZE / sizeof(uint64_t)] __aligned(4096);
126 
127 static MALLOC_DEFINE(M_VTD, "vtd", "vtd");
128 
129 static int
130 vtd_max_domains(struct vtdmap *vtdmap)
131 {
132 	int nd;
133 
134 	nd = VTD_CAP_ND(vtdmap->cap);
135 
136 	switch (nd) {
137 	case 0:
138 		return (16);
139 	case 1:
140 		return (64);
141 	case 2:
142 		return (256);
143 	case 3:
144 		return (1024);
145 	case 4:
146 		return (4 * 1024);
147 	case 5:
148 		return (16 * 1024);
149 	case 6:
150 		return (64 * 1024);
151 	default:
152 		panic("vtd_max_domains: invalid value of nd (0x%0x)", nd);
153 	}
154 }
155 
156 static u_int
157 domain_id(void)
158 {
159 	u_int id;
160 	struct domain *dom;
161 
162 	/* Skip domain id 0 - it is reserved when Caching Mode field is set */
163 	for (id = 1; id < max_domains; id++) {
164 		SLIST_FOREACH(dom, &domhead, next) {
165 			if (dom->id == id)
166 				break;
167 		}
168 		if (dom == NULL)
169 			break;		/* found it */
170 	}
171 
172 	if (id >= max_domains)
173 		panic("domain ids exhausted");
174 
175 	return (id);
176 }
177 
178 static void
179 vtd_wbflush(struct vtdmap *vtdmap)
180 {
181 
182 	if (VTD_ECAP_COHERENCY(vtdmap->ext_cap) == 0)
183 		pmap_invalidate_cache();
184 
185 	if (VTD_CAP_RWBF(vtdmap->cap)) {
186 		vtdmap->gcr = VTD_GCR_WBF;
187 		while ((vtdmap->gsr & VTD_GSR_WBFS) != 0)
188 			;
189 	}
190 }
191 
192 static void
193 vtd_ctx_global_invalidate(struct vtdmap *vtdmap)
194 {
195 
196 	vtdmap->ccr = VTD_CCR_ICC | VTD_CCR_CIRG_GLOBAL;
197 	while ((vtdmap->ccr & VTD_CCR_ICC) != 0)
198 		;
199 }
200 
201 static void
202 vtd_iotlb_global_invalidate(struct vtdmap *vtdmap)
203 {
204 	int offset;
205 	volatile uint64_t *iotlb_reg, val;
206 
207 	vtd_wbflush(vtdmap);
208 
209 	offset = VTD_ECAP_IRO(vtdmap->ext_cap) * 16;
210 	iotlb_reg = (volatile uint64_t *)((caddr_t)vtdmap + offset + 8);
211 
212 	*iotlb_reg =  VTD_IIR_IVT | VTD_IIR_IIRG_GLOBAL |
213 		      VTD_IIR_DRAIN_READS | VTD_IIR_DRAIN_WRITES;
214 
215 	while (1) {
216 		val = *iotlb_reg;
217 		if ((val & VTD_IIR_IVT) == 0)
218 			break;
219 	}
220 }
221 
222 static void
223 vtd_translation_enable(struct vtdmap *vtdmap)
224 {
225 
226 	vtdmap->gcr = VTD_GCR_TE;
227 	while ((vtdmap->gsr & VTD_GSR_TES) == 0)
228 		;
229 }
230 
231 static void
232 vtd_translation_disable(struct vtdmap *vtdmap)
233 {
234 
235 	vtdmap->gcr = 0;
236 	while ((vtdmap->gsr & VTD_GSR_TES) != 0)
237 		;
238 }
239 
240 static int
241 vtd_init(void)
242 {
243 	int i, units, remaining;
244 	struct vtdmap *vtdmap;
245 	vm_paddr_t ctx_paddr;
246 	char *end, envname[32];
247 	unsigned long mapaddr;
248 	ACPI_STATUS status;
249 	ACPI_TABLE_DMAR *dmar;
250 	ACPI_DMAR_HEADER *hdr;
251 	ACPI_DMAR_HARDWARE_UNIT *drhd;
252 
253 	/*
254 	 * Allow the user to override the ACPI DMAR table by specifying the
255 	 * physical address of each remapping unit.
256 	 *
257 	 * The following example specifies two remapping units at
258 	 * physical addresses 0xfed90000 and 0xfeda0000 respectively.
259 	 * set vtd.regmap.0.addr=0xfed90000
260 	 * set vtd.regmap.1.addr=0xfeda0000
261 	 */
262 	for (units = 0; units < DRHD_MAX_UNITS; units++) {
263 		snprintf(envname, sizeof(envname), "vtd.regmap.%d.addr", units);
264 		if (getenv_ulong(envname, &mapaddr) == 0)
265 			break;
266 		vtdmaps[units] = (struct vtdmap *)PHYS_TO_DMAP(mapaddr);
267 	}
268 
269 	if (units > 0)
270 		goto skip_dmar;
271 
272 	/* Search for DMAR table. */
273 	status = AcpiGetTable(ACPI_SIG_DMAR, 0, (ACPI_TABLE_HEADER **)&dmar);
274 	if (ACPI_FAILURE(status))
275 		return (ENXIO);
276 
277 	end = (char *)dmar + dmar->Header.Length;
278 	remaining = dmar->Header.Length - sizeof(ACPI_TABLE_DMAR);
279 	while (remaining > sizeof(ACPI_DMAR_HEADER)) {
280 		hdr = (ACPI_DMAR_HEADER *)(end - remaining);
281 		if (hdr->Length > remaining)
282 			break;
283 		/*
284 		 * From Intel VT-d arch spec, version 1.3:
285 		 * BIOS implementations must report mapping structures
286 		 * in numerical order, i.e. All remapping structures of
287 		 * type 0 (DRHD) enumerated before remapping structures of
288 		 * type 1 (RMRR) and so forth.
289 		 */
290 		if (hdr->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT)
291 			break;
292 
293 		drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr;
294 		vtdmaps[units++] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address);
295 		if (units >= DRHD_MAX_UNITS)
296 			break;
297 		remaining -= hdr->Length;
298 	}
299 
300 	if (units <= 0)
301 		return (ENXIO);
302 
303 skip_dmar:
304 	drhd_num = units;
305 	vtdmap = vtdmaps[0];
306 
307 	if (VTD_CAP_CM(vtdmap->cap) != 0)
308 		panic("vtd_init: invalid caching mode");
309 
310 	max_domains = vtd_max_domains(vtdmap);
311 
312 	/*
313 	 * Set up the root-table to point to the context-entry tables
314 	 */
315 	for (i = 0; i < 256; i++) {
316 		ctx_paddr = vtophys(ctx_tables[i]);
317 		if (ctx_paddr & PAGE_MASK)
318 			panic("ctx table (0x%0lx) not page aligned", ctx_paddr);
319 
320 		root_table[i * 2] = ctx_paddr | VTD_ROOT_PRESENT;
321 	}
322 
323 	return (0);
324 }
325 
326 static void
327 vtd_cleanup(void)
328 {
329 }
330 
331 static void
332 vtd_enable(void)
333 {
334 	int i;
335 	struct vtdmap *vtdmap;
336 
337 	for (i = 0; i < drhd_num; i++) {
338 		vtdmap = vtdmaps[i];
339 		vtd_wbflush(vtdmap);
340 
341 		/* Update the root table address */
342 		vtdmap->rta = vtophys(root_table);
343 		vtdmap->gcr = VTD_GCR_SRTP;
344 		while ((vtdmap->gsr & VTD_GSR_RTPS) == 0)
345 			;
346 
347 		vtd_ctx_global_invalidate(vtdmap);
348 		vtd_iotlb_global_invalidate(vtdmap);
349 
350 		vtd_translation_enable(vtdmap);
351 	}
352 }
353 
354 static void
355 vtd_disable(void)
356 {
357 	int i;
358 	struct vtdmap *vtdmap;
359 
360 	for (i = 0; i < drhd_num; i++) {
361 		vtdmap = vtdmaps[i];
362 		vtd_translation_disable(vtdmap);
363 	}
364 }
365 
366 static void
367 vtd_add_device(void *arg, uint16_t rid)
368 {
369 	int idx;
370 	uint64_t *ctxp;
371 	struct domain *dom = arg;
372 	vm_paddr_t pt_paddr;
373 	struct vtdmap *vtdmap;
374 	uint8_t bus;
375 
376 	vtdmap = vtdmaps[0];
377 	bus = PCI_RID2BUS(rid);
378 	ctxp = ctx_tables[bus];
379 	pt_paddr = vtophys(dom->ptp);
380 	idx = VTD_RID2IDX(rid);
381 
382 	if (ctxp[idx] & VTD_CTX_PRESENT) {
383 		panic("vtd_add_device: device %x is already owned by "
384 		      "domain %d", rid,
385 		      (uint16_t)(ctxp[idx + 1] >> 8));
386 	}
387 
388 	/*
389 	 * Order is important. The 'present' bit is set only after all fields
390 	 * of the context pointer are initialized.
391 	 */
392 	ctxp[idx + 1] = dom->addrwidth | (dom->id << 8);
393 
394 	if (VTD_ECAP_DI(vtdmap->ext_cap))
395 		ctxp[idx] = VTD_CTX_TT_ALL;
396 	else
397 		ctxp[idx] = 0;
398 
399 	ctxp[idx] |= pt_paddr | VTD_CTX_PRESENT;
400 
401 	/*
402 	 * 'Not Present' entries are not cached in either the Context Cache
403 	 * or in the IOTLB, so there is no need to invalidate either of them.
404 	 */
405 }
406 
407 static void
408 vtd_remove_device(void *arg, uint16_t rid)
409 {
410 	int i, idx;
411 	uint64_t *ctxp;
412 	struct vtdmap *vtdmap;
413 	uint8_t bus;
414 
415 	bus = PCI_RID2BUS(rid);
416 	ctxp = ctx_tables[bus];
417 	idx = VTD_RID2IDX(rid);
418 
419 	/*
420 	 * Order is important. The 'present' bit is must be cleared first.
421 	 */
422 	ctxp[idx] = 0;
423 	ctxp[idx + 1] = 0;
424 
425 	/*
426 	 * Invalidate the Context Cache and the IOTLB.
427 	 *
428 	 * XXX use device-selective invalidation for Context Cache
429 	 * XXX use domain-selective invalidation for IOTLB
430 	 */
431 	for (i = 0; i < drhd_num; i++) {
432 		vtdmap = vtdmaps[i];
433 		vtd_ctx_global_invalidate(vtdmap);
434 		vtd_iotlb_global_invalidate(vtdmap);
435 	}
436 }
437 
438 #define	CREATE_MAPPING	0
439 #define	REMOVE_MAPPING	1
440 
441 static uint64_t
442 vtd_update_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len,
443 		   int remove)
444 {
445 	struct domain *dom;
446 	int i, spshift, ptpshift, ptpindex, nlevels;
447 	uint64_t spsize, *ptp;
448 
449 	dom = arg;
450 	ptpindex = 0;
451 	ptpshift = 0;
452 
453 	KASSERT(gpa + len > gpa, ("%s: invalid gpa range %#lx/%#lx", __func__,
454 	    gpa, len));
455 	KASSERT(gpa + len <= dom->maxaddr, ("%s: gpa range %#lx/%#lx beyond "
456 	    "domain maxaddr %#lx", __func__, gpa, len, dom->maxaddr));
457 
458 	if (gpa & PAGE_MASK)
459 		panic("vtd_create_mapping: unaligned gpa 0x%0lx", gpa);
460 
461 	if (hpa & PAGE_MASK)
462 		panic("vtd_create_mapping: unaligned hpa 0x%0lx", hpa);
463 
464 	if (len & PAGE_MASK)
465 		panic("vtd_create_mapping: unaligned len 0x%0lx", len);
466 
467 	/*
468 	 * Compute the size of the mapping that we can accommodate.
469 	 *
470 	 * This is based on three factors:
471 	 * - supported super page size
472 	 * - alignment of the region starting at 'gpa' and 'hpa'
473 	 * - length of the region 'len'
474 	 */
475 	spshift = 48;
476 	for (i = 3; i >= 0; i--) {
477 		spsize = 1UL << spshift;
478 		if ((dom->spsmask & (1 << i)) != 0 &&
479 		    (gpa & (spsize - 1)) == 0 &&
480 		    (hpa & (spsize - 1)) == 0 &&
481 		    (len >= spsize)) {
482 			break;
483 		}
484 		spshift -= 9;
485 	}
486 
487 	ptp = dom->ptp;
488 	nlevels = dom->pt_levels;
489 	while (--nlevels >= 0) {
490 		ptpshift = 12 + nlevels * 9;
491 		ptpindex = (gpa >> ptpshift) & 0x1FF;
492 
493 		/* We have reached the leaf mapping */
494 		if (spshift >= ptpshift) {
495 			break;
496 		}
497 
498 		/*
499 		 * We are working on a non-leaf page table page.
500 		 *
501 		 * Create a downstream page table page if necessary and point
502 		 * to it from the current page table.
503 		 */
504 		if (ptp[ptpindex] == 0) {
505 			void *nlp = malloc(PAGE_SIZE, M_VTD, M_WAITOK | M_ZERO);
506 			ptp[ptpindex] = vtophys(nlp)| VTD_PTE_RD | VTD_PTE_WR;
507 		}
508 
509 		ptp = (uint64_t *)PHYS_TO_DMAP(ptp[ptpindex] & VTD_PTE_ADDR_M);
510 	}
511 
512 	if ((gpa & ((1UL << ptpshift) - 1)) != 0)
513 		panic("gpa 0x%lx and ptpshift %d mismatch", gpa, ptpshift);
514 
515 	/*
516 	 * Update the 'gpa' -> 'hpa' mapping
517 	 */
518 	if (remove) {
519 		ptp[ptpindex] = 0;
520 	} else {
521 		ptp[ptpindex] = hpa | VTD_PTE_RD | VTD_PTE_WR;
522 
523 		if (nlevels > 0)
524 			ptp[ptpindex] |= VTD_PTE_SUPERPAGE;
525 	}
526 
527 	return (1UL << ptpshift);
528 }
529 
530 static uint64_t
531 vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
532 {
533 
534 	return (vtd_update_mapping(arg, gpa, hpa, len, CREATE_MAPPING));
535 }
536 
537 static uint64_t
538 vtd_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
539 {
540 
541 	return (vtd_update_mapping(arg, gpa, 0, len, REMOVE_MAPPING));
542 }
543 
544 static void
545 vtd_invalidate_tlb(void *dom)
546 {
547 	int i;
548 	struct vtdmap *vtdmap;
549 
550 	/*
551 	 * Invalidate the IOTLB.
552 	 * XXX use domain-selective invalidation for IOTLB
553 	 */
554 	for (i = 0; i < drhd_num; i++) {
555 		vtdmap = vtdmaps[i];
556 		vtd_iotlb_global_invalidate(vtdmap);
557 	}
558 }
559 
560 static void *
561 vtd_create_domain(vm_paddr_t maxaddr)
562 {
563 	struct domain *dom;
564 	vm_paddr_t addr;
565 	int tmp, i, gaw, agaw, sagaw, res, pt_levels, addrwidth;
566 	struct vtdmap *vtdmap;
567 
568 	if (drhd_num <= 0)
569 		panic("vtd_create_domain: no dma remapping hardware available");
570 
571 	vtdmap = vtdmaps[0];
572 
573 	/*
574 	 * Calculate AGAW.
575 	 * Section 3.4.2 "Adjusted Guest Address Width", Architecture Spec.
576 	 */
577 	addr = 0;
578 	for (gaw = 0; addr < maxaddr; gaw++)
579 		addr = 1ULL << gaw;
580 
581 	res = (gaw - 12) % 9;
582 	if (res == 0)
583 		agaw = gaw;
584 	else
585 		agaw = gaw + 9 - res;
586 
587 	if (agaw > 64)
588 		agaw = 64;
589 
590 	/*
591 	 * Select the smallest Supported AGAW and the corresponding number
592 	 * of page table levels.
593 	 */
594 	pt_levels = 2;
595 	sagaw = 30;
596 	addrwidth = 0;
597 	tmp = VTD_CAP_SAGAW(vtdmap->cap);
598 	for (i = 0; i < 5; i++) {
599 		if ((tmp & (1 << i)) != 0 && sagaw >= agaw)
600 			break;
601 		pt_levels++;
602 		addrwidth++;
603 		sagaw += 9;
604 		if (sagaw > 64)
605 			sagaw = 64;
606 	}
607 
608 	if (i >= 5) {
609 		panic("vtd_create_domain: SAGAW 0x%lx does not support AGAW %d",
610 		      VTD_CAP_SAGAW(vtdmap->cap), agaw);
611 	}
612 
613 	dom = malloc(sizeof(struct domain), M_VTD, M_ZERO | M_WAITOK);
614 	dom->pt_levels = pt_levels;
615 	dom->addrwidth = addrwidth;
616 	dom->id = domain_id();
617 	dom->maxaddr = maxaddr;
618 	dom->ptp = malloc(PAGE_SIZE, M_VTD, M_ZERO | M_WAITOK);
619 	if ((uintptr_t)dom->ptp & PAGE_MASK)
620 		panic("vtd_create_domain: ptp (%p) not page aligned", dom->ptp);
621 
622 #ifdef notyet
623 	/*
624 	 * XXX superpage mappings for the iommu do not work correctly.
625 	 *
626 	 * By default all physical memory is mapped into the host_domain.
627 	 * When a VM is allocated wired memory the pages belonging to it
628 	 * are removed from the host_domain and added to the vm's domain.
629 	 *
630 	 * If the page being removed was mapped using a superpage mapping
631 	 * in the host_domain then we need to demote the mapping before
632 	 * removing the page.
633 	 *
634 	 * There is not any code to deal with the demotion at the moment
635 	 * so we disable superpage mappings altogether.
636 	 */
637 	dom->spsmask = VTD_CAP_SPS(vtdmap->cap);
638 #endif
639 
640 	SLIST_INSERT_HEAD(&domhead, dom, next);
641 
642 	return (dom);
643 }
644 
645 static void
646 vtd_free_ptp(uint64_t *ptp, int level)
647 {
648 	int i;
649 	uint64_t *nlp;
650 
651 	if (level > 1) {
652 		for (i = 0; i < 512; i++) {
653 			if ((ptp[i] & (VTD_PTE_RD | VTD_PTE_WR)) == 0)
654 				continue;
655 			if ((ptp[i] & VTD_PTE_SUPERPAGE) != 0)
656 				continue;
657 			nlp = (uint64_t *)PHYS_TO_DMAP(ptp[i] & VTD_PTE_ADDR_M);
658 			vtd_free_ptp(nlp, level - 1);
659 		}
660 	}
661 
662 	bzero(ptp, PAGE_SIZE);
663 	free(ptp, M_VTD);
664 }
665 
666 static void
667 vtd_destroy_domain(void *arg)
668 {
669 	struct domain *dom;
670 
671 	dom = arg;
672 
673 	SLIST_REMOVE(&domhead, dom, domain, next);
674 	vtd_free_ptp(dom->ptp, dom->pt_levels);
675 	free(dom, M_VTD);
676 }
677 
678 struct iommu_ops iommu_ops_intel = {
679 	vtd_init,
680 	vtd_cleanup,
681 	vtd_enable,
682 	vtd_disable,
683 	vtd_create_domain,
684 	vtd_destroy_domain,
685 	vtd_create_mapping,
686 	vtd_remove_mapping,
687 	vtd_add_device,
688 	vtd_remove_device,
689 	vtd_invalidate_tlb,
690 };
691