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