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)