diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2017-01-14 21:59:00 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-02-28 06:06:09 -0500 |
commit | e377cd8221ebbe0b517861aa3d823bb42f9abbd4 (patch) | |
tree | 009c0f27e450c6e40a9576dbce4e03a55a4dadae | |
parent | 399f157afd30ad942e08dfa0ab28734c50bc6b00 (diff) |
ARM: 8640/1: Add support for CONFIG_DEBUG_VIRTUAL
x86 has an option: CONFIG_DEBUG_VIRTUAL to do additional checks on
virt_to_phys calls. The goal is to catch users who are calling
virt_to_phys on non-linear addresses immediately. This includes caller
using __virt_to_phys() on image addresses instead of __pa_symbol(). This
is a generally useful debug feature to spot bad code (particulary in
drivers).
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Acked-by: Laura Abbott <labbott@redhat.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/memory.h | 15 | ||||
-rw-r--r-- | arch/arm/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mm/physaddr.c | 57 |
4 files changed, 72 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5fab553fd03a..4700294f4e09 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -2,6 +2,7 @@ config ARM | |||
2 | bool | 2 | bool |
3 | default y | 3 | default y |
4 | select ARCH_CLOCKSOURCE_DATA | 4 | select ARCH_CLOCKSOURCE_DATA |
5 | select ARCH_HAS_DEBUG_VIRTUAL | ||
5 | select ARCH_HAS_DEVMEM_IS_ALLOWED | 6 | select ARCH_HAS_DEVMEM_IS_ALLOWED |
6 | select ARCH_HAS_ELF_RANDOMIZE | 7 | select ARCH_HAS_ELF_RANDOMIZE |
7 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST | 8 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST |
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index bee7511c5098..c30d0d82a105 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h | |||
@@ -213,7 +213,7 @@ extern const void *__pv_table_begin, *__pv_table_end; | |||
213 | : "r" (x), "I" (__PV_BITS_31_24) \ | 213 | : "r" (x), "I" (__PV_BITS_31_24) \ |
214 | : "cc") | 214 | : "cc") |
215 | 215 | ||
216 | static inline phys_addr_t __virt_to_phys(unsigned long x) | 216 | static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x) |
217 | { | 217 | { |
218 | phys_addr_t t; | 218 | phys_addr_t t; |
219 | 219 | ||
@@ -245,7 +245,7 @@ static inline unsigned long __phys_to_virt(phys_addr_t x) | |||
245 | #define PHYS_OFFSET PLAT_PHYS_OFFSET | 245 | #define PHYS_OFFSET PLAT_PHYS_OFFSET |
246 | #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) | 246 | #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) |
247 | 247 | ||
248 | static inline phys_addr_t __virt_to_phys(unsigned long x) | 248 | static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x) |
249 | { | 249 | { |
250 | return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET; | 250 | return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET; |
251 | } | 251 | } |
@@ -261,6 +261,16 @@ static inline unsigned long __phys_to_virt(phys_addr_t x) | |||
261 | ((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \ | 261 | ((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \ |
262 | PHYS_PFN_OFFSET) | 262 | PHYS_PFN_OFFSET) |
263 | 263 | ||
264 | #define __pa_symbol_nodebug(x) __virt_to_phys_nodebug((x)) | ||
265 | |||
266 | #ifdef CONFIG_DEBUG_VIRTUAL | ||
267 | extern phys_addr_t __virt_to_phys(unsigned long x); | ||
268 | extern phys_addr_t __phys_addr_symbol(unsigned long x); | ||
269 | #else | ||
270 | #define __virt_to_phys(x) __virt_to_phys_nodebug(x) | ||
271 | #define __phys_addr_symbol(x) __pa_symbol_nodebug(x) | ||
272 | #endif | ||
273 | |||
264 | /* | 274 | /* |
265 | * These are *only* valid on the kernel direct mapped RAM memory. | 275 | * These are *only* valid on the kernel direct mapped RAM memory. |
266 | * Note: Drivers should NOT use these. They are the wrong | 276 | * Note: Drivers should NOT use these. They are the wrong |
@@ -283,6 +293,7 @@ static inline void *phys_to_virt(phys_addr_t x) | |||
283 | * Drivers should NOT use these either. | 293 | * Drivers should NOT use these either. |
284 | */ | 294 | */ |
285 | #define __pa(x) __virt_to_phys((unsigned long)(x)) | 295 | #define __pa(x) __virt_to_phys((unsigned long)(x)) |
296 | #define __pa_symbol(x) __phys_addr_symbol(RELOC_HIDE((unsigned long)(x), 0)) | ||
286 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) | 297 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) |
287 | #define pfn_to_kaddr(pfn) __va((phys_addr_t)(pfn) << PAGE_SHIFT) | 298 | #define pfn_to_kaddr(pfn) __va((phys_addr_t)(pfn) << PAGE_SHIFT) |
288 | 299 | ||
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index e8698241ece9..b3dea80715b4 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile | |||
@@ -14,6 +14,7 @@ endif | |||
14 | 14 | ||
15 | obj-$(CONFIG_ARM_PTDUMP) += dump.o | 15 | obj-$(CONFIG_ARM_PTDUMP) += dump.o |
16 | obj-$(CONFIG_MODULES) += proc-syms.o | 16 | obj-$(CONFIG_MODULES) += proc-syms.o |
17 | obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o | ||
17 | 18 | ||
18 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o | 19 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o |
19 | obj-$(CONFIG_HIGHMEM) += highmem.o | 20 | obj-$(CONFIG_HIGHMEM) += highmem.o |
diff --git a/arch/arm/mm/physaddr.c b/arch/arm/mm/physaddr.c new file mode 100644 index 000000000000..02e60f495608 --- /dev/null +++ b/arch/arm/mm/physaddr.c | |||
@@ -0,0 +1,57 @@ | |||
1 | #include <linux/bug.h> | ||
2 | #include <linux/export.h> | ||
3 | #include <linux/types.h> | ||
4 | #include <linux/mmdebug.h> | ||
5 | #include <linux/mm.h> | ||
6 | |||
7 | #include <asm/sections.h> | ||
8 | #include <asm/memory.h> | ||
9 | #include <asm/fixmap.h> | ||
10 | #include <asm/dma.h> | ||
11 | |||
12 | #include "mm.h" | ||
13 | |||
14 | static inline bool __virt_addr_valid(unsigned long x) | ||
15 | { | ||
16 | /* | ||
17 | * high_memory does not get immediately defined, and there | ||
18 | * are early callers of __pa() against PAGE_OFFSET | ||
19 | */ | ||
20 | if (!high_memory && x >= PAGE_OFFSET) | ||
21 | return true; | ||
22 | |||
23 | if (high_memory && x >= PAGE_OFFSET && x < (unsigned long)high_memory) | ||
24 | return true; | ||
25 | |||
26 | /* | ||
27 | * MAX_DMA_ADDRESS is a virtual address that may not correspond to an | ||
28 | * actual physical address. Enough code relies on __pa(MAX_DMA_ADDRESS) | ||
29 | * that we just need to work around it and always return true. | ||
30 | */ | ||
31 | if (x == MAX_DMA_ADDRESS) | ||
32 | return true; | ||
33 | |||
34 | return false; | ||
35 | } | ||
36 | |||
37 | phys_addr_t __virt_to_phys(unsigned long x) | ||
38 | { | ||
39 | WARN(!__virt_addr_valid(x), | ||
40 | "virt_to_phys used for non-linear address: %pK (%pS)\n", | ||
41 | (void *)x, (void *)x); | ||
42 | |||
43 | return __virt_to_phys_nodebug(x); | ||
44 | } | ||
45 | EXPORT_SYMBOL(__virt_to_phys); | ||
46 | |||
47 | phys_addr_t __phys_addr_symbol(unsigned long x) | ||
48 | { | ||
49 | /* This is bounds checking against the kernel image only. | ||
50 | * __pa_symbol should only be used on kernel symbol addresses. | ||
51 | */ | ||
52 | VIRTUAL_BUG_ON(x < (unsigned long)KERNEL_START || | ||
53 | x > (unsigned long)KERNEL_END); | ||
54 | |||
55 | return __pa_symbol_nodebug(x); | ||
56 | } | ||
57 | EXPORT_SYMBOL(__phys_addr_symbol); | ||