18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/memblock.h>
38c2ecf20Sopenharmony_ci#include <linux/mmdebug.h>
48c2ecf20Sopenharmony_ci#include <linux/export.h>
58c2ecf20Sopenharmony_ci#include <linux/mm.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <asm/page.h>
88c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "physaddr.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VIRTUAL
158c2ecf20Sopenharmony_ciunsigned long __phys_addr(unsigned long x)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/* use the carry flag to determine if x was < __START_KERNEL_map */
208c2ecf20Sopenharmony_ci	if (unlikely(x > y)) {
218c2ecf20Sopenharmony_ci		x = y + phys_base;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci		VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
248c2ecf20Sopenharmony_ci	} else {
258c2ecf20Sopenharmony_ci		x = y + (__START_KERNEL_map - PAGE_OFFSET);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci		/* carry flag will be set if starting x was >= PAGE_OFFSET */
288c2ecf20Sopenharmony_ci		VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x));
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return x;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__phys_addr);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciunsigned long __phys_addr_symbol(unsigned long x)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/* only check upper bounds since lower bounds will trigger carry */
408c2ecf20Sopenharmony_ci	VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return y + phys_base;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__phys_addr_symbol);
458c2ecf20Sopenharmony_ci#endif
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cibool __virt_addr_valid(unsigned long x)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	unsigned long y = x - __START_KERNEL_map;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* use the carry flag to determine if x was < __START_KERNEL_map */
528c2ecf20Sopenharmony_ci	if (unlikely(x > y)) {
538c2ecf20Sopenharmony_ci		x = y + phys_base;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if (y >= KERNEL_IMAGE_SIZE)
568c2ecf20Sopenharmony_ci			return false;
578c2ecf20Sopenharmony_ci	} else {
588c2ecf20Sopenharmony_ci		x = y + (__START_KERNEL_map - PAGE_OFFSET);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		/* carry flag will be set if starting x was >= PAGE_OFFSET */
618c2ecf20Sopenharmony_ci		if ((x > y) || !phys_addr_valid(x))
628c2ecf20Sopenharmony_ci			return false;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return pfn_valid(x >> PAGE_SHIFT);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__virt_addr_valid);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#else
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VIRTUAL
728c2ecf20Sopenharmony_ciunsigned long __phys_addr(unsigned long x)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	unsigned long phys_addr = x - PAGE_OFFSET;
758c2ecf20Sopenharmony_ci	/* VMALLOC_* aren't constants  */
768c2ecf20Sopenharmony_ci	VIRTUAL_BUG_ON(x < PAGE_OFFSET);
778c2ecf20Sopenharmony_ci	VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x));
788c2ecf20Sopenharmony_ci	/* max_low_pfn is set early, but not _that_ early */
798c2ecf20Sopenharmony_ci	if (max_low_pfn) {
808c2ecf20Sopenharmony_ci		VIRTUAL_BUG_ON((phys_addr >> PAGE_SHIFT) > max_low_pfn);
818c2ecf20Sopenharmony_ci		BUG_ON(slow_virt_to_phys((void *)x) != phys_addr);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	return phys_addr;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__phys_addr);
868c2ecf20Sopenharmony_ci#endif
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cibool __virt_addr_valid(unsigned long x)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	if (x < PAGE_OFFSET)
918c2ecf20Sopenharmony_ci		return false;
928c2ecf20Sopenharmony_ci	if (__vmalloc_start_set && is_vmalloc_addr((void *) x))
938c2ecf20Sopenharmony_ci		return false;
948c2ecf20Sopenharmony_ci	if (x >= FIXADDR_START)
958c2ecf20Sopenharmony_ci		return false;
968c2ecf20Sopenharmony_ci	return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__virt_addr_valid);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#endif	/* CONFIG_X86_64 */
101