iommu: populate functions for setup/teardown of page tables
authorAditya Basu <mitthu@google.com>
Sat, 17 Aug 2019 01:00:56 +0000 (21:00 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 19 Aug 2019 16:39:09 +0000 (12:39 -0400)
* setup_page_tables(): add pci_device to a proc's addr space
* teardown_page_tables(): remove pci_device from the proc's addr space

Signed-off-by: Aditya Basu <mitthu@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/iommu.c

index 9ae50fb..6fcb5a4 100644 (file)
@@ -154,14 +154,72 @@ static physaddr_t rt_init(struct iommu *iommu, uint16_t did)
        return rt;
 }
 
+static struct context_entry *get_ctx_for(int bus, int dev, int func,
+       physaddr_t roottable)
+{
+       struct root_entry *rte;
+       physaddr_t cte_phy;
+       struct context_entry *cte;
+       uint32_t offset = 0;
+
+       rte = get_root_entry(roottable) + bus;
+
+       cte_phy = rte->lo & 0xFFFFFFFFFFFFF000;
+       cte = get_context_entry(cte_phy);
+
+       offset = (dev * 8) + func;
+       cte += offset;
+
+       return cte;
+}
+
+/* The process pid is used as the Domain ID (DID) */
 static void setup_page_tables(struct proc *p, struct pci_device *d)
 {
-       // setup the pte; use the pip as did
+       uint32_t cmd, status;
+       uint16_t did = p->pid; /* casts down to 16-bit */
+       struct iommu *iommu = d->iommu;
+       struct context_entry *cte =
+               get_ctx_for(d->bus, d->dev, d->func, iommu->roottable);
+
+       /* Mark the entry as not present */
+       cte->lo &= ~0x1;
+       write_buffer_flush(iommu);
+       iotlb_flush(iommu, IOMMU_DID_DEFAULT);
+
+       cte->hi = 0
+               | (did << CTX_HI_DID_SHIFT) // DID bit: 72 to 87
+               | (CTX_AW_L4 << CTX_HI_AW_SHIFT); // AW
+
+       cte->lo = PTE_ADDR(p->env_pgdir.eptp)
+               | (0x0 << CTX_LO_TRANS_SHIFT)
+               | (0x1 << CTX_LO_FPD_SHIFT) // disable faults
+               | (0x1 << CTX_LO_PRESENT_SHIFT); /* mark present */
 }
 
+/* TODO: We should mark the entry as not present to block any stray DMAs from
+ * reaching the kernel. To force a re-attach the device to the kernel, we can
+ * use pid 0. */
 static void teardown_page_tables(struct proc *p, struct pci_device *d)
 {
-       // revert to default did
+       uint16_t did = IOMMU_DID_DEFAULT;
+       struct iommu *iommu = d->iommu;
+       struct context_entry *cte =
+               get_ctx_for(d->bus, d->dev, d->func, iommu->roottable);
+
+       /* Mark the entry as not present */
+       cte->lo &= ~0x1;
+       write_buffer_flush(iommu);
+       iotlb_flush(iommu, p->pid);
+
+       cte->hi = 0
+               | (did << CTX_HI_DID_SHIFT) // DID bit: 72 to 87
+               | (CTX_AW_L4 << CTX_HI_AW_SHIFT); // AW
+
+       cte->lo = 0 /* assumes page alignment */
+               | (0x2 << CTX_LO_TRANS_SHIFT)
+               | (0x1 << CTX_LO_FPD_SHIFT) // disable faults
+               | (0x1 << CTX_LO_PRESENT_SHIFT); /* mark present */
 }
 
 static bool _iommu_enable(struct iommu *iommu)