]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/vmm/intel/vtd.c
Fix host crash in bhyve with PCI device passthrough.
[FreeBSD/FreeBSD.git] / sys / amd64 / vmm / intel / vtd.c
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 #define VTD_DRHD_INCLUDE_PCI_ALL(Flags)  (((Flags) >> 0) & 0x1)
55
56 /* Section 10.4 "Register Descriptions" */
57 struct vtdmap {
58         volatile uint32_t       version;
59         volatile uint32_t       res0;
60         volatile uint64_t       cap;
61         volatile uint64_t       ext_cap;
62         volatile uint32_t       gcr;
63         volatile uint32_t       gsr;
64         volatile uint64_t       rta;
65         volatile uint64_t       ccr;
66 };
67
68 #define VTD_CAP_SAGAW(cap)      (((cap) >> 8) & 0x1F)
69 #define VTD_CAP_ND(cap)         ((cap) & 0x7)
70 #define VTD_CAP_CM(cap)         (((cap) >> 7) & 0x1)
71 #define VTD_CAP_SPS(cap)        (((cap) >> 34) & 0xF)
72 #define VTD_CAP_RWBF(cap)       (((cap) >> 4) & 0x1)
73
74 #define VTD_ECAP_DI(ecap)       (((ecap) >> 2) & 0x1)
75 #define VTD_ECAP_COHERENCY(ecap) ((ecap) & 0x1)
76 #define VTD_ECAP_IRO(ecap)      (((ecap) >> 8) & 0x3FF)
77
78 #define VTD_GCR_WBF             (1 << 27)
79 #define VTD_GCR_SRTP            (1 << 30)
80 #define VTD_GCR_TE              (1U << 31)
81
82 #define VTD_GSR_WBFS            (1 << 27)
83 #define VTD_GSR_RTPS            (1 << 30)
84 #define VTD_GSR_TES             (1U << 31)
85
86 #define VTD_CCR_ICC             (1UL << 63)     /* invalidate context cache */
87 #define VTD_CCR_CIRG_GLOBAL     (1UL << 61)     /* global invalidation */
88
89 #define VTD_IIR_IVT             (1UL << 63)     /* invalidation IOTLB */
90 #define VTD_IIR_IIRG_GLOBAL     (1ULL << 60)    /* global IOTLB invalidation */
91 #define VTD_IIR_IIRG_DOMAIN     (2ULL << 60)    /* domain IOTLB invalidation */
92 #define VTD_IIR_IIRG_PAGE       (3ULL << 60)    /* page IOTLB invalidation */
93 #define VTD_IIR_DRAIN_READS     (1ULL << 49)    /* drain pending DMA reads */
94 #define VTD_IIR_DRAIN_WRITES    (1ULL << 48)    /* drain pending DMA writes */
95 #define VTD_IIR_DOMAIN_P        32
96
97 #define VTD_ROOT_PRESENT        0x1
98 #define VTD_CTX_PRESENT         0x1
99 #define VTD_CTX_TT_ALL          (1UL << 2)
100
101 #define VTD_PTE_RD              (1UL << 0)
102 #define VTD_PTE_WR              (1UL << 1)
103 #define VTD_PTE_SUPERPAGE       (1UL << 7)
104 #define VTD_PTE_ADDR_M          (0x000FFFFFFFFFF000UL)
105
106 #define VTD_RID2IDX(rid)        (((rid) & 0xff) * 2)
107
108 struct domain {
109         uint64_t        *ptp;           /* first level page table page */
110         int             pt_levels;      /* number of page table levels */
111         int             addrwidth;      /* 'AW' field in context entry */
112         int             spsmask;        /* supported super page sizes */
113         u_int           id;             /* domain id */
114         vm_paddr_t      maxaddr;        /* highest address to be mapped */
115         SLIST_ENTRY(domain) next;
116 };
117
118 static SLIST_HEAD(, domain) domhead;
119
120 #define DRHD_MAX_UNITS  8
121 static ACPI_DMAR_HARDWARE_UNIT  *drhds[DRHD_MAX_UNITS];
122 static int                      drhd_num;
123 static struct vtdmap            *vtdmaps[DRHD_MAX_UNITS];
124 static int                      max_domains;
125 typedef int                     (*drhd_ident_func_t)(void);
126
127 static uint64_t root_table[PAGE_SIZE / sizeof(uint64_t)] __aligned(4096);
128 static uint64_t ctx_tables[256][PAGE_SIZE / sizeof(uint64_t)] __aligned(4096);
129
130 static MALLOC_DEFINE(M_VTD, "vtd", "vtd");
131
132 static int
133 vtd_max_domains(struct vtdmap *vtdmap)
134 {
135         int nd;
136
137         nd = VTD_CAP_ND(vtdmap->cap);
138
139         switch (nd) {
140         case 0:
141                 return (16);
142         case 1:
143                 return (64);
144         case 2:
145                 return (256);
146         case 3:
147                 return (1024);
148         case 4:
149                 return (4 * 1024);
150         case 5:
151                 return (16 * 1024);
152         case 6:
153                 return (64 * 1024);
154         default:
155                 panic("vtd_max_domains: invalid value of nd (0x%0x)", nd);
156         }
157 }
158
159 static u_int
160 domain_id(void)
161 {
162         u_int id;
163         struct domain *dom;
164
165         /* Skip domain id 0 - it is reserved when Caching Mode field is set */
166         for (id = 1; id < max_domains; id++) {
167                 SLIST_FOREACH(dom, &domhead, next) {
168                         if (dom->id == id)
169                                 break;
170                 }
171                 if (dom == NULL)
172                         break;          /* found it */
173         }
174         
175         if (id >= max_domains)
176                 panic("domain ids exhausted");
177
178         return (id);
179 }
180
181 static struct vtdmap *
182 vtd_device_scope(uint16_t rid)
183 {
184         int i, remaining, pathremaining;
185         char *end, *pathend;
186         struct vtdmap *vtdmap;
187         ACPI_DMAR_HARDWARE_UNIT *drhd;
188         ACPI_DMAR_DEVICE_SCOPE *device_scope;
189         ACPI_DMAR_PCI_PATH *path;
190
191         for (i = 0; i < drhd_num; i++) {
192                 drhd = drhds[i];
193
194                 if (VTD_DRHD_INCLUDE_PCI_ALL(drhd->Flags)) {
195                         /*
196                          * From Intel VT-d arch spec, version 3.0:
197                          * If a DRHD structure with INCLUDE_PCI_ALL flag Set is reported
198                          * for a Segment, it must be enumerated by BIOS after all other
199                          * DRHD structures for the same Segment.
200                          */
201                         vtdmap = vtdmaps[i];
202                         return(vtdmap);
203                 }
204
205                 end = (char *)drhd + drhd->Header.Length;
206                 remaining = drhd->Header.Length - sizeof(ACPI_DMAR_HARDWARE_UNIT);
207                 while (remaining > sizeof(ACPI_DMAR_DEVICE_SCOPE)) {
208                         device_scope = (ACPI_DMAR_DEVICE_SCOPE *)(end - remaining);
209                         remaining -= device_scope->Length;
210
211                         switch (device_scope->EntryType){
212                                 /* 0x01 and 0x02 are PCI device entries */
213                                 case 0x01:
214                                 case 0x02:
215                                         break;
216                                 default:
217                                         continue;
218                         }
219
220                         if (PCI_RID2BUS(rid) != device_scope->Bus)
221                                 continue;
222
223                         pathend = (char *)device_scope + device_scope->Length;
224                         pathremaining = device_scope->Length - sizeof(ACPI_DMAR_DEVICE_SCOPE);
225                         while (pathremaining >= sizeof(ACPI_DMAR_PCI_PATH)) {
226                                 path = (ACPI_DMAR_PCI_PATH *)(pathend - pathremaining);
227                                 pathremaining -= sizeof(ACPI_DMAR_PCI_PATH);
228
229                                 if (PCI_RID2SLOT(rid) != path->Device)
230                                         continue;
231                                 if (PCI_RID2FUNC(rid) != path->Function)
232                                         continue;
233
234                                 vtdmap = vtdmaps[i];
235                                 return (vtdmap);
236                         }
237                 }
238         }
239
240         /* No matching scope */
241         return (NULL);
242 }
243
244 static void
245 vtd_wbflush(struct vtdmap *vtdmap)
246 {
247
248         if (VTD_ECAP_COHERENCY(vtdmap->ext_cap) == 0)
249                 pmap_invalidate_cache();
250
251         if (VTD_CAP_RWBF(vtdmap->cap)) {
252                 vtdmap->gcr = VTD_GCR_WBF;
253                 while ((vtdmap->gsr & VTD_GSR_WBFS) != 0)
254                         ;
255         }
256 }
257
258 static void
259 vtd_ctx_global_invalidate(struct vtdmap *vtdmap)
260 {
261
262         vtdmap->ccr = VTD_CCR_ICC | VTD_CCR_CIRG_GLOBAL;
263         while ((vtdmap->ccr & VTD_CCR_ICC) != 0)
264                 ;
265 }
266
267 static void
268 vtd_iotlb_global_invalidate(struct vtdmap *vtdmap)
269 {
270         int offset;
271         volatile uint64_t *iotlb_reg, val;
272
273         vtd_wbflush(vtdmap);
274
275         offset = VTD_ECAP_IRO(vtdmap->ext_cap) * 16;
276         iotlb_reg = (volatile uint64_t *)((caddr_t)vtdmap + offset + 8);
277         
278         *iotlb_reg =  VTD_IIR_IVT | VTD_IIR_IIRG_GLOBAL |
279                       VTD_IIR_DRAIN_READS | VTD_IIR_DRAIN_WRITES;
280
281         while (1) {
282                 val = *iotlb_reg;
283                 if ((val & VTD_IIR_IVT) == 0)
284                         break;
285         }
286 }
287
288 static void
289 vtd_translation_enable(struct vtdmap *vtdmap)
290 {
291
292         vtdmap->gcr = VTD_GCR_TE;
293         while ((vtdmap->gsr & VTD_GSR_TES) == 0)
294                 ;
295 }
296
297 static void
298 vtd_translation_disable(struct vtdmap *vtdmap)
299 {
300
301         vtdmap->gcr = 0;
302         while ((vtdmap->gsr & VTD_GSR_TES) != 0)
303                 ;
304 }
305
306 static int
307 vtd_init(void)
308 {
309         int i, units, remaining, tmp;
310         struct vtdmap *vtdmap;
311         vm_paddr_t ctx_paddr;
312         char *end, envname[32];
313         unsigned long mapaddr;
314         ACPI_STATUS status;
315         ACPI_TABLE_DMAR *dmar;
316         ACPI_DMAR_HEADER *hdr;
317         ACPI_DMAR_HARDWARE_UNIT *drhd;
318
319         /*
320          * Allow the user to override the ACPI DMAR table by specifying the
321          * physical address of each remapping unit.
322          *
323          * The following example specifies two remapping units at
324          * physical addresses 0xfed90000 and 0xfeda0000 respectively.
325          * set vtd.regmap.0.addr=0xfed90000
326          * set vtd.regmap.1.addr=0xfeda0000
327          */
328         for (units = 0; units < DRHD_MAX_UNITS; units++) {
329                 snprintf(envname, sizeof(envname), "vtd.regmap.%d.addr", units);
330                 if (getenv_ulong(envname, &mapaddr) == 0)
331                         break;
332                 vtdmaps[units] = (struct vtdmap *)PHYS_TO_DMAP(mapaddr);
333         }
334
335         if (units > 0)
336                 goto skip_dmar;
337
338         /* Search for DMAR table. */
339         status = AcpiGetTable(ACPI_SIG_DMAR, 0, (ACPI_TABLE_HEADER **)&dmar);
340         if (ACPI_FAILURE(status))
341                 return (ENXIO);
342
343         end = (char *)dmar + dmar->Header.Length;
344         remaining = dmar->Header.Length - sizeof(ACPI_TABLE_DMAR);
345         while (remaining > sizeof(ACPI_DMAR_HEADER)) {
346                 hdr = (ACPI_DMAR_HEADER *)(end - remaining);
347                 if (hdr->Length > remaining)
348                         break;
349                 /*
350                  * From Intel VT-d arch spec, version 1.3:
351                  * BIOS implementations must report mapping structures
352                  * in numerical order, i.e. All remapping structures of
353                  * type 0 (DRHD) enumerated before remapping structures of
354                  * type 1 (RMRR) and so forth.
355                  */
356                 if (hdr->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT)
357                         break;
358
359                 drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr;
360                 drhds[units] = drhd;
361                 vtdmaps[units] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address);
362                 if (++units >= DRHD_MAX_UNITS)
363                         break;
364                 remaining -= hdr->Length;
365         }
366
367         if (units <= 0)
368                 return (ENXIO);
369
370 skip_dmar:
371         drhd_num = units;
372
373         max_domains = 64 * 1024; /* maximum valid value */
374         for (i = 0; i < drhd_num; i++){
375                 vtdmap = vtdmaps[i];
376
377                 if (VTD_CAP_CM(vtdmap->cap) != 0)
378                         panic("vtd_init: invalid caching mode");
379
380                 /* take most compatible (minimum) value */
381                 if ((tmp = vtd_max_domains(vtdmap)) < max_domains)
382                         max_domains = tmp;
383         }
384
385         /*
386          * Set up the root-table to point to the context-entry tables
387          */
388         for (i = 0; i < 256; i++) {
389                 ctx_paddr = vtophys(ctx_tables[i]);
390                 if (ctx_paddr & PAGE_MASK)
391                         panic("ctx table (0x%0lx) not page aligned", ctx_paddr);
392
393                 root_table[i * 2] = ctx_paddr | VTD_ROOT_PRESENT;
394         }
395
396         return (0);
397 }
398
399 static void
400 vtd_cleanup(void)
401 {
402 }
403
404 static void
405 vtd_enable(void)
406 {
407         int i;
408         struct vtdmap *vtdmap;
409
410         for (i = 0; i < drhd_num; i++) {
411                 vtdmap = vtdmaps[i];
412                 vtd_wbflush(vtdmap);
413
414                 /* Update the root table address */
415                 vtdmap->rta = vtophys(root_table);
416                 vtdmap->gcr = VTD_GCR_SRTP;
417                 while ((vtdmap->gsr & VTD_GSR_RTPS) == 0)
418                         ;
419
420                 vtd_ctx_global_invalidate(vtdmap);
421                 vtd_iotlb_global_invalidate(vtdmap);
422
423                 vtd_translation_enable(vtdmap);
424         }
425 }
426
427 static void
428 vtd_disable(void)
429 {
430         int i;
431         struct vtdmap *vtdmap;
432
433         for (i = 0; i < drhd_num; i++) {
434                 vtdmap = vtdmaps[i];
435                 vtd_translation_disable(vtdmap);
436         }
437 }
438
439 static void
440 vtd_add_device(void *arg, uint16_t rid)
441 {
442         int idx;
443         uint64_t *ctxp;
444         struct domain *dom = arg;
445         vm_paddr_t pt_paddr;
446         struct vtdmap *vtdmap;
447         uint8_t bus;
448
449         bus = PCI_RID2BUS(rid);
450         ctxp = ctx_tables[bus];
451         pt_paddr = vtophys(dom->ptp);
452         idx = VTD_RID2IDX(rid);
453
454         if (ctxp[idx] & VTD_CTX_PRESENT) {
455                 panic("vtd_add_device: device %x is already owned by "
456                       "domain %d", rid,
457                       (uint16_t)(ctxp[idx + 1] >> 8));
458         }
459
460         if ((vtdmap = vtd_device_scope(rid)) == NULL)
461                 panic("vtd_add_device: device %x is not in scope for "
462                       "any DMA remapping unit", rid);
463
464         /*
465          * Order is important. The 'present' bit is set only after all fields
466          * of the context pointer are initialized.
467          */
468         ctxp[idx + 1] = dom->addrwidth | (dom->id << 8);
469
470         if (VTD_ECAP_DI(vtdmap->ext_cap))
471                 ctxp[idx] = VTD_CTX_TT_ALL;
472         else
473                 ctxp[idx] = 0;
474
475         ctxp[idx] |= pt_paddr | VTD_CTX_PRESENT;
476
477         /*
478          * 'Not Present' entries are not cached in either the Context Cache
479          * or in the IOTLB, so there is no need to invalidate either of them.
480          */
481 }
482
483 static void
484 vtd_remove_device(void *arg, uint16_t rid)
485 {
486         int i, idx;
487         uint64_t *ctxp;
488         struct vtdmap *vtdmap;
489         uint8_t bus;
490
491         bus = PCI_RID2BUS(rid);
492         ctxp = ctx_tables[bus];
493         idx = VTD_RID2IDX(rid);
494
495         /*
496          * Order is important. The 'present' bit is must be cleared first.
497          */
498         ctxp[idx] = 0;
499         ctxp[idx + 1] = 0;
500
501         /*
502          * Invalidate the Context Cache and the IOTLB.
503          *
504          * XXX use device-selective invalidation for Context Cache
505          * XXX use domain-selective invalidation for IOTLB
506          */
507         for (i = 0; i < drhd_num; i++) {
508                 vtdmap = vtdmaps[i];
509                 vtd_ctx_global_invalidate(vtdmap);
510                 vtd_iotlb_global_invalidate(vtdmap);
511         }
512 }
513
514 #define CREATE_MAPPING  0
515 #define REMOVE_MAPPING  1
516
517 static uint64_t
518 vtd_update_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len,
519                    int remove)
520 {
521         struct domain *dom;
522         int i, spshift, ptpshift, ptpindex, nlevels;
523         uint64_t spsize, *ptp;
524
525         dom = arg;
526         ptpindex = 0;
527         ptpshift = 0;
528
529         KASSERT(gpa + len > gpa, ("%s: invalid gpa range %#lx/%#lx", __func__,
530             gpa, len));
531         KASSERT(gpa + len <= dom->maxaddr, ("%s: gpa range %#lx/%#lx beyond "
532             "domain maxaddr %#lx", __func__, gpa, len, dom->maxaddr));
533
534         if (gpa & PAGE_MASK)
535                 panic("vtd_create_mapping: unaligned gpa 0x%0lx", gpa);
536
537         if (hpa & PAGE_MASK)
538                 panic("vtd_create_mapping: unaligned hpa 0x%0lx", hpa);
539
540         if (len & PAGE_MASK)
541                 panic("vtd_create_mapping: unaligned len 0x%0lx", len);
542
543         /*
544          * Compute the size of the mapping that we can accommodate.
545          *
546          * This is based on three factors:
547          * - supported super page size
548          * - alignment of the region starting at 'gpa' and 'hpa'
549          * - length of the region 'len'
550          */
551         spshift = 48;
552         for (i = 3; i >= 0; i--) {
553                 spsize = 1UL << spshift;
554                 if ((dom->spsmask & (1 << i)) != 0 &&
555                     (gpa & (spsize - 1)) == 0 &&
556                     (hpa & (spsize - 1)) == 0 &&
557                     (len >= spsize)) {
558                         break;
559                 }
560                 spshift -= 9;
561         }
562
563         ptp = dom->ptp;
564         nlevels = dom->pt_levels;
565         while (--nlevels >= 0) {
566                 ptpshift = 12 + nlevels * 9;
567                 ptpindex = (gpa >> ptpshift) & 0x1FF;
568
569                 /* We have reached the leaf mapping */
570                 if (spshift >= ptpshift) {
571                         break;
572                 }
573
574                 /*
575                  * We are working on a non-leaf page table page.
576                  *
577                  * Create a downstream page table page if necessary and point
578                  * to it from the current page table.
579                  */
580                 if (ptp[ptpindex] == 0) {
581                         void *nlp = malloc(PAGE_SIZE, M_VTD, M_WAITOK | M_ZERO);
582                         ptp[ptpindex] = vtophys(nlp)| VTD_PTE_RD | VTD_PTE_WR;
583                 }
584
585                 ptp = (uint64_t *)PHYS_TO_DMAP(ptp[ptpindex] & VTD_PTE_ADDR_M);
586         }
587
588         if ((gpa & ((1UL << ptpshift) - 1)) != 0)
589                 panic("gpa 0x%lx and ptpshift %d mismatch", gpa, ptpshift);
590
591         /*
592          * Update the 'gpa' -> 'hpa' mapping
593          */
594         if (remove) {
595                 ptp[ptpindex] = 0;
596         } else {
597                 ptp[ptpindex] = hpa | VTD_PTE_RD | VTD_PTE_WR;
598
599                 if (nlevels > 0)
600                         ptp[ptpindex] |= VTD_PTE_SUPERPAGE;
601         }
602
603         return (1UL << ptpshift);
604 }
605
606 static uint64_t
607 vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
608 {
609
610         return (vtd_update_mapping(arg, gpa, hpa, len, CREATE_MAPPING));
611 }
612
613 static uint64_t
614 vtd_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
615 {
616
617         return (vtd_update_mapping(arg, gpa, 0, len, REMOVE_MAPPING));
618 }
619
620 static void
621 vtd_invalidate_tlb(void *dom)
622 {
623         int i;
624         struct vtdmap *vtdmap;
625
626         /*
627          * Invalidate the IOTLB.
628          * XXX use domain-selective invalidation for IOTLB
629          */
630         for (i = 0; i < drhd_num; i++) {
631                 vtdmap = vtdmaps[i];
632                 vtd_iotlb_global_invalidate(vtdmap);
633         }
634 }
635
636 static void *
637 vtd_create_domain(vm_paddr_t maxaddr)
638 {
639         struct domain *dom;
640         vm_paddr_t addr;
641         int tmp, i, gaw, agaw, sagaw, res, pt_levels, addrwidth;
642         struct vtdmap *vtdmap;
643
644         if (drhd_num <= 0)
645                 panic("vtd_create_domain: no dma remapping hardware available");
646
647         /*
648          * Calculate AGAW.
649          * Section 3.4.2 "Adjusted Guest Address Width", Architecture Spec.
650          */
651         addr = 0;
652         for (gaw = 0; addr < maxaddr; gaw++)
653                 addr = 1ULL << gaw;
654
655         res = (gaw - 12) % 9;
656         if (res == 0)
657                 agaw = gaw;
658         else
659                 agaw = gaw + 9 - res;
660
661         if (agaw > 64)
662                 agaw = 64;
663
664         /*
665          * Select the smallest Supported AGAW and the corresponding number
666          * of page table levels.
667          */
668         pt_levels = 2;
669         sagaw = 30;
670         addrwidth = 0;
671
672         tmp = ~0;
673         for (i = 0; i < drhd_num; i++) {
674                 vtdmap = vtdmaps[i];
675                 /* take most compatible value */
676                 tmp &= VTD_CAP_SAGAW(vtdmap->cap);
677         }
678
679         for (i = 0; i < 5; i++) {
680                 if ((tmp & (1 << i)) != 0 && sagaw >= agaw)
681                         break;
682                 pt_levels++;
683                 addrwidth++;
684                 sagaw += 9;
685                 if (sagaw > 64)
686                         sagaw = 64;
687         }
688
689         if (i >= 5) {
690                 panic("vtd_create_domain: SAGAW 0x%x does not support AGAW %d",
691                       tmp, agaw);
692         }
693
694         dom = malloc(sizeof(struct domain), M_VTD, M_ZERO | M_WAITOK);
695         dom->pt_levels = pt_levels;
696         dom->addrwidth = addrwidth;
697         dom->id = domain_id();
698         dom->maxaddr = maxaddr;
699         dom->ptp = malloc(PAGE_SIZE, M_VTD, M_ZERO | M_WAITOK);
700         if ((uintptr_t)dom->ptp & PAGE_MASK)
701                 panic("vtd_create_domain: ptp (%p) not page aligned", dom->ptp);
702
703 #ifdef notyet
704         /*
705          * XXX superpage mappings for the iommu do not work correctly.
706          *
707          * By default all physical memory is mapped into the host_domain.
708          * When a VM is allocated wired memory the pages belonging to it
709          * are removed from the host_domain and added to the vm's domain.
710          *
711          * If the page being removed was mapped using a superpage mapping
712          * in the host_domain then we need to demote the mapping before
713          * removing the page.
714          *
715          * There is not any code to deal with the demotion at the moment
716          * so we disable superpage mappings altogether.
717          */
718         dom->spsmask = ~0;
719         for (i = 0; i < drhd_num; i++) {
720                 vtdmap = vtdmaps[i];
721                 /* take most compatible value */
722                 dom->spsmask &= VTD_CAP_SPS(vtdmap->cap);
723         }
724 #endif
725
726         SLIST_INSERT_HEAD(&domhead, dom, next);
727
728         return (dom);
729 }
730
731 static void
732 vtd_free_ptp(uint64_t *ptp, int level)
733 {
734         int i;
735         uint64_t *nlp;
736
737         if (level > 1) {
738                 for (i = 0; i < 512; i++) {
739                         if ((ptp[i] & (VTD_PTE_RD | VTD_PTE_WR)) == 0)
740                                 continue;
741                         if ((ptp[i] & VTD_PTE_SUPERPAGE) != 0)
742                                 continue;
743                         nlp = (uint64_t *)PHYS_TO_DMAP(ptp[i] & VTD_PTE_ADDR_M);
744                         vtd_free_ptp(nlp, level - 1);
745                 }
746         }
747
748         bzero(ptp, PAGE_SIZE);
749         free(ptp, M_VTD);
750 }
751
752 static void
753 vtd_destroy_domain(void *arg)
754 {
755         struct domain *dom;
756         
757         dom = arg;
758
759         SLIST_REMOVE(&domhead, dom, domain, next);
760         vtd_free_ptp(dom->ptp, dom->pt_levels);
761         free(dom, M_VTD);
762 }
763
764 struct iommu_ops iommu_ops_intel = {
765         vtd_init,
766         vtd_cleanup,
767         vtd_enable,
768         vtd_disable,
769         vtd_create_domain,
770         vtd_destroy_domain,
771         vtd_create_mapping,
772         vtd_remove_mapping,
773         vtd_add_device,
774         vtd_remove_device,
775         vtd_invalidate_tlb,
776 };