|
@@ -1155,6 +1155,55 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
|
|
+/*
|
|
|
+ * All top-level PAGE_TABLE_ISOLATION page tables are order-1 pages
|
|
|
+ * (8k-aligned and 8k in size). The kernel one is at the beginning 4k and
|
|
|
+ * the user one is in the last 4k. To switch between them, you
|
|
|
+ * just need to flip the 12th bit in their addresses.
|
|
|
+ */
|
|
|
+#define PTI_PGTABLE_SWITCH_BIT PAGE_SHIFT
|
|
|
+
|
|
|
+/*
|
|
|
+ * This generates better code than the inline assembly in
|
|
|
+ * __set_bit().
|
|
|
+ */
|
|
|
+static inline void *ptr_set_bit(void *ptr, int bit)
|
|
|
+{
|
|
|
+ unsigned long __ptr = (unsigned long)ptr;
|
|
|
+
|
|
|
+ __ptr |= BIT(bit);
|
|
|
+ return (void *)__ptr;
|
|
|
+}
|
|
|
+static inline void *ptr_clear_bit(void *ptr, int bit)
|
|
|
+{
|
|
|
+ unsigned long __ptr = (unsigned long)ptr;
|
|
|
+
|
|
|
+ __ptr &= ~BIT(bit);
|
|
|
+ return (void *)__ptr;
|
|
|
+}
|
|
|
+
|
|
|
+static inline pgd_t *kernel_to_user_pgdp(pgd_t *pgdp)
|
|
|
+{
|
|
|
+ return ptr_set_bit(pgdp, PTI_PGTABLE_SWITCH_BIT);
|
|
|
+}
|
|
|
+
|
|
|
+static inline pgd_t *user_to_kernel_pgdp(pgd_t *pgdp)
|
|
|
+{
|
|
|
+ return ptr_clear_bit(pgdp, PTI_PGTABLE_SWITCH_BIT);
|
|
|
+}
|
|
|
+
|
|
|
+static inline p4d_t *kernel_to_user_p4dp(p4d_t *p4dp)
|
|
|
+{
|
|
|
+ return ptr_set_bit(p4dp, PTI_PGTABLE_SWITCH_BIT);
|
|
|
+}
|
|
|
+
|
|
|
+static inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp)
|
|
|
+{
|
|
|
+ return ptr_clear_bit(p4dp, PTI_PGTABLE_SWITCH_BIT);
|
|
|
+}
|
|
|
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
|
|
|
+
|
|
|
/*
|
|
|
* clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
|
|
|
*
|