diff options
Diffstat (limited to 'arch/x86/mm/physaddr.c')
| -rw-r--r-- | arch/x86/mm/physaddr.c | 60 | 
1 files changed, 44 insertions, 16 deletions
diff --git a/arch/x86/mm/physaddr.c b/arch/x86/mm/physaddr.c index d2e2735327b..e666cbbb926 100644 --- a/arch/x86/mm/physaddr.c +++ b/arch/x86/mm/physaddr.c @@ -1,3 +1,4 @@ +#include <linux/bootmem.h>  #include <linux/mmdebug.h>  #include <linux/module.h>  #include <linux/mm.h> @@ -8,33 +9,54 @@  #ifdef CONFIG_X86_64 +#ifdef CONFIG_DEBUG_VIRTUAL  unsigned long __phys_addr(unsigned long x)  { -	if (x >= __START_KERNEL_map) { -		x -= __START_KERNEL_map; -		VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE); -		x += phys_base; +	unsigned long y = x - __START_KERNEL_map; + +	/* use the carry flag to determine if x was < __START_KERNEL_map */ +	if (unlikely(x > y)) { +		x = y + phys_base; + +		VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);  	} else { -		VIRTUAL_BUG_ON(x < PAGE_OFFSET); -		x -= PAGE_OFFSET; -		VIRTUAL_BUG_ON(!phys_addr_valid(x)); +		x = y + (__START_KERNEL_map - PAGE_OFFSET); + +		/* carry flag will be set if starting x was >= PAGE_OFFSET */ +		VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x));  	} +  	return x;  }  EXPORT_SYMBOL(__phys_addr); +unsigned long __phys_addr_symbol(unsigned long x) +{ +	unsigned long y = x - __START_KERNEL_map; + +	/* only check upper bounds since lower bounds will trigger carry */ +	VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE); + +	return y + phys_base; +} +EXPORT_SYMBOL(__phys_addr_symbol); +#endif +  bool __virt_addr_valid(unsigned long x)  { -	if (x >= __START_KERNEL_map) { -		x -= __START_KERNEL_map; -		if (x >= KERNEL_IMAGE_SIZE) +	unsigned long y = x - __START_KERNEL_map; + +	/* use the carry flag to determine if x was < __START_KERNEL_map */ +	if (unlikely(x > y)) { +		x = y + phys_base; + +		if (y >= KERNEL_IMAGE_SIZE)  			return false; -		x += phys_base;  	} else { -		if (x < PAGE_OFFSET) -			return false; -		x -= PAGE_OFFSET; -		if (!phys_addr_valid(x)) +		x = y + (__START_KERNEL_map - PAGE_OFFSET); + +		/* carry flag will be set if starting x was >= PAGE_OFFSET */ +		if ((x > y) || !phys_addr_valid(x))  			return false;  	} @@ -47,10 +69,16 @@ EXPORT_SYMBOL(__virt_addr_valid);  #ifdef CONFIG_DEBUG_VIRTUAL  unsigned long __phys_addr(unsigned long x)  { +	unsigned long phys_addr = x - PAGE_OFFSET;  	/* VMALLOC_* aren't constants  */  	VIRTUAL_BUG_ON(x < PAGE_OFFSET);  	VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x)); -	return x - PAGE_OFFSET; +	/* max_low_pfn is set early, but not _that_ early */ +	if (max_low_pfn) { +		VIRTUAL_BUG_ON((phys_addr >> PAGE_SHIFT) > max_low_pfn); +		BUG_ON(slow_virt_to_phys((void *)x) != phys_addr); +	} +	return phys_addr;  }  EXPORT_SYMBOL(__phys_addr);  #endif  |