Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Add support for CONFIG_DEBUG_VIRTUAL

Provide hooks to intercept bad usages of virt_to_phys() and
__pa_symbol() throughout the kernel. To make this possible, we need to
rename the current implement of virt_to_phys() into
__virt_to_phys_nodebug() and wrap it around depending on
CONFIG_DEBUG_VIRTUAL.

A similar thing is needed for __pa_symbol() which is now aliased to
__phys_addr_symbol() whose implementation is either the direct return of
RELOC_HIDE or goes through the debug version.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

authored by

Florian Fainelli and committed by
Thomas Bogendoerfer
dfad83cb 666c1fc9

+83 -4
+1
arch/mips/Kconfig
··· 4 4 default y 5 5 select ARCH_32BIT_OFF_T if !64BIT 6 6 select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT 7 + select ARCH_HAS_DEBUG_VIRTUAL if !64BIT 7 8 select ARCH_HAS_FORTIFY_SOURCE 8 9 select ARCH_HAS_KCOV 9 10 select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE if !EVA
+13 -1
arch/mips/include/asm/io.h
··· 100 100 * almost all conceivable cases a device driver should not be using 101 101 * this function 102 102 */ 103 - static inline unsigned long virt_to_phys(volatile const void *address) 103 + static inline unsigned long __virt_to_phys_nodebug(volatile const void *address) 104 104 { 105 105 return __pa(address); 106 + } 107 + 108 + #ifdef CONFIG_DEBUG_VIRTUAL 109 + extern phys_addr_t __virt_to_phys(volatile const void *x); 110 + #else 111 + #define __virt_to_phys(x) __virt_to_phys_nodebug(x) 112 + #endif 113 + 114 + #define virt_to_phys virt_to_phys 115 + static inline phys_addr_t virt_to_phys(const volatile void *x) 116 + { 117 + return __virt_to_phys(x); 106 118 } 107 119 108 120 /*
+8 -1
arch/mips/include/asm/page.h
··· 210 210 * also affect MIPS so we keep this one until GCC 3.x has been retired 211 211 * before we can apply https://patchwork.linux-mips.org/patch/1541/ 212 212 */ 213 + #define __pa_symbol_nodebug(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) 214 + 215 + #ifdef CONFIG_DEBUG_VIRTUAL 216 + extern phys_addr_t __phys_addr_symbol(unsigned long x); 217 + #else 218 + #define __phys_addr_symbol(x) __pa_symbol_nodebug(x) 219 + #endif 213 220 214 221 #ifndef __pa_symbol 215 - #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) 222 + #define __pa_symbol(x) __phys_addr_symbol((unsigned long)(x)) 216 223 #endif 217 224 218 225 #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+3 -2
arch/mips/kernel/vdso.c
··· 90 90 { 91 91 struct mips_vdso_image *image = current->thread.abi->vdso; 92 92 struct mm_struct *mm = current->mm; 93 - unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn; 93 + unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn, gic_base; 94 94 struct vm_area_struct *vma; 95 95 int ret; 96 96 ··· 158 158 159 159 /* Map GIC user page. */ 160 160 if (gic_size) { 161 - gic_pfn = virt_to_phys(mips_gic_base + MIPS_GIC_USER_OFS) >> PAGE_SHIFT; 161 + gic_base = (unsigned long)mips_gic_base + MIPS_GIC_USER_OFS; 162 + gic_pfn = virt_to_phys((void *)gic_base) >> PAGE_SHIFT; 162 163 163 164 ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size, 164 165 pgprot_noncached(vma->vm_page_prot));
+2
arch/mips/mm/Makefile
··· 40 40 obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o 41 41 obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o 42 42 obj-$(CONFIG_SCACHE_DEBUGFS) += sc-debugfs.o 43 + 44 + obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
+56
arch/mips/mm/physaddr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/bug.h> 3 + #include <linux/export.h> 4 + #include <linux/types.h> 5 + #include <linux/mmdebug.h> 6 + #include <linux/mm.h> 7 + 8 + #include <asm/sections.h> 9 + #include <asm/io.h> 10 + #include <asm/page.h> 11 + #include <asm/dma.h> 12 + 13 + static inline bool __debug_virt_addr_valid(unsigned long x) 14 + { 15 + /* high_memory does not get immediately defined, and there 16 + * are early callers of __pa() against PAGE_OFFSET 17 + */ 18 + if (!high_memory && x >= PAGE_OFFSET) 19 + return true; 20 + 21 + if (high_memory && x >= PAGE_OFFSET && x < (unsigned long)high_memory) 22 + return true; 23 + 24 + /* 25 + * MAX_DMA_ADDRESS is a virtual address that may not correspond to an 26 + * actual physical address. Enough code relies on 27 + * virt_to_phys(MAX_DMA_ADDRESS) that we just need to work around it 28 + * and always return true. 29 + */ 30 + if (x == MAX_DMA_ADDRESS) 31 + return true; 32 + 33 + return false; 34 + } 35 + 36 + phys_addr_t __virt_to_phys(volatile const void *x) 37 + { 38 + WARN(!__debug_virt_addr_valid((unsigned long)x), 39 + "virt_to_phys used for non-linear address: %pK (%pS)\n", 40 + x, x); 41 + 42 + return __virt_to_phys_nodebug(x); 43 + } 44 + EXPORT_SYMBOL(__virt_to_phys); 45 + 46 + phys_addr_t __phys_addr_symbol(unsigned long x) 47 + { 48 + /* This is bounds checking against the kernel image only. 49 + * __pa_symbol should only be used on kernel symbol addresses. 50 + */ 51 + VIRTUAL_BUG_ON(x < (unsigned long)_text || 52 + x > (unsigned long)_end); 53 + 54 + return __pa_symbol_nodebug(x); 55 + } 56 + EXPORT_SYMBOL(__phys_addr_symbol);