diff options
author | Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | 2022-06-17 13:25:15 +0100 |
---|---|---|
committer | Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | 2023-10-30 12:56:15 +0000 |
commit | 0b0a9f1236df10a6e4539872da60ad7932904201 (patch) | |
tree | 257d3182b69d66f26668bcf2c6feb89298d0ce3e | |
parent | 9ccc4b641f545790622f8fe2423989db463cdae8 (diff) |
arm64: text replication: add test module
Add a module to allow kernel text replication to be tested; this
exposes some data in procfs which can be used to verify that:
(a) we're using different page tables in TTBR1 on CPUs in different
NUMA nodes
(b) that CPUs in different NUMA nodes are indeed accessing different
copies of the kernel
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-rw-r--r-- | arch/arm64/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm64/include/asm/ktext.h | 2 | ||||
-rw-r--r-- | arch/arm64/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm64/mm/ktext-test.c | 93 | ||||
-rw-r--r-- | arch/arm64/mm/ktext.c | 15 |
5 files changed, 119 insertions, 0 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 82b10e9e72a8..636cdc7bbf13 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1454,6 +1454,14 @@ config REPLICATE_KTEXT_DEFAULT Determine whether kernel text replication is enabled at boot by default. +config TEST_KTEXT_REPLICATE + tristate "Kernel text replication testing module" + depends on REPLICATE_KTEXT + help + Enable building of a test module for kernel text replication. + + If unsure, say N. + source "kernel/Kconfig.hz" config ARCH_SPARSEMEM_ENABLE diff --git a/arch/arm64/include/asm/ktext.h b/arch/arm64/include/asm/ktext.h index 2927e5672ace..741b9f75c63e 100644 --- a/arch/arm64/include/asm/ktext.h +++ b/arch/arm64/include/asm/ktext.h @@ -19,6 +19,8 @@ void ktext_replication_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd); void ktext_replication_init_tramp(void); void create_kernel_nid_map(pgd_t *pgdp, void *ktext); +extern const char ktext_nid[32]; + #else static inline void ktext_replication_init(void) diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index 41e705027c57..482ba013c390 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_KASAN) += kasan_init.o KASAN_SANITIZE_kasan_init.o := n obj-$(CONFIG_REPLICATE_KTEXT) += ktext.o +obj-$(CONFIG_TEST_KTEXT_REPLICATE) += ktext-test.o diff --git a/arch/arm64/mm/ktext-test.c b/arch/arm64/mm/ktext-test.c new file mode 100644 index 000000000000..f397b2fe2e0b --- /dev/null +++ b/arch/arm64/mm/ktext-test.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/proc_fs.h> + +#include <asm/sysreg.h> + +static int ttbr1_show(struct seq_file *m, void *v) +{ + unsigned long ttbr; + int cpu; + + preempt_disable(); + cpu = smp_processor_id(); + ttbr = read_sysreg(ttbr1_el1); + preempt_enable(); + + seq_printf(m, "CPU%u: TTBR1 0x%08lx\n", cpu, ttbr); + + return 0; +} + +static int ttbr1_open(struct inode *inode, struct file *file) +{ + return single_open(file, ttbr1_show, NULL); +} + +static const struct proc_ops ttbr1_fops = { + .proc_open = ttbr1_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +extern const char ktext_nid[32]; + +static int nid_show(struct seq_file *m, void *v) +{ + int cpu; + + preempt_disable(); + cpu = smp_processor_id(); + seq_printf(m, "CPU%u: nid %s\n", + cpu, ktext_nid); + preempt_enable(); + + + return 0; +} + +static int nid_open(struct inode *inode, struct file *file) +{ + return single_open(file, nid_show, NULL); +} + +static const struct proc_ops nid_fops = { + .proc_open = nid_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int ttbr1_init(void) +{ + struct proc_dir_entry *dir; + + dir = proc_mkdir("ktext", NULL); + if (!dir) + return -ENOMEM; + + if (!proc_create("ttbr1", S_IRUSR, dir, &ttbr1_fops) || + !proc_create("text_nid", S_IRUSR, dir, &nid_fops)) { + remove_proc_subtree("ktext", NULL); + return -ENOMEM; + } + + return 0; +} +module_init(ttbr1_init); + +static void ttbr1_fin(void) +{ + remove_proc_subtree("ktext", NULL); +} +module_exit(ttbr1_fin); + +MODULE_AUTHOR("Russell King"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm64/mm/ktext.c b/arch/arm64/mm/ktext.c index 4ab04f531c81..d29497c37da9 100644 --- a/arch/arm64/mm/ktext.c +++ b/arch/arm64/mm/ktext.c @@ -22,6 +22,11 @@ struct pgtables *pgtables[MAX_NUMNODES] = { static void *kernel_texts[MAX_NUMNODES]; +#if IS_ENABLED(CONFIG_TEST_KTEXT_REPLICATE) +const char ktext_nid[32] = "0"; +EXPORT_SYMBOL_GPL(ktext_nid); +#endif + static pgd_t *__swapper_pg_dir_node(int nid) { return pgtables[nid]->swapper_pg_dir; @@ -131,6 +136,9 @@ early_param("ktext", parse_ktext); void __init ktext_replication_init(void) { size_t size = __end_rodata - _stext; +#if IS_ENABLED(CONFIG_TEST_KTEXT_REPLICATE) + size_t kt_nid = ktext_nid - _stext; +#endif int kidx = pgd_index((phys_addr_t)KERNEL_START); int nid; @@ -159,6 +167,13 @@ void __init ktext_replication_init(void) /* Allocate and copy initial kernel text for this node */ kernel_texts[nid] = memblock_alloc_node(size, PAGE_SIZE, nid); memcpy(kernel_texts[nid], _stext, size); + +#if IS_ENABLED(CONFIG_TEST_KTEXT_REPLICATE) + /* Update the node ID in each copy of the kernel text/rodata */ + snprintf(kernel_texts[nid] + kt_nid, sizeof(kernel_texts[nid]), + "%u", nid); +#endif + caches_clean_inval_pou((u64)kernel_texts[nid], (u64)kernel_texts[nid] + size); |