mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Andi Kleen <ak@suse.de>
To: linux-kernel@vger.kernel.org
Subject: [PATCH CPA] [9/28] CPA: Add simple self test at boot
Date: Thu,  3 Jan 2008 16:24:23 +0100 (CET)	[thread overview]
Message-ID: <20080103152423.8ABD614E23@wotan.suse.de> (raw)
In-Reply-To: <20080103424.989432000@suse.de>


Since change_page_attr() is tricky code it is good to have some regression
test code. This patch maps and unmaps some random pages in the direct mapping
at boot and then dumps the state.

One disadvantage is that the results currently have to be checked
manually, it would be better if it had a global passed/failed message.

Add it with a CONFIG option.

Optional patch, but I find it useful.

Signed-off-by: Andi Kleen <ak@suse.de>

---
 arch/x86/mm/Makefile_32     |    1 
 arch/x86/mm/Makefile_64     |    1 
 arch/x86/mm/pageattr-test.c |  187 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 189 insertions(+)

Index: linux/arch/x86/mm/Makefile_64
===================================================================
--- linux.orig/arch/x86/mm/Makefile_64
+++ linux/arch/x86/mm/Makefile_64
@@ -7,3 +7,4 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
 obj-$(CONFIG_NUMA) += numa_64.o
 obj-$(CONFIG_K8_NUMA) += k8topology_64.o
 obj-$(CONFIG_ACPI_NUMA) += srat_64.o
+obj-$(CONFIG_CPA_DEBUG) += pageattr-test.o
Index: linux/arch/x86/mm/pageattr-test.c
===================================================================
--- /dev/null
+++ linux/arch/x86/mm/pageattr-test.c
@@ -0,0 +1,187 @@
+/*
+ * self test for change_page_attr.
+ *
+ * Clears the global bit on random pages in the direct mapping, then reverts and
+ * compares page tables forwards and afterwards.
+ */
+
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <asm/kdebug.h>
+
+enum {
+	NTEST = 25,
+#ifdef CONFIG_X86_64
+	LOWEST_LEVEL = 4,
+	LPS = (1 << PMD_SHIFT),
+#elif defined(CONFIG_X86_PAE)
+	LOWEST_LEVEL = 3,
+	LPS = (1 << PMD_SHIFT),
+#else
+	LOWEST_LEVEL = 3, /* lookup_address lies here */
+	LPS = (1 << 22),
+#endif
+	GPS = (1<<30)
+};
+
+#ifdef CONFIG_X86_64
+#include <asm/proto.h>
+#define max_mapped end_pfn_map
+#else
+#define max_mapped max_low_pfn
+#endif
+
+struct split_state {
+	long lpg, gpg, spg, nx;
+};
+
+static __init int print_split(struct split_state *s)
+{
+	int printed = 0;
+	long i, expected, missed = 0;
+	s->lpg = s->gpg = s->spg = s->nx = 0;
+	for (i = 0; i < max_mapped; ) {
+		int level;
+		pte_t *pte;
+		unsigned long adr = (unsigned long)__va(i << PAGE_SHIFT);
+
+		pte = lookup_address(adr, &level);
+		if (!pte) {
+			if (!printed) {
+				dump_pagetable(adr);
+				printk("CPA %lx no pte level %d\n", adr, level);
+				printed = 1;
+			}
+			missed++;
+			i++;
+			continue;
+		}
+
+		if (level == 2 && sizeof(long) == 8) {
+			s->gpg++;
+			i += GPS/PAGE_SIZE;
+		} else if (level != LOWEST_LEVEL) {
+			s->lpg++;
+			i += LPS/PAGE_SIZE;
+		} else {
+			s->spg++;
+			i++;
+		}
+		if (pte_val(*pte) & _PAGE_NX)
+			s->nx++;
+	}
+	printk("CPA direct mapping small %lu large %lu giga %lu nx %lu missed %lu\n",
+		s->spg, s->lpg, s->gpg, s->nx, missed);
+	expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
+	if (expected != max_mapped) {
+		printk("CPA max_mapped %lu but expected %lu\n",
+			max_mapped, expected);
+		return 1;
+	}
+	return 0;
+}
+
+static __init int state_same(struct split_state *a, struct split_state *b)
+{
+	return a->lpg == b->lpg && a->gpg == b->gpg && a->spg == b->spg &&
+			a->nx == b->nx;
+}
+
+static unsigned long addr[NTEST] __initdata;
+static unsigned len[NTEST] __initdata;
+
+/* Change the global bit on random pages in the direct mapping */
+static __init int exercise_pageattr(void)
+{
+	int i;
+	pte_t *pte;
+	int level;
+	int err;
+	struct split_state sa, sb, sc;
+	int failed = 0;
+
+	printk("CPA exercising pageattr\n");
+	failed += print_split(&sa);
+	srandom32(100);
+	for (i = 0; i < NTEST; i++) {
+		unsigned long pfn = random32() % max_mapped;
+		addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
+		len[i] = min_t(unsigned long, random32() % 100, max_mapped - pfn);
+		pte = lookup_address(addr[i], &level);
+		if (!pte) {
+			printk("lookup of %lx failed\n", addr[i]);
+			failed++;
+			continue;
+		}
+		if (pgprot_val(pte_pgprot(*pte)) == 0) {
+			addr[i] = 0;
+			continue;
+		}
+
+		err = change_page_attr(virt_to_page(addr[i]), len[i],
+			    pte_pgprot(pte_clrhuge(pte_clrglobal(*pte))));
+		if (err < 0) {
+			printk("cpa %d failed %d\n", i, err);
+			failed++;
+		}
+
+		pte = lookup_address(addr[i], &level);
+		if (!pte || pte_global(*pte) || pte_huge(*pte)) {
+			printk("%lx: bad pte %Lx\n", addr[i],
+				pte ? (u64)pte_val(*pte) : 0ULL);
+			failed++;
+		}
+		if (level != LOWEST_LEVEL) {
+			printk("%lx: unexpected level %d\n", addr[i], level);
+			failed++;
+		}
+
+	}
+	global_flush_tlb();
+
+	failed += print_split(&sb);
+
+	printk("CPA reverting everything\n");
+	for (i = 0; i < NTEST; i++) {
+		if (!addr[i])
+			continue;
+		pte = lookup_address(addr[i], &level);
+		if (!pte) {
+			printk("lookup of %lx failed\n", addr[i]);
+			failed++;
+			continue;
+		}
+		err = change_page_attr(virt_to_page(addr[i]), len[i],
+					  pte_pgprot(pte_mkglobal(*pte)));
+		if (err < 0) {
+			printk("cpa2 failed: %d\n", err);
+			failed++;
+		}
+		pte = lookup_address(addr[i], &level);
+		if (!pte || !pte_global(*pte)) {
+			printk("%lx: bad pte %Lx\n", addr[i],
+			       pte ? (u64)pte_val(*pte) : 0ULL);
+			failed++;
+		}
+
+	}
+	global_flush_tlb();
+
+	failed += print_split(&sc);
+	if (!state_same(&sa, &sc))
+		failed++;
+
+	if (failed)
+		printk("CPA selftests NOT PASSED. Please report.\n");
+	else
+		printk("CPA selftests PASSED\n");
+
+	return 0;
+}
+
+module_init(exercise_pageattr);
Index: linux/arch/x86/mm/Makefile_32
===================================================================
--- linux.orig/arch/x86/mm/Makefile_32
+++ linux/arch/x86/mm/Makefile_32
@@ -8,3 +8,4 @@ obj-$(CONFIG_NUMA) += discontig_32.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_HIGHMEM) += highmem_32.o
 obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o
+obj-$(CONFIG_CPA_DEBUG) += pageattr-test.o

  parent reply	other threads:[~2008-01-03 15:28 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-03 15:24 [PATCH CPA] [1/28] Shrink __PAGE_KERNEL/__PAGE_KERNEL_EXEC on non PAE kernels Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [2/28] CPA: Do a simple self test at boot Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [3/28] Add pte accessors for the global bit Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [4/28] Add pte_clrhuge on i386 Andi Kleen
2008-01-05  6:48   ` Jeremy Fitzhardinge
2008-01-03 15:24 ` [PATCH CPA] [5/28] Add pte_pgprot " Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [6/28] CPA: Undo white space changes Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [7/28] Extract page table dumping code from i386 fault handler into dump_pagetable() Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [8/28] CPA: Return the page table level in lookup_address() Andi Kleen
2008-01-03 15:24 ` Andi Kleen [this message]
2008-01-03 15:24 ` [PATCH CPA] [10/28] CPA: Change kernel_map_pages to not use c_p_a() Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [11/28] CPA: Change 32bit back to init_mm semaphore locking Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [12/28] CPA: CLFLUSH support in change_page_attr() Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [13/28] CPA: Use macros to modify the PG_arch_1 page flags in change_page_attr Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [14/28] CPA: Use page granuality TLB flushing " Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [15/28] CPA: Don't flush the caches when the CPU supports self-snoop Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [16/28] CPA: Use wbinvd() macro instead of inline assembly in 64bit c_p_a() Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [17/28] CPA: Reorder TLB / cache flushes to follow Intel recommendation Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [18/28] CPA: Make change_page_attr() more robust against use of PAT bits Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [19/28] CPA: Limit cache flushing to pages that really change caching Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [20/28] CPA: Fix inaccurate comments in 64bit change_page_attr() Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [21/28] CPA: Dump pagetable when inconsistency is detected Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [22/28] CPA: Only queue actually unused page table pages for freeing Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [23/28] CPA: Remove unnecessary masking of address Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [24/28] CPA: Only unmap kernel init pages in text mapping when CONFIG_DEBUG_RODATA is set Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [25/28] CPA: Always do full TLB flush when splitting large pages Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [26/28] CPA: Fix reference counting when changing already changed pages Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [27/28] CPA: Change comments of external interfaces to kerneldoc format Andi Kleen
2008-01-03 15:24 ` [PATCH CPA] [28/28] Make kernel_text test match boot mapping initialization Andi Kleen
2008-01-10  9:31 ` CPA patchset Ingo Molnar
2008-01-10  9:44   ` Dave Airlie
2008-01-10  9:55     ` Andi Kleen
2008-01-10 10:20       ` Dave Airlie
2008-01-10 10:50         ` Andi Kleen
2008-01-10 10:02     ` Ingo Molnar
2008-01-10  9:53   ` Andi Kleen
2008-01-10 10:04     ` Ingo Molnar
2008-01-10 10:07       ` Andi Kleen
2008-01-10 10:57         ` Ingo Molnar
2008-01-10 11:12           ` Andi Kleen
2008-01-11  7:19             ` Ingo Molnar
2008-01-11  7:33               ` Ingo Molnar
2008-01-11 11:28                 ` Andi Kleen
2008-01-11 11:26               ` Andi Kleen
2008-01-11 17:02               ` dean gaudet
2008-01-11 17:18                 ` Arjan van de Ven
2008-01-11 17:56                 ` dean gaudet
2008-01-10 10:43     ` Ingo Molnar
2008-01-10 11:07       ` Andi Kleen
2008-01-10 12:22         ` Ingo Molnar
2008-01-10 12:39           ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080103152423.8ABD614E23@wotan.suse.de \
    --to=ak@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®