iommu: populate functions for setup/teardown of page tables * 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>
diff --git a/kern/drivers/dev/iommu.c b/kern/drivers/dev/iommu.c index 9ae50fb..6fcb5a4 100644 --- a/kern/drivers/dev/iommu.c +++ b/kern/drivers/dev/iommu.c
@@ -154,14 +154,72 @@ return rt; } -static void setup_page_tables(struct proc *p, struct pci_device *d) +static struct context_entry *get_ctx_for(int bus, int dev, int func, + physaddr_t roottable) { - // setup the pte; use the pip as did + 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) +{ + 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)