diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2009-03-16 11:51:55 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-03-17 07:56:48 -0400 |
commit | 2e34bde18576a02c897ae6b699ea26301d92be1b (patch) | |
tree | 301278f1af66dd5be296814e19af2f6190e27634 /lib | |
parent | 6c132d1bcdc716e898b4092bb1abc696505c37e7 (diff) |
dma-debug: add checks for kernel text and rodata
Impact: get notified if a device dma maps illegal areas
This patch adds a check to print a warning message when a device driver
tries to map a memory area from the kernel text segment or rodata.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma-debug.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index dba02f138bd3..6022eb4a0cd0 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include <asm/sections.h> | ||
33 | |||
32 | #define HASH_SIZE 1024ULL | 34 | #define HASH_SIZE 1024ULL |
33 | #define HASH_FN_SHIFT 13 | 35 | #define HASH_FN_SHIFT 13 |
34 | #define HASH_FN_MASK (HASH_SIZE - 1) | 36 | #define HASH_FN_MASK (HASH_SIZE - 1) |
@@ -549,6 +551,24 @@ static void check_for_stack(struct device *dev, void *addr) | |||
549 | "stack [addr=%p]\n", addr); | 551 | "stack [addr=%p]\n", addr); |
550 | } | 552 | } |
551 | 553 | ||
554 | static inline bool overlap(void *addr, u64 size, void *start, void *end) | ||
555 | { | ||
556 | void *addr2 = (char *)addr + size; | ||
557 | |||
558 | return ((addr >= start && addr < end) || | ||
559 | (addr2 >= start && addr2 < end) || | ||
560 | ((addr < start) && (addr2 >= end))); | ||
561 | } | ||
562 | |||
563 | static void check_for_illegal_area(struct device *dev, void *addr, u64 size) | ||
564 | { | ||
565 | if (overlap(addr, size, _text, _etext) || | ||
566 | overlap(addr, size, __start_rodata, __end_rodata)) | ||
567 | err_printk(dev, NULL, "DMA-API: device driver maps " | ||
568 | "memory from kernel text or rodata " | ||
569 | "[addr=%p] [size=%llu]\n", addr, size); | ||
570 | } | ||
571 | |||
552 | static void check_sync(struct device *dev, dma_addr_t addr, | 572 | static void check_sync(struct device *dev, dma_addr_t addr, |
553 | u64 size, u64 offset, int direction, bool to_cpu) | 573 | u64 size, u64 offset, int direction, bool to_cpu) |
554 | { | 574 | { |
@@ -645,8 +665,11 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
645 | entry->direction = direction; | 665 | entry->direction = direction; |
646 | 666 | ||
647 | if (map_single) { | 667 | if (map_single) { |
668 | void *addr = ((char *)page_address(page)) + offset; | ||
669 | |||
648 | entry->type = dma_debug_single; | 670 | entry->type = dma_debug_single; |
649 | check_for_stack(dev, page_address(page) + offset); | 671 | check_for_stack(dev, addr); |
672 | check_for_illegal_area(dev, addr, size); | ||
650 | } | 673 | } |
651 | 674 | ||
652 | add_dma_entry(entry); | 675 | add_dma_entry(entry); |
@@ -699,6 +722,7 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, | |||
699 | entry->sg_mapped_ents = mapped_ents; | 722 | entry->sg_mapped_ents = mapped_ents; |
700 | 723 | ||
701 | check_for_stack(dev, sg_virt(s)); | 724 | check_for_stack(dev, sg_virt(s)); |
725 | check_for_illegal_area(dev, sg_virt(s), s->length); | ||
702 | 726 | ||
703 | add_dma_entry(entry); | 727 | add_dma_entry(entry); |
704 | } | 728 | } |