[RFC v4][PATCH part-2 01/13] mm/x86: Introduce decorated page-table (dpt)

From: Alexandre Chartre
Date: Mon May 04 2020 - 11:00:11 EST


A decorated page-table (dpt) encapsulates a native page-table (e.g.
a PGD) and maintain additional attributes related to this page-table.
It aims to be the base structure for providing useful functions to
manage a page-table, such as tracking VA range mapped in a page-table
or safely handling references to another page-table.

Signed-off-by: Alexandre Chartre <alexandre.chartre@xxxxxxxxxx>
---
arch/x86/include/asm/dpt.h | 23 +++++++++++++
arch/x86/mm/Makefile | 2 +-
arch/x86/mm/dpt.c | 67 ++++++++++++++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/include/asm/dpt.h
create mode 100644 arch/x86/mm/dpt.c

diff --git a/arch/x86/include/asm/dpt.h b/arch/x86/include/asm/dpt.h
new file mode 100644
index 000000000000..1da4d43d5e94
--- /dev/null
+++ b/arch/x86/include/asm/dpt.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_X86_MM_DPT_H
+#define ARCH_X86_MM_DPT_H
+
+#include <linux/spinlock.h>
+
+#include <asm/pgtable.h>
+
+/*
+ * A decorated page-table (dpt) encapsulates a native page-table (e.g.
+ * a PGD) and maintain additional attributes related to this page-table.
+ */
+struct dpt {
+ spinlock_t lock; /* protect all attributes */
+ pgd_t *pagetable; /* the actual page-table */
+ unsigned int alignment; /* page-table alignment */
+
+};
+
+extern struct dpt *dpt_create(unsigned int pgt_alignment);
+extern void dpt_destroy(struct dpt *dpt);
+
+#endif
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index e57af263e870..5b52d854a030 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -48,7 +48,7 @@ obj-$(CONFIG_NUMA_EMU) += numa_emulation.o
obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o
obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o
obj-$(CONFIG_PAGE_TABLE_ISOLATION) += pti.o
-obj-$(CONFIG_ADDRESS_SPACE_ISOLATION) += asi.o
+obj-$(CONFIG_ADDRESS_SPACE_ISOLATION) += asi.o dpt.o

obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt.o
obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_identity.o
diff --git a/arch/x86/mm/dpt.c b/arch/x86/mm/dpt.c
new file mode 100644
index 000000000000..333e259c5b7f
--- /dev/null
+++ b/arch/x86/mm/dpt.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates.
+ *
+ */
+
+#include <linux/slab.h>
+
+#include <asm/dpt.h>
+
+/*
+ * dpt_create - allocate a page-table and create a corresponding
+ * decorated page-table. The page-table is allocated and aligned
+ * at the specified alignment (pgt_alignment) which should be a
+ * multiple of PAGE_SIZE.
+ */
+struct dpt *dpt_create(unsigned int pgt_alignment)
+{
+ unsigned int alloc_order;
+ unsigned long pagetable;
+ struct dpt *dpt;
+
+ if (!IS_ALIGNED(pgt_alignment, PAGE_SIZE))
+ return NULL;
+
+ alloc_order = round_up(PAGE_SIZE + pgt_alignment,
+ PAGE_SIZE) >> PAGE_SHIFT;
+
+ dpt = kzalloc(sizeof(*dpt), GFP_KERNEL);
+ if (!dpt)
+ return NULL;
+
+ pagetable = (unsigned long)__get_free_pages(GFP_KERNEL_ACCOUNT |
+ __GFP_ZERO,
+ alloc_order);
+ if (!pagetable) {
+ kfree(dpt);
+ return NULL;
+ }
+ dpt->pagetable = (pgd_t *)(pagetable + pgt_alignment);
+ dpt->alignment = pgt_alignment;
+
+ spin_lock_init(&dpt->lock);
+
+ return dpt;
+}
+EXPORT_SYMBOL(dpt_create);
+
+void dpt_destroy(struct dpt *dpt)
+{
+ unsigned int pgt_alignment;
+ unsigned int alloc_order;
+
+ if (!dpt)
+ return;
+
+ if (dpt->pagetable) {
+ pgt_alignment = dpt->alignment;
+ alloc_order = round_up(PAGE_SIZE + pgt_alignment,
+ PAGE_SIZE) >> PAGE_SHIFT;
+ free_pages((unsigned long)(dpt->pagetable) - pgt_alignment,
+ alloc_order);
+ }
+
+ kfree(dpt);
+}
+EXPORT_SYMBOL(dpt_destroy);
--
2.18.2