162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#define DISABLE_BRANCH_PROFILING
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/kasan.h>
662306a36Sopenharmony_ci#include <linux/memblock.h>
762306a36Sopenharmony_ci#include <linux/hugetlb.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic int __init
1062306a36Sopenharmony_cikasan_init_shadow_8M(unsigned long k_start, unsigned long k_end, void *block)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	pmd_t *pmd = pmd_off_k(k_start);
1362306a36Sopenharmony_ci	unsigned long k_cur, k_next;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	for (k_cur = k_start; k_cur != k_end; k_cur = k_next, pmd += 2, block += SZ_8M) {
1662306a36Sopenharmony_ci		pte_basic_t *new;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci		k_next = pgd_addr_end(k_cur, k_end);
1962306a36Sopenharmony_ci		k_next = pgd_addr_end(k_next, k_end);
2062306a36Sopenharmony_ci		if ((void *)pmd_page_vaddr(*pmd) != kasan_early_shadow_pte)
2162306a36Sopenharmony_ci			continue;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		new = memblock_alloc(sizeof(pte_basic_t), SZ_4K);
2462306a36Sopenharmony_ci		if (!new)
2562306a36Sopenharmony_ci			return -ENOMEM;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci		*new = pte_val(pte_mkhuge(pfn_pte(PHYS_PFN(__pa(block)), PAGE_KERNEL)));
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci		hugepd_populate_kernel((hugepd_t *)pmd, (pte_t *)new, PAGE_SHIFT_8M);
3062306a36Sopenharmony_ci		hugepd_populate_kernel((hugepd_t *)pmd + 1, (pte_t *)new, PAGE_SHIFT_8M);
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci	return 0;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint __init kasan_init_region(void *start, size_t size)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned long k_start = (unsigned long)kasan_mem_to_shadow(start);
3862306a36Sopenharmony_ci	unsigned long k_end = (unsigned long)kasan_mem_to_shadow(start + size);
3962306a36Sopenharmony_ci	unsigned long k_cur;
4062306a36Sopenharmony_ci	int ret;
4162306a36Sopenharmony_ci	void *block;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	block = memblock_alloc(k_end - k_start, SZ_8M);
4462306a36Sopenharmony_ci	if (!block)
4562306a36Sopenharmony_ci		return -ENOMEM;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (IS_ALIGNED(k_start, SZ_8M)) {
4862306a36Sopenharmony_ci		kasan_init_shadow_8M(k_start, ALIGN_DOWN(k_end, SZ_8M), block);
4962306a36Sopenharmony_ci		k_cur = ALIGN_DOWN(k_end, SZ_8M);
5062306a36Sopenharmony_ci		if (k_cur == k_end)
5162306a36Sopenharmony_ci			goto finish;
5262306a36Sopenharmony_ci	} else {
5362306a36Sopenharmony_ci		k_cur = k_start;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	ret = kasan_init_shadow_page_tables(k_start, k_end);
5762306a36Sopenharmony_ci	if (ret)
5862306a36Sopenharmony_ci		return ret;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (; k_cur < k_end; k_cur += PAGE_SIZE) {
6162306a36Sopenharmony_ci		pmd_t *pmd = pmd_off_k(k_cur);
6262306a36Sopenharmony_ci		void *va = block + k_cur - k_start;
6362306a36Sopenharmony_ci		pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		if (k_cur < ALIGN_DOWN(k_end, SZ_512K))
6662306a36Sopenharmony_ci			pte = pte_mkhuge(pte);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		__set_pte_at(&init_mm, k_cur, pte_offset_kernel(pmd, k_cur), pte, 0);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_cifinish:
7162306a36Sopenharmony_ci	flush_tlb_kernel_range(k_start, k_end);
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
74