123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- #include <linux/kmemcheck.h>
- #include <linux/module.h>
- #include <linux/mm.h>
- #include <asm/page.h>
- #include <asm/pgtable.h>
- #include "pte.h"
- #include "shadow.h"
- /*
- * Return the shadow address for the given address. Returns NULL if the
- * address is not tracked.
- *
- * We need to be extremely careful not to follow any invalid pointers,
- * because this function can be called for *any* possible address.
- */
- void *kmemcheck_shadow_lookup(unsigned long address)
- {
- pte_t *pte;
- struct page *page;
- if (!virt_addr_valid(address))
- return NULL;
- pte = kmemcheck_pte_lookup(address);
- if (!pte)
- return NULL;
- page = virt_to_page(address);
- if (!page->shadow)
- return NULL;
- return page->shadow + (address & (PAGE_SIZE - 1));
- }
- static void mark_shadow(void *address, unsigned int n,
- enum kmemcheck_shadow status)
- {
- unsigned long addr = (unsigned long) address;
- unsigned long last_addr = addr + n - 1;
- unsigned long page = addr & PAGE_MASK;
- unsigned long last_page = last_addr & PAGE_MASK;
- unsigned int first_n;
- void *shadow;
- /* If the memory range crosses a page boundary, stop there. */
- if (page == last_page)
- first_n = n;
- else
- first_n = page + PAGE_SIZE - addr;
- shadow = kmemcheck_shadow_lookup(addr);
- if (shadow)
- memset(shadow, status, first_n);
- addr += first_n;
- n -= first_n;
- /* Do full-page memset()s. */
- while (n >= PAGE_SIZE) {
- shadow = kmemcheck_shadow_lookup(addr);
- if (shadow)
- memset(shadow, status, PAGE_SIZE);
- addr += PAGE_SIZE;
- n -= PAGE_SIZE;
- }
- /* Do the remaining page, if any. */
- if (n > 0) {
- shadow = kmemcheck_shadow_lookup(addr);
- if (shadow)
- memset(shadow, status, n);
- }
- }
- void kmemcheck_mark_unallocated(void *address, unsigned int n)
- {
- mark_shadow(address, n, KMEMCHECK_SHADOW_UNALLOCATED);
- }
- void kmemcheck_mark_uninitialized(void *address, unsigned int n)
- {
- mark_shadow(address, n, KMEMCHECK_SHADOW_UNINITIALIZED);
- }
- /*
- * Fill the shadow memory of the given address such that the memory at that
- * address is marked as being initialized.
- */
- void kmemcheck_mark_initialized(void *address, unsigned int n)
- {
- mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED);
- }
- EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized);
- void kmemcheck_mark_freed(void *address, unsigned int n)
- {
- mark_shadow(address, n, KMEMCHECK_SHADOW_FREED);
- }
- void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n)
- {
- unsigned int i;
- for (i = 0; i < n; ++i)
- kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE);
- }
- void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n)
- {
- unsigned int i;
- for (i = 0; i < n; ++i)
- kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE);
- }
- void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n)
- {
- unsigned int i;
- for (i = 0; i < n; ++i)
- kmemcheck_mark_initialized(page_address(&p[i]), PAGE_SIZE);
- }
- enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size)
- {
- uint8_t *x;
- unsigned int i;
- x = shadow;
- #ifdef CONFIG_KMEMCHECK_PARTIAL_OK
- /*
- * Make sure _some_ bytes are initialized. Gcc frequently generates
- * code to access neighboring bytes.
- */
- for (i = 0; i < size; ++i) {
- if (x[i] == KMEMCHECK_SHADOW_INITIALIZED)
- return x[i];
- }
- #else
- /* All bytes must be initialized. */
- for (i = 0; i < size; ++i) {
- if (x[i] != KMEMCHECK_SHADOW_INITIALIZED)
- return x[i];
- }
- #endif
- return x[0];
- }
- void kmemcheck_shadow_set(void *shadow, unsigned int size)
- {
- uint8_t *x;
- unsigned int i;
- x = shadow;
- for (i = 0; i < size; ++i)
- x[i] = KMEMCHECK_SHADOW_INITIALIZED;
- }
|