162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/memblock.h>
362306a36Sopenharmony_ci#include <linux/mmdebug.h>
462306a36Sopenharmony_ci#include <linux/export.h>
562306a36Sopenharmony_ci#include <linux/mm.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/page.h>
862306a36Sopenharmony_ci#include <linux/vmalloc.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "physaddr.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#ifdef CONFIG_X86_64
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VIRTUAL
1562306a36Sopenharmony_ciunsigned long __phys_addr(unsigned long x)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/* use the carry flag to determine if x was < __START_KERNEL_map */
2062306a36Sopenharmony_ci	if (unlikely(x > y)) {
2162306a36Sopenharmony_ci		x = y + phys_base;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
2462306a36Sopenharmony_ci	} else {
2562306a36Sopenharmony_ci		x = y + (__START_KERNEL_map - PAGE_OFFSET);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci		/* carry flag will be set if starting x was >= PAGE_OFFSET */
2862306a36Sopenharmony_ci		VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x));
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return x;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ciEXPORT_SYMBOL(__phys_addr);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciunsigned long __phys_addr_symbol(unsigned long x)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* only check upper bounds since lower bounds will trigger carry */
4062306a36Sopenharmony_ci	VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return y + phys_base;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ciEXPORT_SYMBOL(__phys_addr_symbol);
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cibool __virt_addr_valid(unsigned long x)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* use the carry flag to determine if x was < __START_KERNEL_map */
5262306a36Sopenharmony_ci	if (unlikely(x > y)) {
5362306a36Sopenharmony_ci		x = y + phys_base;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		if (y >= KERNEL_IMAGE_SIZE)
5662306a36Sopenharmony_ci			return false;
5762306a36Sopenharmony_ci	} else {
5862306a36Sopenharmony_ci		x = y + (__START_KERNEL_map - PAGE_OFFSET);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		/* carry flag will be set if starting x was >= PAGE_OFFSET */
6162306a36Sopenharmony_ci		if ((x > y) || !phys_addr_valid(x))
6262306a36Sopenharmony_ci			return false;
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return pfn_valid(x >> PAGE_SHIFT);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ciEXPORT_SYMBOL(__virt_addr_valid);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#else
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VIRTUAL
7262306a36Sopenharmony_ciunsigned long __phys_addr(unsigned long x)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	unsigned long phys_addr = x - PAGE_OFFSET;
7562306a36Sopenharmony_ci	/* VMALLOC_* aren't constants  */
7662306a36Sopenharmony_ci	VIRTUAL_BUG_ON(x < PAGE_OFFSET);
7762306a36Sopenharmony_ci	VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x));
7862306a36Sopenharmony_ci	/* max_low_pfn is set early, but not _that_ early */
7962306a36Sopenharmony_ci	if (max_low_pfn) {
8062306a36Sopenharmony_ci		VIRTUAL_BUG_ON((phys_addr >> PAGE_SHIFT) > max_low_pfn);
8162306a36Sopenharmony_ci		BUG_ON(slow_virt_to_phys((void *)x) != phys_addr);
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci	return phys_addr;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ciEXPORT_SYMBOL(__phys_addr);
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cibool __virt_addr_valid(unsigned long x)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (x < PAGE_OFFSET)
9162306a36Sopenharmony_ci		return false;
9262306a36Sopenharmony_ci	if (__vmalloc_start_set && is_vmalloc_addr((void *) x))
9362306a36Sopenharmony_ci		return false;
9462306a36Sopenharmony_ci	if (x >= FIXADDR_START)
9562306a36Sopenharmony_ci		return false;
9662306a36Sopenharmony_ci	return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ciEXPORT_SYMBOL(__virt_addr_valid);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#endif	/* CONFIG_X86_64 */
101