1#include <linux/kernel.h>
2#include <linux/mm.h>
3#include <linux/page-debug-flags.h>
4#include <linux/poison.h>
5
6static inline void set_page_poison(struct page *page)
7{
8	__set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
9}
10
11static inline void clear_page_poison(struct page *page)
12{
13	__clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
14}
15
16static inline bool page_poison(struct page *page)
17{
18	return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
19}
20
21static void poison_highpage(struct page *page)
22{
23	/*
24	 * Page poisoning for highmem pages is not implemented.
25	 *
26	 * This can be called from interrupt contexts.
27	 * So we need to create a new kmap_atomic slot for this
28	 * application and it will need interrupt protection.
29	 */
30}
31
32static void poison_page(struct page *page)
33{
34	void *addr;
35
36	if (PageHighMem(page)) {
37		poison_highpage(page);
38		return;
39	}
40	set_page_poison(page);
41	addr = page_address(page);
42	memset(addr, PAGE_POISON, PAGE_SIZE);
43}
44
45static void poison_pages(struct page *page, int n)
46{
47	int i;
48
49	for (i = 0; i < n; i++)
50		poison_page(page + i);
51}
52
53static bool single_bit_flip(unsigned char a, unsigned char b)
54{
55	unsigned char error = a ^ b;
56
57	return error && !(error & (error - 1));
58}
59
60static void check_poison_mem(unsigned char *mem, size_t bytes)
61{
62	unsigned char *start;
63	unsigned char *end;
64
65	for (start = mem; start < mem + bytes; start++) {
66		if (*start != PAGE_POISON)
67			break;
68	}
69	if (start == mem + bytes)
70		return;
71
72	for (end = mem + bytes - 1; end > start; end--) {
73		if (*end != PAGE_POISON)
74			break;
75	}
76
77	if (!printk_ratelimit())
78		return;
79	else if (start == end && single_bit_flip(*start, PAGE_POISON))
80		printk(KERN_ERR "pagealloc: single bit error\n");
81	else
82		printk(KERN_ERR "pagealloc: memory corruption\n");
83
84	print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
85			end - start + 1, 1);
86	dump_stack();
87}
88
89static void unpoison_highpage(struct page *page)
90{
91	/*
92	 * See comment in poison_highpage().
93	 * Highmem pages should not be poisoned for now
94	 */
95	BUG_ON(page_poison(page));
96}
97
98static void unpoison_page(struct page *page)
99{
100	if (PageHighMem(page)) {
101		unpoison_highpage(page);
102		return;
103	}
104	if (page_poison(page)) {
105		void *addr = page_address(page);
106
107		check_poison_mem(addr, PAGE_SIZE);
108		clear_page_poison(page);
109	}
110}
111
112static void unpoison_pages(struct page *page, int n)
113{
114	int i;
115
116	for (i = 0; i < n; i++)
117		unpoison_page(page + i);
118}
119
120void kernel_map_pages(struct page *page, int numpages, int enable)
121{
122	if (!debug_pagealloc_enabled)
123		return;
124
125	if (enable)
126		unpoison_pages(page, numpages);
127	else
128		poison_pages(page, numpages);
129}
130