Add linux-next specific files for 20110831
[linux-2.6/next.git] / arch / x86 / mm / kmemcheck / shadow.c
blobaec124214d972703812b68e3f9ff9abf8f851cb5
1 #include <linux/kmemcheck.h>
2 #include <linux/module.h>
3 #include <linux/mm.h>
5 #include <asm/page.h>
6 #include <asm/pgtable.h>
8 #include "pte.h"
9 #include "shadow.h"
12 * Return the shadow address for the given address. Returns NULL if the
13 * address is not tracked.
15 * We need to be extremely careful not to follow any invalid pointers,
16 * because this function can be called for *any* possible address.
18 void *kmemcheck_shadow_lookup(unsigned long address)
20 pte_t *pte;
21 struct page *page;
23 if (!virt_addr_valid(address))
24 return NULL;
26 pte = kmemcheck_pte_lookup(address);
27 if (!pte)
28 return NULL;
30 page = virt_to_page(address);
31 if (!page->shadow)
32 return NULL;
33 return page->shadow + (address & (PAGE_SIZE - 1));
36 static void mark_shadow(void *address, unsigned int n,
37 enum kmemcheck_shadow status)
39 unsigned long addr = (unsigned long) address;
40 unsigned long last_addr = addr + n - 1;
41 unsigned long page = addr & PAGE_MASK;
42 unsigned long last_page = last_addr & PAGE_MASK;
43 unsigned int first_n;
44 void *shadow;
46 /* If the memory range crosses a page boundary, stop there. */
47 if (page == last_page)
48 first_n = n;
49 else
50 first_n = page + PAGE_SIZE - addr;
52 shadow = kmemcheck_shadow_lookup(addr);
53 if (shadow)
54 memset(shadow, status, first_n);
56 addr += first_n;
57 n -= first_n;
59 /* Do full-page memset()s. */
60 while (n >= PAGE_SIZE) {
61 shadow = kmemcheck_shadow_lookup(addr);
62 if (shadow)
63 memset(shadow, status, PAGE_SIZE);
65 addr += PAGE_SIZE;
66 n -= PAGE_SIZE;
69 /* Do the remaining page, if any. */
70 if (n > 0) {
71 shadow = kmemcheck_shadow_lookup(addr);
72 if (shadow)
73 memset(shadow, status, n);
77 void kmemcheck_mark_unallocated(void *address, unsigned int n)
79 mark_shadow(address, n, KMEMCHECK_SHADOW_UNALLOCATED);
82 void kmemcheck_mark_uninitialized(void *address, unsigned int n)
84 mark_shadow(address, n, KMEMCHECK_SHADOW_UNINITIALIZED);
88 * Fill the shadow memory of the given address such that the memory at that
89 * address is marked as being initialized.
91 void kmemcheck_mark_initialized(void *address, unsigned int n)
93 mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED);
95 EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized);
97 void kmemcheck_mark_freed(void *address, unsigned int n)
99 mark_shadow(address, n, KMEMCHECK_SHADOW_FREED);
102 void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n)
104 unsigned int i;
106 for (i = 0; i < n; ++i)
107 kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE);
110 void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n)
112 unsigned int i;
114 for (i = 0; i < n; ++i)
115 kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE);
118 void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n)
120 unsigned int i;
122 for (i = 0; i < n; ++i)
123 kmemcheck_mark_initialized(page_address(&p[i]), PAGE_SIZE);
126 enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size)
128 #ifdef CONFIG_KMEMCHECK_PARTIAL_OK
129 uint8_t *x;
130 unsigned int i;
132 x = shadow;
135 * Make sure _some_ bytes are initialized. Gcc frequently generates
136 * code to access neighboring bytes.
138 for (i = 0; i < size; ++i) {
139 if (x[i] == KMEMCHECK_SHADOW_INITIALIZED)
140 return x[i];
143 return x[0];
144 #else
145 return kmemcheck_shadow_test_all(shadow, size);
146 #endif
149 enum kmemcheck_shadow kmemcheck_shadow_test_all(void *shadow, unsigned int size)
151 uint8_t *x;
152 unsigned int i;
154 x = shadow;
156 /* All bytes must be initialized. */
157 for (i = 0; i < size; ++i) {
158 if (x[i] != KMEMCHECK_SHADOW_INITIALIZED)
159 return x[i];
162 return x[0];
165 void kmemcheck_shadow_set(void *shadow, unsigned int size)
167 uint8_t *x;
168 unsigned int i;
170 x = shadow;
171 for (i = 0; i < size; ++i)
172 x[i] = KMEMCHECK_SHADOW_INITIALIZED;