|
@@ -47,6 +47,16 @@ struct tce_container {
|
|
|
bool enabled;
|
|
|
};
|
|
|
|
|
|
+static bool tce_page_is_contained(struct page *page, unsigned page_shift)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Check that the TCE table granularity is not bigger than the size of
|
|
|
+ * a page we just found. Otherwise the hardware can get access to
|
|
|
+ * a bigger memory chunk that it should.
|
|
|
+ */
|
|
|
+ return (PAGE_SHIFT + compound_order(compound_head(page))) >= page_shift;
|
|
|
+}
|
|
|
+
|
|
|
static int tce_iommu_enable(struct tce_container *container)
|
|
|
{
|
|
|
int ret = 0;
|
|
@@ -189,6 +199,12 @@ static long tce_iommu_build(struct tce_container *container,
|
|
|
ret = -EFAULT;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ if (!tce_page_is_contained(page, tbl->it_page_shift)) {
|
|
|
+ ret = -EPERM;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
hva = (unsigned long) page_address(page) + offset;
|
|
|
|
|
|
ret = iommu_tce_build(tbl, entry + i, hva, direction);
|