Skip to content

Commit

Permalink
MIPS: Add support for CONFIG_DEBUG_VIRTUAL
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ffainelli authored and intel-lab-lkp committed Mar 26, 2021
1 parent 0f4498c commit ee0c68f
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 3 deletions.
1 change: 1 addition & 0 deletions arch/mips/Kconfig
Expand Up @@ -4,6 +4,7 @@ config MIPS
default y
select ARCH_32BIT_OFF_T if !64BIT
select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT
select ARCH_HAS_DEBUG_VIRTUAL if !64BIT
select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_KCOV
select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI)
Expand Down
14 changes: 13 additions & 1 deletion arch/mips/include/asm/io.h
Expand Up @@ -100,11 +100,23 @@ static inline void set_io_port_base(unsigned long base)
* almost all conceivable cases a device driver should not be using
* this function
*/
static inline unsigned long virt_to_phys(volatile const void *address)
static inline unsigned long __virt_to_phys_nodebug(volatile const void *address)
{
return __pa(address);
}

#ifdef CONFIG_DEBUG_VIRTUAL
extern phys_addr_t __virt_to_phys(volatile const void *x);
#else
#define __virt_to_phys(x) __virt_to_phys_nodebug(x)
#endif

#define virt_to_phys virt_to_phys
static inline phys_addr_t virt_to_phys(const volatile void *x)
{
return __virt_to_phys(x);
}

/*
* phys_to_virt - map physical address to virtual
* @address: address to remap
Expand Down
9 changes: 8 additions & 1 deletion arch/mips/include/asm/page.h
Expand Up @@ -210,9 +210,16 @@ static inline unsigned long ___pa(unsigned long x)
* also affect MIPS so we keep this one until GCC 3.x has been retired
* before we can apply https://patchwork.linux-mips.org/patch/1541/
*/
#define __pa_symbol_nodebug(x) __pa(RELOC_HIDE((unsigned long)(x), 0))

#ifdef CONFIG_DEBUG_VIRTUAL
extern phys_addr_t __phys_addr_symbol(unsigned long x);
#else
#define __phys_addr_symbol(x) __pa_symbol_nodebug(x)
#endif

#ifndef __pa_symbol
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
#define __pa_symbol(x) __phys_addr_symbol((unsigned long)(x))
#endif

#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/kernel/vdso.c
Expand Up @@ -158,7 +158,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)

/* Map GIC user page. */
if (gic_size) {
gic_pfn = virt_to_phys(mips_gic_base + MIPS_GIC_USER_OFS) >> PAGE_SHIFT;
gic_pfn = virt_to_phys((void *)mips_gic_base + MIPS_GIC_USER_OFS) >> PAGE_SHIFT;

ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size,
pgprot_noncached(vma->vm_page_prot));
Expand Down
2 changes: 2 additions & 0 deletions arch/mips/mm/Makefile
Expand Up @@ -40,3 +40,5 @@ obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
obj-$(CONFIG_SCACHE_DEBUGFS) += sc-debugfs.o

obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
56 changes: 56 additions & 0 deletions arch/mips/mm/physaddr.c
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bug.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/mmdebug.h>
#include <linux/mm.h>

#include <asm/sections.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/dma.h>

static inline bool __debug_virt_addr_valid(unsigned long x)
{
/* high_memory does not get immediately defined, and there
* are early callers of __pa() against PAGE_OFFSET
*/
if (!high_memory && x >= PAGE_OFFSET)
return true;

if (high_memory && x >= PAGE_OFFSET && x < (unsigned long)high_memory)
return true;

/*
* MAX_DMA_ADDRESS is a virtual address that may not correspond to an
* actual physical address. Enough code relies on
* virt_to_phys(MAX_DMA_ADDRESS) that we just need to work around it
* and always return true.
*/
if (x == MAX_DMA_ADDRESS)
return true;

return false;
}

phys_addr_t __virt_to_phys(volatile const void *x)
{
WARN(!__debug_virt_addr_valid((unsigned long)x),
"virt_to_phys used for non-linear address: %pK (%pS)\n",
x, x);

return __virt_to_phys_nodebug(x);
}
EXPORT_SYMBOL(__virt_to_phys);

phys_addr_t __phys_addr_symbol(unsigned long x)
{
/* This is bounds checking against the kernel image only.
* __pa_symbol should only be used on kernel symbol addresses.
*/
VIRTUAL_BUG_ON(x < (unsigned long)_text ||
x > (unsigned long)_end);

return __pa_symbol_nodebug(x);
}
EXPORT_SYMBOL(__phys_addr_symbol);

0 comments on commit ee0c68f

Please sign in to comment.