[PATCH RFC 14/18] x86/mm/pat, mm: move cpa-test to mm
Mike Rapoport (Microsoft)
rppt at kernel.org
Tue Jul 21 09:23:37 PDT 2026
x86 has a nice test suite for set_memory APIs and CPA machinery.
Now that core CPA machinery is a part of the generic code let's make the
test also available as the part of the common code:
* move arch/x86/mm/pat/cpa-test.c to mm/
* keep it included in set_memory.c rather than a separate compilation unit.
* adjust the code to use pXd accessors instead of hardcoded x86 specific
bits
* replace max_pfn_mapped used as an upper bound with test local
max_test_pfn derived from high_memory.
Signed-off-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
---
arch/x86/Kconfig.debug | 6 ----
arch/x86/mm/pat/set_memory.c | 8 -----
mm/Kconfig.debug | 7 ++++
{arch/x86/mm/pat => mm}/cpa-test.c | 66 +++++++++++++++++++-------------------
mm/set_memory.c | 8 +++++
5 files changed, 48 insertions(+), 47 deletions(-)
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index c95c3aaadf97..314b72aad6ff 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -157,12 +157,6 @@ config DEBUG_BOOT_PARAMS
help
This option will cause struct boot_params to be exported via debugfs.
-config CPA_DEBUG
- bool "CPA self-test code"
- depends on DEBUG_KERNEL
- help
- Do change_page_attr() self-tests every 30 seconds.
-
config DEBUG_ENTRY
bool "Debug low-level entry code"
depends on DEBUG_KERNEL
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 5109139a2d31..c460121c96b9 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -2324,11 +2324,3 @@ int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
return retval;
}
-
-/*
- * The testcases use internal knowledge of the implementation that shouldn't
- * be exposed to the rest of the kernel. Include these directly here.
- */
-#ifdef CONFIG_CPA_DEBUG
-#include "cpa-test.c"
-#endif
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 91b3e027b753..83cfef6b2d8c 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -320,3 +320,10 @@ config PER_VMA_LOCK_STATS
overhead in the page fault path.
If in doubt, say N.
+
+config CPA_DEBUG
+ bool "CPA self-test code"
+ depends on GENERIC_SET_MEMORY
+ depends on DEBUG_KERNEL
+ help
+ Do change_page_attr() self-tests every 30 seconds.
diff --git a/arch/x86/mm/pat/cpa-test.c b/mm/cpa-test.c
similarity index 80%
rename from arch/x86/mm/pat/cpa-test.c
rename to mm/cpa-test.c
index ad3c1feec990..63c3463a5a7d 100644
--- a/arch/x86/mm/pat/cpa-test.c
+++ b/mm/cpa-test.c
@@ -13,32 +13,24 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
-
/*
* Only print the results of the first pass:
*/
static __read_mostly int print = 1;
+static unsigned long max_test_pfn;
enum {
NTEST = 3 * 100,
NPAGES = 100,
-#ifdef CONFIG_X86_64
- LPS = (1 << PMD_SHIFT),
-#elif defined(CONFIG_X86_PAE)
- LPS = (1 << PMD_SHIFT),
-#else
- LPS = (1 << 22),
-#endif
- GPS = (1<<30)
+ LPS = PMD_SIZE,
+ GPS = PUD_SIZE
};
-#define PAGE_CPA_TEST __pgprot(_PAGE_CPA_TEST)
+#define PAGE_CPA_TEST __pgprot(_PAGE_SPECIAL)
static int pte_testbit(pte_t pte)
{
- return pte_flags(pte) & _PAGE_SOFTW1;
+ return pte_special(pte);
}
struct split_state {
@@ -54,10 +46,10 @@ static int print_split(struct split_state *s)
s->lpg = s->gpg = s->spg = s->exec = 0;
s->min_exec = ~0UL;
s->max_exec = 0;
- for (i = 0; i < max_pfn_mapped; ) {
+ for (i = 0; i < max_test_pfn; ) {
unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
unsigned int level;
- pte_t *pte;
+ pte_t *pte, pteval;
pte = lookup_address(addr, &level);
if (!pte) {
@@ -65,15 +57,16 @@ static int print_split(struct split_state *s)
i++;
continue;
}
+ pteval = ptep_get(pte);
- if (level == PG_LEVEL_1G && sizeof(long) == 8) {
+ if (level == PGTABLE_LEVEL_PUD && sizeof(long) == 8) {
s->gpg++;
i += GPS/PAGE_SIZE;
- } else if (level == PG_LEVEL_2M) {
- if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) {
+ } else if (level == PGTABLE_LEVEL_PMD) {
+ if (pte_present(pteval) && !pte_huge(pteval)) {
printk(KERN_ERR
- "%lx level %d but not PSE %Lx\n",
- addr, level, (u64)pte_val(*pte));
+ "%lx level %d but not leaf %Lx\n",
+ addr, level, (u64)pte_val(pteval));
err = 1;
}
s->lpg++;
@@ -82,7 +75,7 @@ static int print_split(struct split_state *s)
s->spg++;
i++;
}
- if (!(pte_val(*pte) & _PAGE_NX)) {
+ if (pte_exec(pteval)) {
s->exec++;
if (addr < s->min_exec)
s->min_exec = addr;
@@ -100,8 +93,8 @@ static int print_split(struct split_state *s)
expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
if (expected != i) {
- printk(KERN_ERR "CPA max_pfn_mapped %lu but expected %lu\n",
- max_pfn_mapped, expected);
+ printk(KERN_ERR "CPA max_test_pfn %lu but expected %lu\n",
+ max_test_pfn, expected);
return 1;
}
return err;
@@ -118,7 +111,7 @@ static int pageattr_test(void)
{
struct split_state sa, sb, sc;
unsigned long *bm;
- pte_t *pte, pte0;
+ pte_t *pte, pte0, pte_val;
int failed = 0;
unsigned int level;
int i, k;
@@ -127,7 +120,7 @@ static int pageattr_test(void)
if (print)
printk(KERN_INFO "CPA self-test:\n");
- bm = vzalloc((max_pfn_mapped + 7) / 8);
+ bm = vzalloc((max_test_pfn + 7) / 8);
if (!bm) {
printk(KERN_ERR "CPA Cannot vmalloc bitmap\n");
return -ENOMEM;
@@ -136,11 +129,11 @@ static int pageattr_test(void)
failed += print_split(&sa);
for (i = 0; i < NTEST; i++) {
- unsigned long pfn = get_random_u32_below(max_pfn_mapped);
+ unsigned long pfn = get_random_u32_below(max_test_pfn);
addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
len[i] = get_random_u32_below(NPAGES);
- len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1);
+ len[i] = min_t(unsigned long, len[i], max_test_pfn - pfn - 1);
if (len[i] == 0)
len[i] = 1;
@@ -150,15 +143,20 @@ static int pageattr_test(void)
for (k = 0; k < len[i]; k++) {
pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
- if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
- !(pte_val(*pte) & _PAGE_PRESENT)) {
+ if (!pte) {
+ addr[i] = 0;
+ break;
+ }
+ pte_val = ptep_get(pte);
+ if (pgprot_val(pte_pgprot(pte_val)) == 0 ||
+ !pte_present(pte_val)) {
addr[i] = 0;
break;
}
if (k == 0) {
- pte0 = *pte;
+ pte0 = pte_val;
} else {
- if (pgprot_val(pte_pgprot(*pte)) !=
+ if (pgprot_val(pte_pgprot(pte_val)) !=
pgprot_val(pte_pgprot(pte0))) {
len[i] = k;
break;
@@ -198,12 +196,12 @@ static int pageattr_test(void)
}
pte = lookup_address(addr[i], &level);
- if (!pte || !pte_testbit(*pte) || pte_huge(*pte)) {
+ if (!pte || !pte_testbit(*pte) || level != PGTABLE_LEVEL_PTE) {
printk(KERN_ERR "CPA %lx: bad pte %Lx\n", addr[i],
pte ? (u64)pte_val(*pte) : 0ULL);
failed++;
}
- if (level != PG_LEVEL_4K) {
+ if (level != PGTABLE_LEVEL_PTE) {
printk(KERN_ERR "CPA %lx: unexpected level %d\n",
addr[i], level);
failed++;
@@ -266,6 +264,8 @@ static int start_pageattr_test(void)
{
struct task_struct *p;
+ max_test_pfn = PFN_DOWN(__pa(high_memory - 1));
+
p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
if (!IS_ERR(p))
wake_up_process(p);
diff --git a/mm/set_memory.c b/mm/set_memory.c
index 1a7e63512981..744405efcc34 100644
--- a/mm/set_memory.c
+++ b/mm/set_memory.c
@@ -386,3 +386,11 @@ int change_page_attr_set_clr(unsigned long *addr, int numpages,
out:
return err;
}
+
+/*
+ * The testcases use internal knowledge of the implementation that shouldn't
+ * be exposed to the rest of the kernel. Include these directly here.
+ */
+#ifdef CONFIG_CPA_DEBUG
+#include "cpa-test.c"
+#endif
--
2.53.0
More information about the linux-riscv
mailing list