162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Regents of the University of California 462306a36Sopenharmony_ci * Copyright (C) 2019 Western Digital Corporation or its affiliates. 562306a36Sopenharmony_ci * Copyright (C) 2020 FORTH-ICS/CARV 662306a36Sopenharmony_ci * Nick Kossifidis <mick@ics.forth.gr> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/memblock.h> 1262306a36Sopenharmony_ci#include <linux/initrd.h> 1362306a36Sopenharmony_ci#include <linux/swap.h> 1462306a36Sopenharmony_ci#include <linux/swiotlb.h> 1562306a36Sopenharmony_ci#include <linux/sizes.h> 1662306a36Sopenharmony_ci#include <linux/of_fdt.h> 1762306a36Sopenharmony_ci#include <linux/of_reserved_mem.h> 1862306a36Sopenharmony_ci#include <linux/libfdt.h> 1962306a36Sopenharmony_ci#include <linux/set_memory.h> 2062306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 2162306a36Sopenharmony_ci#include <linux/crash_dump.h> 2262306a36Sopenharmony_ci#include <linux/hugetlb.h> 2362306a36Sopenharmony_ci#ifdef CONFIG_RELOCATABLE 2462306a36Sopenharmony_ci#include <linux/elf.h> 2562306a36Sopenharmony_ci#endif 2662306a36Sopenharmony_ci#include <linux/kfence.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <asm/fixmap.h> 2962306a36Sopenharmony_ci#include <asm/io.h> 3062306a36Sopenharmony_ci#include <asm/numa.h> 3162306a36Sopenharmony_ci#include <asm/pgtable.h> 3262306a36Sopenharmony_ci#include <asm/ptdump.h> 3362306a36Sopenharmony_ci#include <asm/sections.h> 3462306a36Sopenharmony_ci#include <asm/soc.h> 3562306a36Sopenharmony_ci#include <asm/tlbflush.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "../kernel/head.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct kernel_mapping kernel_map __ro_after_init; 4062306a36Sopenharmony_ciEXPORT_SYMBOL(kernel_map); 4162306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 4262306a36Sopenharmony_ci#define kernel_map (*(struct kernel_mapping *)XIP_FIXUP(&kernel_map)) 4362306a36Sopenharmony_ci#endif 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#ifdef CONFIG_64BIT 4662306a36Sopenharmony_ciu64 satp_mode __ro_after_init = !IS_ENABLED(CONFIG_XIP_KERNEL) ? SATP_MODE_57 : SATP_MODE_39; 4762306a36Sopenharmony_ci#else 4862306a36Sopenharmony_ciu64 satp_mode __ro_after_init = SATP_MODE_32; 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ciEXPORT_SYMBOL(satp_mode); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cibool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL); 5362306a36Sopenharmony_cibool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL); 5462306a36Sopenharmony_ciEXPORT_SYMBOL(pgtable_l4_enabled); 5562306a36Sopenharmony_ciEXPORT_SYMBOL(pgtable_l5_enabled); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciphys_addr_t phys_ram_base __ro_after_init; 5862306a36Sopenharmony_ciEXPORT_SYMBOL(phys_ram_base); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciunsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] 6162306a36Sopenharmony_ci __page_aligned_bss; 6262306a36Sopenharmony_ciEXPORT_SYMBOL(empty_zero_page); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciextern char _start[]; 6562306a36Sopenharmony_civoid *_dtb_early_va __initdata; 6662306a36Sopenharmony_ciuintptr_t _dtb_early_pa __initdata; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic phys_addr_t dma32_phys_limit __initdata; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void __init zone_sizes_init(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, }; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32 7562306a36Sopenharmony_ci max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit); 7662306a36Sopenharmony_ci#endif 7762306a36Sopenharmony_ci max_zone_pfns[ZONE_NORMAL] = max_low_pfn; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci free_area_init(max_zone_pfns); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#if defined(CONFIG_MMU) && defined(CONFIG_DEBUG_VM) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define LOG2_SZ_1K ilog2(SZ_1K) 8562306a36Sopenharmony_ci#define LOG2_SZ_1M ilog2(SZ_1M) 8662306a36Sopenharmony_ci#define LOG2_SZ_1G ilog2(SZ_1G) 8762306a36Sopenharmony_ci#define LOG2_SZ_1T ilog2(SZ_1T) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic inline void print_mlk(char *name, unsigned long b, unsigned long t) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld kB)\n", name, b, t, 9262306a36Sopenharmony_ci (((t) - (b)) >> LOG2_SZ_1K)); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline void print_mlm(char *name, unsigned long b, unsigned long t) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld MB)\n", name, b, t, 9862306a36Sopenharmony_ci (((t) - (b)) >> LOG2_SZ_1M)); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline void print_mlg(char *name, unsigned long b, unsigned long t) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld GB)\n", name, b, t, 10462306a36Sopenharmony_ci (((t) - (b)) >> LOG2_SZ_1G)); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#ifdef CONFIG_64BIT 10862306a36Sopenharmony_cistatic inline void print_mlt(char *name, unsigned long b, unsigned long t) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld TB)\n", name, b, t, 11162306a36Sopenharmony_ci (((t) - (b)) >> LOG2_SZ_1T)); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci#else 11462306a36Sopenharmony_ci#define print_mlt(n, b, t) do {} while (0) 11562306a36Sopenharmony_ci#endif 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void print_ml(char *name, unsigned long b, unsigned long t) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci unsigned long diff = t - b; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT) && (diff >> LOG2_SZ_1T) >= 10) 12262306a36Sopenharmony_ci print_mlt(name, b, t); 12362306a36Sopenharmony_ci else if ((diff >> LOG2_SZ_1G) >= 10) 12462306a36Sopenharmony_ci print_mlg(name, b, t); 12562306a36Sopenharmony_ci else if ((diff >> LOG2_SZ_1M) >= 10) 12662306a36Sopenharmony_ci print_mlm(name, b, t); 12762306a36Sopenharmony_ci else 12862306a36Sopenharmony_ci print_mlk(name, b, t); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void __init print_vm_layout(void) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci pr_notice("Virtual kernel memory layout:\n"); 13462306a36Sopenharmony_ci print_ml("fixmap", (unsigned long)FIXADDR_START, 13562306a36Sopenharmony_ci (unsigned long)FIXADDR_TOP); 13662306a36Sopenharmony_ci print_ml("pci io", (unsigned long)PCI_IO_START, 13762306a36Sopenharmony_ci (unsigned long)PCI_IO_END); 13862306a36Sopenharmony_ci print_ml("vmemmap", (unsigned long)VMEMMAP_START, 13962306a36Sopenharmony_ci (unsigned long)VMEMMAP_END); 14062306a36Sopenharmony_ci print_ml("vmalloc", (unsigned long)VMALLOC_START, 14162306a36Sopenharmony_ci (unsigned long)VMALLOC_END); 14262306a36Sopenharmony_ci#ifdef CONFIG_64BIT 14362306a36Sopenharmony_ci print_ml("modules", (unsigned long)MODULES_VADDR, 14462306a36Sopenharmony_ci (unsigned long)MODULES_END); 14562306a36Sopenharmony_ci#endif 14662306a36Sopenharmony_ci print_ml("lowmem", (unsigned long)PAGE_OFFSET, 14762306a36Sopenharmony_ci (unsigned long)high_memory); 14862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) { 14962306a36Sopenharmony_ci#ifdef CONFIG_KASAN 15062306a36Sopenharmony_ci print_ml("kasan", KASAN_SHADOW_START, KASAN_SHADOW_END); 15162306a36Sopenharmony_ci#endif 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci print_ml("kernel", (unsigned long)kernel_map.virt_addr, 15462306a36Sopenharmony_ci (unsigned long)ADDRESS_SPACE_END); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci#else 15862306a36Sopenharmony_cistatic void print_vm_layout(void) { } 15962306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_VM */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_civoid __init mem_init(void) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci#ifdef CONFIG_FLATMEM 16462306a36Sopenharmony_ci BUG_ON(!mem_map); 16562306a36Sopenharmony_ci#endif /* CONFIG_FLATMEM */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci swiotlb_init(max_pfn > PFN_DOWN(dma32_phys_limit), SWIOTLB_VERBOSE); 16862306a36Sopenharmony_ci memblock_free_all(); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci print_vm_layout(); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Limit the memory size via mem. */ 17462306a36Sopenharmony_cistatic phys_addr_t memory_limit; 17562306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 17662306a36Sopenharmony_ci#define memory_limit (*(phys_addr_t *)XIP_FIXUP(&memory_limit)) 17762306a36Sopenharmony_ci#endif /* CONFIG_XIP_KERNEL */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int __init early_mem(char *p) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci u64 size; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!p) 18462306a36Sopenharmony_ci return 1; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci size = memparse(p, &p) & PAGE_MASK; 18762306a36Sopenharmony_ci memory_limit = min_t(u64, size, memory_limit); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci pr_notice("Memory limited to %lldMB\n", (u64)memory_limit >> 20); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ciearly_param("mem", early_mem); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic void __init setup_bootmem(void) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci phys_addr_t vmlinux_end = __pa_symbol(&_end); 19862306a36Sopenharmony_ci phys_addr_t max_mapped_addr; 19962306a36Sopenharmony_ci phys_addr_t phys_ram_end, vmlinux_start; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_XIP_KERNEL)) 20262306a36Sopenharmony_ci vmlinux_start = __pa_symbol(&_sdata); 20362306a36Sopenharmony_ci else 20462306a36Sopenharmony_ci vmlinux_start = __pa_symbol(&_start); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci memblock_enforce_memory_limit(memory_limit); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * Make sure we align the reservation on PMD_SIZE since we will 21062306a36Sopenharmony_ci * map the kernel in the linear mapping as read-only: we do not want 21162306a36Sopenharmony_ci * any allocation to happen between _end and the next pmd aligned page. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) 21462306a36Sopenharmony_ci vmlinux_end = (vmlinux_end + PMD_SIZE - 1) & PMD_MASK; 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * Reserve from the start of the kernel to the end of the kernel 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci phys_ram_end = memblock_end_of_DRAM(); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * Make sure we align the start of the memory on a PMD boundary so that 22462306a36Sopenharmony_ci * at worst, we map the linear mapping with PMD mappings. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_XIP_KERNEL)) 22762306a36Sopenharmony_ci phys_ram_base = memblock_start_of_DRAM() & PMD_MASK; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * In 64-bit, any use of __va/__pa before this point is wrong as we 23162306a36Sopenharmony_ci * did not know the start of DRAM before. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 23462306a36Sopenharmony_ci kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* 23762306a36Sopenharmony_ci * memblock allocator is not aware of the fact that last 4K bytes of 23862306a36Sopenharmony_ci * the addressable memory can not be mapped because of IS_ERR_VALUE 23962306a36Sopenharmony_ci * macro. Make sure that last 4k bytes are not usable by memblock 24062306a36Sopenharmony_ci * if end of dram is equal to maximum addressable memory. For 64-bit 24162306a36Sopenharmony_ci * kernel, this problem can't happen here as the end of the virtual 24262306a36Sopenharmony_ci * address space is occupied by the kernel mapping then this check must 24362306a36Sopenharmony_ci * be done as soon as the kernel mapping base address is determined. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_64BIT)) { 24662306a36Sopenharmony_ci max_mapped_addr = __pa(~(ulong)0); 24762306a36Sopenharmony_ci if (max_mapped_addr == (phys_ram_end - 1)) 24862306a36Sopenharmony_ci memblock_set_current_limit(max_mapped_addr - 4096); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci min_low_pfn = PFN_UP(phys_ram_base); 25262306a36Sopenharmony_ci max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end); 25362306a36Sopenharmony_ci high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn)); 25662306a36Sopenharmony_ci set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci reserve_initrd_mem(); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * No allocation should be done before reserving the memory as defined 26262306a36Sopenharmony_ci * in the device tree, otherwise the allocation could end up in a 26362306a36Sopenharmony_ci * reserved region. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci early_init_fdt_scan_reserved_mem(); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * If DTB is built in, no need to reserve its memblock. 26962306a36Sopenharmony_ci * Otherwise, do reserve it but avoid using 27062306a36Sopenharmony_ci * early_init_fdt_reserve_self() since __pa() does 27162306a36Sopenharmony_ci * not work for DTB pointers that are fixmap addresses 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_BUILTIN_DTB)) 27462306a36Sopenharmony_ci memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va)); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dma_contiguous_reserve(dma32_phys_limit); 27762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 27862306a36Sopenharmony_ci hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#ifdef CONFIG_MMU 28262306a36Sopenharmony_cistruct pt_alloc_ops pt_ops __initdata; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cipgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; 28562306a36Sopenharmony_cipgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; 28662306a36Sopenharmony_cistatic pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cipgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 29162306a36Sopenharmony_ci#define pt_ops (*(struct pt_alloc_ops *)XIP_FIXUP(&pt_ops)) 29262306a36Sopenharmony_ci#define trampoline_pg_dir ((pgd_t *)XIP_FIXUP(trampoline_pg_dir)) 29362306a36Sopenharmony_ci#define fixmap_pte ((pte_t *)XIP_FIXUP(fixmap_pte)) 29462306a36Sopenharmony_ci#define early_pg_dir ((pgd_t *)XIP_FIXUP(early_pg_dir)) 29562306a36Sopenharmony_ci#endif /* CONFIG_XIP_KERNEL */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic const pgprot_t protection_map[16] = { 29862306a36Sopenharmony_ci [VM_NONE] = PAGE_NONE, 29962306a36Sopenharmony_ci [VM_READ] = PAGE_READ, 30062306a36Sopenharmony_ci [VM_WRITE] = PAGE_COPY, 30162306a36Sopenharmony_ci [VM_WRITE | VM_READ] = PAGE_COPY, 30262306a36Sopenharmony_ci [VM_EXEC] = PAGE_EXEC, 30362306a36Sopenharmony_ci [VM_EXEC | VM_READ] = PAGE_READ_EXEC, 30462306a36Sopenharmony_ci [VM_EXEC | VM_WRITE] = PAGE_COPY_EXEC, 30562306a36Sopenharmony_ci [VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY_EXEC, 30662306a36Sopenharmony_ci [VM_SHARED] = PAGE_NONE, 30762306a36Sopenharmony_ci [VM_SHARED | VM_READ] = PAGE_READ, 30862306a36Sopenharmony_ci [VM_SHARED | VM_WRITE] = PAGE_SHARED, 30962306a36Sopenharmony_ci [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED, 31062306a36Sopenharmony_ci [VM_SHARED | VM_EXEC] = PAGE_EXEC, 31162306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READ_EXEC, 31262306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED_EXEC, 31362306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED_EXEC 31462306a36Sopenharmony_ci}; 31562306a36Sopenharmony_ciDECLARE_VM_GET_PAGE_PROT 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned long addr = __fix_to_virt(idx); 32062306a36Sopenharmony_ci pte_t *ptep; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ptep = &fixmap_pte[pte_index(addr)]; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (pgprot_val(prot)) 32762306a36Sopenharmony_ci set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci pte_clear(&init_mm, addr, ptep); 33062306a36Sopenharmony_ci local_flush_tlb_page(addr); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic inline pte_t *__init get_pte_virt_early(phys_addr_t pa) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci return (pte_t *)((uintptr_t)pa); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic inline pte_t *__init get_pte_virt_fixmap(phys_addr_t pa) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci clear_fixmap(FIX_PTE); 34162306a36Sopenharmony_ci return (pte_t *)set_fixmap_offset(FIX_PTE, pa); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic inline pte_t *__init get_pte_virt_late(phys_addr_t pa) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return (pte_t *) __va(pa); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic inline phys_addr_t __init alloc_pte_early(uintptr_t va) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * We only create PMD or PGD early mappings so we 35362306a36Sopenharmony_ci * should never reach here with MMU disabled. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci BUG(); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic inline phys_addr_t __init alloc_pte_fixmap(uintptr_t va) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic phys_addr_t __init alloc_pte_late(uintptr_t va) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL & ~__GFP_HIGHMEM, 0); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci BUG_ON(!ptdesc || !pagetable_pte_ctor(ptdesc)); 36862306a36Sopenharmony_ci return __pa((pte_t *)ptdesc_address(ptdesc)); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void __init create_pte_mapping(pte_t *ptep, 37262306a36Sopenharmony_ci uintptr_t va, phys_addr_t pa, 37362306a36Sopenharmony_ci phys_addr_t sz, pgprot_t prot) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci uintptr_t pte_idx = pte_index(va); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci BUG_ON(sz != PAGE_SIZE); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (pte_none(ptep[pte_idx])) 38062306a36Sopenharmony_ci ptep[pte_idx] = pfn_pte(PFN_DOWN(pa), prot); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss; 38662306a36Sopenharmony_cistatic pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss; 38762306a36Sopenharmony_cistatic pmd_t early_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 39062306a36Sopenharmony_ci#define trampoline_pmd ((pmd_t *)XIP_FIXUP(trampoline_pmd)) 39162306a36Sopenharmony_ci#define fixmap_pmd ((pmd_t *)XIP_FIXUP(fixmap_pmd)) 39262306a36Sopenharmony_ci#define early_pmd ((pmd_t *)XIP_FIXUP(early_pmd)) 39362306a36Sopenharmony_ci#endif /* CONFIG_XIP_KERNEL */ 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic p4d_t trampoline_p4d[PTRS_PER_P4D] __page_aligned_bss; 39662306a36Sopenharmony_cistatic p4d_t fixmap_p4d[PTRS_PER_P4D] __page_aligned_bss; 39762306a36Sopenharmony_cistatic p4d_t early_p4d[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 40062306a36Sopenharmony_ci#define trampoline_p4d ((p4d_t *)XIP_FIXUP(trampoline_p4d)) 40162306a36Sopenharmony_ci#define fixmap_p4d ((p4d_t *)XIP_FIXUP(fixmap_p4d)) 40262306a36Sopenharmony_ci#define early_p4d ((p4d_t *)XIP_FIXUP(early_p4d)) 40362306a36Sopenharmony_ci#endif /* CONFIG_XIP_KERNEL */ 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic pud_t trampoline_pud[PTRS_PER_PUD] __page_aligned_bss; 40662306a36Sopenharmony_cistatic pud_t fixmap_pud[PTRS_PER_PUD] __page_aligned_bss; 40762306a36Sopenharmony_cistatic pud_t early_pud[PTRS_PER_PUD] __initdata __aligned(PAGE_SIZE); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 41062306a36Sopenharmony_ci#define trampoline_pud ((pud_t *)XIP_FIXUP(trampoline_pud)) 41162306a36Sopenharmony_ci#define fixmap_pud ((pud_t *)XIP_FIXUP(fixmap_pud)) 41262306a36Sopenharmony_ci#define early_pud ((pud_t *)XIP_FIXUP(early_pud)) 41362306a36Sopenharmony_ci#endif /* CONFIG_XIP_KERNEL */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic pmd_t *__init get_pmd_virt_early(phys_addr_t pa) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci /* Before MMU is enabled */ 41862306a36Sopenharmony_ci return (pmd_t *)((uintptr_t)pa); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic pmd_t *__init get_pmd_virt_fixmap(phys_addr_t pa) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci clear_fixmap(FIX_PMD); 42462306a36Sopenharmony_ci return (pmd_t *)set_fixmap_offset(FIX_PMD, pa); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic pmd_t *__init get_pmd_virt_late(phys_addr_t pa) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci return (pmd_t *) __va(pa); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic phys_addr_t __init alloc_pmd_early(uintptr_t va) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci BUG_ON((va - kernel_map.virt_addr) >> PUD_SHIFT); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return (uintptr_t)early_pmd; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic phys_addr_t __init alloc_pmd_fixmap(uintptr_t va) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic phys_addr_t __init alloc_pmd_late(uintptr_t va) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL & ~__GFP_HIGHMEM, 0); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci BUG_ON(!ptdesc || !pagetable_pmd_ctor(ptdesc)); 44962306a36Sopenharmony_ci return __pa((pmd_t *)ptdesc_address(ptdesc)); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void __init create_pmd_mapping(pmd_t *pmdp, 45362306a36Sopenharmony_ci uintptr_t va, phys_addr_t pa, 45462306a36Sopenharmony_ci phys_addr_t sz, pgprot_t prot) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci pte_t *ptep; 45762306a36Sopenharmony_ci phys_addr_t pte_phys; 45862306a36Sopenharmony_ci uintptr_t pmd_idx = pmd_index(va); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (sz == PMD_SIZE) { 46162306a36Sopenharmony_ci if (pmd_none(pmdp[pmd_idx])) 46262306a36Sopenharmony_ci pmdp[pmd_idx] = pfn_pmd(PFN_DOWN(pa), prot); 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (pmd_none(pmdp[pmd_idx])) { 46762306a36Sopenharmony_ci pte_phys = pt_ops.alloc_pte(va); 46862306a36Sopenharmony_ci pmdp[pmd_idx] = pfn_pmd(PFN_DOWN(pte_phys), PAGE_TABLE); 46962306a36Sopenharmony_ci ptep = pt_ops.get_pte_virt(pte_phys); 47062306a36Sopenharmony_ci memset(ptep, 0, PAGE_SIZE); 47162306a36Sopenharmony_ci } else { 47262306a36Sopenharmony_ci pte_phys = PFN_PHYS(_pmd_pfn(pmdp[pmd_idx])); 47362306a36Sopenharmony_ci ptep = pt_ops.get_pte_virt(pte_phys); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci create_pte_mapping(ptep, va, pa, sz, prot); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic pud_t *__init get_pud_virt_early(phys_addr_t pa) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci return (pud_t *)((uintptr_t)pa); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic pud_t *__init get_pud_virt_fixmap(phys_addr_t pa) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci clear_fixmap(FIX_PUD); 48762306a36Sopenharmony_ci return (pud_t *)set_fixmap_offset(FIX_PUD, pa); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic pud_t *__init get_pud_virt_late(phys_addr_t pa) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci return (pud_t *)__va(pa); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic phys_addr_t __init alloc_pud_early(uintptr_t va) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci /* Only one PUD is available for early mapping */ 49862306a36Sopenharmony_ci BUG_ON((va - kernel_map.virt_addr) >> PGDIR_SHIFT); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return (uintptr_t)early_pud; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic phys_addr_t __init alloc_pud_fixmap(uintptr_t va) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic phys_addr_t alloc_pud_late(uintptr_t va) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci unsigned long vaddr; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci vaddr = __get_free_page(GFP_KERNEL); 51362306a36Sopenharmony_ci BUG_ON(!vaddr); 51462306a36Sopenharmony_ci return __pa(vaddr); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic p4d_t *__init get_p4d_virt_early(phys_addr_t pa) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci return (p4d_t *)((uintptr_t)pa); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic p4d_t *__init get_p4d_virt_fixmap(phys_addr_t pa) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci clear_fixmap(FIX_P4D); 52562306a36Sopenharmony_ci return (p4d_t *)set_fixmap_offset(FIX_P4D, pa); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic p4d_t *__init get_p4d_virt_late(phys_addr_t pa) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci return (p4d_t *)__va(pa); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic phys_addr_t __init alloc_p4d_early(uintptr_t va) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci /* Only one P4D is available for early mapping */ 53662306a36Sopenharmony_ci BUG_ON((va - kernel_map.virt_addr) >> PGDIR_SHIFT); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return (uintptr_t)early_p4d; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic phys_addr_t __init alloc_p4d_fixmap(uintptr_t va) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic phys_addr_t alloc_p4d_late(uintptr_t va) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci unsigned long vaddr; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci vaddr = __get_free_page(GFP_KERNEL); 55162306a36Sopenharmony_ci BUG_ON(!vaddr); 55262306a36Sopenharmony_ci return __pa(vaddr); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void __init create_pud_mapping(pud_t *pudp, 55662306a36Sopenharmony_ci uintptr_t va, phys_addr_t pa, 55762306a36Sopenharmony_ci phys_addr_t sz, pgprot_t prot) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci pmd_t *nextp; 56062306a36Sopenharmony_ci phys_addr_t next_phys; 56162306a36Sopenharmony_ci uintptr_t pud_index = pud_index(va); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (sz == PUD_SIZE) { 56462306a36Sopenharmony_ci if (pud_val(pudp[pud_index]) == 0) 56562306a36Sopenharmony_ci pudp[pud_index] = pfn_pud(PFN_DOWN(pa), prot); 56662306a36Sopenharmony_ci return; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (pud_val(pudp[pud_index]) == 0) { 57062306a36Sopenharmony_ci next_phys = pt_ops.alloc_pmd(va); 57162306a36Sopenharmony_ci pudp[pud_index] = pfn_pud(PFN_DOWN(next_phys), PAGE_TABLE); 57262306a36Sopenharmony_ci nextp = pt_ops.get_pmd_virt(next_phys); 57362306a36Sopenharmony_ci memset(nextp, 0, PAGE_SIZE); 57462306a36Sopenharmony_ci } else { 57562306a36Sopenharmony_ci next_phys = PFN_PHYS(_pud_pfn(pudp[pud_index])); 57662306a36Sopenharmony_ci nextp = pt_ops.get_pmd_virt(next_phys); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci create_pmd_mapping(nextp, va, pa, sz, prot); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void __init create_p4d_mapping(p4d_t *p4dp, 58362306a36Sopenharmony_ci uintptr_t va, phys_addr_t pa, 58462306a36Sopenharmony_ci phys_addr_t sz, pgprot_t prot) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci pud_t *nextp; 58762306a36Sopenharmony_ci phys_addr_t next_phys; 58862306a36Sopenharmony_ci uintptr_t p4d_index = p4d_index(va); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (sz == P4D_SIZE) { 59162306a36Sopenharmony_ci if (p4d_val(p4dp[p4d_index]) == 0) 59262306a36Sopenharmony_ci p4dp[p4d_index] = pfn_p4d(PFN_DOWN(pa), prot); 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (p4d_val(p4dp[p4d_index]) == 0) { 59762306a36Sopenharmony_ci next_phys = pt_ops.alloc_pud(va); 59862306a36Sopenharmony_ci p4dp[p4d_index] = pfn_p4d(PFN_DOWN(next_phys), PAGE_TABLE); 59962306a36Sopenharmony_ci nextp = pt_ops.get_pud_virt(next_phys); 60062306a36Sopenharmony_ci memset(nextp, 0, PAGE_SIZE); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci next_phys = PFN_PHYS(_p4d_pfn(p4dp[p4d_index])); 60362306a36Sopenharmony_ci nextp = pt_ops.get_pud_virt(next_phys); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci create_pud_mapping(nextp, va, pa, sz, prot); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci#define pgd_next_t p4d_t 61062306a36Sopenharmony_ci#define alloc_pgd_next(__va) (pgtable_l5_enabled ? \ 61162306a36Sopenharmony_ci pt_ops.alloc_p4d(__va) : (pgtable_l4_enabled ? \ 61262306a36Sopenharmony_ci pt_ops.alloc_pud(__va) : pt_ops.alloc_pmd(__va))) 61362306a36Sopenharmony_ci#define get_pgd_next_virt(__pa) (pgtable_l5_enabled ? \ 61462306a36Sopenharmony_ci pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(pgtable_l4_enabled ? \ 61562306a36Sopenharmony_ci pt_ops.get_pud_virt(__pa) : (pud_t *)pt_ops.get_pmd_virt(__pa))) 61662306a36Sopenharmony_ci#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot) \ 61762306a36Sopenharmony_ci (pgtable_l5_enabled ? \ 61862306a36Sopenharmony_ci create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \ 61962306a36Sopenharmony_ci (pgtable_l4_enabled ? \ 62062306a36Sopenharmony_ci create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) : \ 62162306a36Sopenharmony_ci create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot))) 62262306a36Sopenharmony_ci#define fixmap_pgd_next (pgtable_l5_enabled ? \ 62362306a36Sopenharmony_ci (uintptr_t)fixmap_p4d : (pgtable_l4_enabled ? \ 62462306a36Sopenharmony_ci (uintptr_t)fixmap_pud : (uintptr_t)fixmap_pmd)) 62562306a36Sopenharmony_ci#define trampoline_pgd_next (pgtable_l5_enabled ? \ 62662306a36Sopenharmony_ci (uintptr_t)trampoline_p4d : (pgtable_l4_enabled ? \ 62762306a36Sopenharmony_ci (uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd)) 62862306a36Sopenharmony_ci#else 62962306a36Sopenharmony_ci#define pgd_next_t pte_t 63062306a36Sopenharmony_ci#define alloc_pgd_next(__va) pt_ops.alloc_pte(__va) 63162306a36Sopenharmony_ci#define get_pgd_next_virt(__pa) pt_ops.get_pte_virt(__pa) 63262306a36Sopenharmony_ci#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot) \ 63362306a36Sopenharmony_ci create_pte_mapping(__nextp, __va, __pa, __sz, __prot) 63462306a36Sopenharmony_ci#define fixmap_pgd_next ((uintptr_t)fixmap_pte) 63562306a36Sopenharmony_ci#define create_p4d_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0) 63662306a36Sopenharmony_ci#define create_pud_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0) 63762306a36Sopenharmony_ci#define create_pmd_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0) 63862306a36Sopenharmony_ci#endif /* __PAGETABLE_PMD_FOLDED */ 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_civoid __init create_pgd_mapping(pgd_t *pgdp, 64162306a36Sopenharmony_ci uintptr_t va, phys_addr_t pa, 64262306a36Sopenharmony_ci phys_addr_t sz, pgprot_t prot) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci pgd_next_t *nextp; 64562306a36Sopenharmony_ci phys_addr_t next_phys; 64662306a36Sopenharmony_ci uintptr_t pgd_idx = pgd_index(va); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (sz == PGDIR_SIZE) { 64962306a36Sopenharmony_ci if (pgd_val(pgdp[pgd_idx]) == 0) 65062306a36Sopenharmony_ci pgdp[pgd_idx] = pfn_pgd(PFN_DOWN(pa), prot); 65162306a36Sopenharmony_ci return; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (pgd_val(pgdp[pgd_idx]) == 0) { 65562306a36Sopenharmony_ci next_phys = alloc_pgd_next(va); 65662306a36Sopenharmony_ci pgdp[pgd_idx] = pfn_pgd(PFN_DOWN(next_phys), PAGE_TABLE); 65762306a36Sopenharmony_ci nextp = get_pgd_next_virt(next_phys); 65862306a36Sopenharmony_ci memset(nextp, 0, PAGE_SIZE); 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci next_phys = PFN_PHYS(_pgd_pfn(pgdp[pgd_idx])); 66162306a36Sopenharmony_ci nextp = get_pgd_next_virt(next_phys); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci create_pgd_next_mapping(nextp, va, pa, sz, prot); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va, 66862306a36Sopenharmony_ci phys_addr_t size) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci if (!(pa & (PGDIR_SIZE - 1)) && !(va & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE) 67162306a36Sopenharmony_ci return PGDIR_SIZE; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE) 67462306a36Sopenharmony_ci return P4D_SIZE; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (!(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE) 67762306a36Sopenharmony_ci return PUD_SIZE; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (!(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE) 68062306a36Sopenharmony_ci return PMD_SIZE; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return PAGE_SIZE; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 68662306a36Sopenharmony_ci#define phys_ram_base (*(phys_addr_t *)XIP_FIXUP(&phys_ram_base)) 68762306a36Sopenharmony_ciextern char _xiprom[], _exiprom[], __data_loc; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/* called from head.S with MMU off */ 69062306a36Sopenharmony_ciasmlinkage void __init __copy_data(void) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci void *from = (void *)(&__data_loc); 69362306a36Sopenharmony_ci void *to = (void *)CONFIG_PHYS_RAM_BASE; 69462306a36Sopenharmony_ci size_t sz = (size_t)((uintptr_t)(&_end) - (uintptr_t)(&_sdata)); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci memcpy(to, from, sz); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci#endif 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci#ifdef CONFIG_STRICT_KERNEL_RWX 70162306a36Sopenharmony_cistatic __init pgprot_t pgprot_from_va(uintptr_t va) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci if (is_va_kernel_text(va)) 70462306a36Sopenharmony_ci return PAGE_KERNEL_READ_EXEC; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* 70762306a36Sopenharmony_ci * In 64-bit kernel, the kernel mapping is outside the linear mapping so 70862306a36Sopenharmony_ci * we must protect its linear mapping alias from being executed and 70962306a36Sopenharmony_ci * written. 71062306a36Sopenharmony_ci * And rodata section is marked readonly in mark_rodata_ro. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT) && is_va_kernel_lm_alias_text(va)) 71362306a36Sopenharmony_ci return PAGE_KERNEL_READ; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci return PAGE_KERNEL; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_civoid mark_rodata_ro(void) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci set_kernel_memory(__start_rodata, _data, set_memory_ro); 72162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 72262306a36Sopenharmony_ci set_kernel_memory(lm_alias(__start_rodata), lm_alias(_data), 72362306a36Sopenharmony_ci set_memory_ro); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci debug_checkwx(); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci#else 72862306a36Sopenharmony_cistatic __init pgprot_t pgprot_from_va(uintptr_t va) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT) && !is_kernel_mapping(va)) 73162306a36Sopenharmony_ci return PAGE_KERNEL; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return PAGE_KERNEL_EXEC; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci#endif /* CONFIG_STRICT_KERNEL_RWX */ 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci#if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL) 73862306a36Sopenharmony_ciu64 __pi_set_satp_mode_from_cmdline(uintptr_t dtb_pa); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic void __init disable_pgtable_l5(void) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci pgtable_l5_enabled = false; 74362306a36Sopenharmony_ci kernel_map.page_offset = PAGE_OFFSET_L4; 74462306a36Sopenharmony_ci satp_mode = SATP_MODE_48; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic void __init disable_pgtable_l4(void) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci pgtable_l4_enabled = false; 75062306a36Sopenharmony_ci kernel_map.page_offset = PAGE_OFFSET_L3; 75162306a36Sopenharmony_ci satp_mode = SATP_MODE_39; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int __init print_no4lvl(char *p) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci pr_info("Disabled 4-level and 5-level paging"); 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ciearly_param("no4lvl", print_no4lvl); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int __init print_no5lvl(char *p) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci pr_info("Disabled 5-level paging"); 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ciearly_param("no5lvl", print_no5lvl); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* 76962306a36Sopenharmony_ci * There is a simple way to determine if 4-level is supported by the 77062306a36Sopenharmony_ci * underlying hardware: establish 1:1 mapping in 4-level page table mode 77162306a36Sopenharmony_ci * then read SATP to see if the configuration was taken into account 77262306a36Sopenharmony_ci * meaning sv48 is supported. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_cistatic __init void set_satp_mode(uintptr_t dtb_pa) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u64 identity_satp, hw_satp; 77762306a36Sopenharmony_ci uintptr_t set_satp_mode_pmd = ((unsigned long)set_satp_mode) & PMD_MASK; 77862306a36Sopenharmony_ci u64 satp_mode_cmdline = __pi_set_satp_mode_from_cmdline(dtb_pa); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (satp_mode_cmdline == SATP_MODE_57) { 78162306a36Sopenharmony_ci disable_pgtable_l5(); 78262306a36Sopenharmony_ci } else if (satp_mode_cmdline == SATP_MODE_48) { 78362306a36Sopenharmony_ci disable_pgtable_l5(); 78462306a36Sopenharmony_ci disable_pgtable_l4(); 78562306a36Sopenharmony_ci return; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci create_p4d_mapping(early_p4d, 78962306a36Sopenharmony_ci set_satp_mode_pmd, (uintptr_t)early_pud, 79062306a36Sopenharmony_ci P4D_SIZE, PAGE_TABLE); 79162306a36Sopenharmony_ci create_pud_mapping(early_pud, 79262306a36Sopenharmony_ci set_satp_mode_pmd, (uintptr_t)early_pmd, 79362306a36Sopenharmony_ci PUD_SIZE, PAGE_TABLE); 79462306a36Sopenharmony_ci /* Handle the case where set_satp_mode straddles 2 PMDs */ 79562306a36Sopenharmony_ci create_pmd_mapping(early_pmd, 79662306a36Sopenharmony_ci set_satp_mode_pmd, set_satp_mode_pmd, 79762306a36Sopenharmony_ci PMD_SIZE, PAGE_KERNEL_EXEC); 79862306a36Sopenharmony_ci create_pmd_mapping(early_pmd, 79962306a36Sopenharmony_ci set_satp_mode_pmd + PMD_SIZE, 80062306a36Sopenharmony_ci set_satp_mode_pmd + PMD_SIZE, 80162306a36Sopenharmony_ci PMD_SIZE, PAGE_KERNEL_EXEC); 80262306a36Sopenharmony_ciretry: 80362306a36Sopenharmony_ci create_pgd_mapping(early_pg_dir, 80462306a36Sopenharmony_ci set_satp_mode_pmd, 80562306a36Sopenharmony_ci pgtable_l5_enabled ? 80662306a36Sopenharmony_ci (uintptr_t)early_p4d : (uintptr_t)early_pud, 80762306a36Sopenharmony_ci PGDIR_SIZE, PAGE_TABLE); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci identity_satp = PFN_DOWN((uintptr_t)&early_pg_dir) | satp_mode; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci local_flush_tlb_all(); 81262306a36Sopenharmony_ci csr_write(CSR_SATP, identity_satp); 81362306a36Sopenharmony_ci hw_satp = csr_swap(CSR_SATP, 0ULL); 81462306a36Sopenharmony_ci local_flush_tlb_all(); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (hw_satp != identity_satp) { 81762306a36Sopenharmony_ci if (pgtable_l5_enabled) { 81862306a36Sopenharmony_ci disable_pgtable_l5(); 81962306a36Sopenharmony_ci memset(early_pg_dir, 0, PAGE_SIZE); 82062306a36Sopenharmony_ci goto retry; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci disable_pgtable_l4(); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci memset(early_pg_dir, 0, PAGE_SIZE); 82662306a36Sopenharmony_ci memset(early_p4d, 0, PAGE_SIZE); 82762306a36Sopenharmony_ci memset(early_pud, 0, PAGE_SIZE); 82862306a36Sopenharmony_ci memset(early_pmd, 0, PAGE_SIZE); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci#endif 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci/* 83362306a36Sopenharmony_ci * setup_vm() is called from head.S with MMU-off. 83462306a36Sopenharmony_ci * 83562306a36Sopenharmony_ci * Following requirements should be honoured for setup_vm() to work 83662306a36Sopenharmony_ci * correctly: 83762306a36Sopenharmony_ci * 1) It should use PC-relative addressing for accessing kernel symbols. 83862306a36Sopenharmony_ci * To achieve this we always use GCC cmodel=medany. 83962306a36Sopenharmony_ci * 2) The compiler instrumentation for FTRACE will not work for setup_vm() 84062306a36Sopenharmony_ci * so disable compiler instrumentation when FTRACE is enabled. 84162306a36Sopenharmony_ci * 84262306a36Sopenharmony_ci * Currently, the above requirements are honoured by using custom CFLAGS 84362306a36Sopenharmony_ci * for init.o in mm/Makefile. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci#ifndef __riscv_cmodel_medany 84762306a36Sopenharmony_ci#error "setup_vm() is called from head.S before relocate so it should not use absolute addressing." 84862306a36Sopenharmony_ci#endif 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci#ifdef CONFIG_RELOCATABLE 85162306a36Sopenharmony_ciextern unsigned long __rela_dyn_start, __rela_dyn_end; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic void __init relocate_kernel(void) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci Elf64_Rela *rela = (Elf64_Rela *)&__rela_dyn_start; 85662306a36Sopenharmony_ci /* 85762306a36Sopenharmony_ci * This holds the offset between the linked virtual address and the 85862306a36Sopenharmony_ci * relocated virtual address. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ci uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR; 86162306a36Sopenharmony_ci /* 86262306a36Sopenharmony_ci * This holds the offset between kernel linked virtual address and 86362306a36Sopenharmony_ci * physical address. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci for ( ; rela < (Elf64_Rela *)&__rela_dyn_end; rela++) { 86862306a36Sopenharmony_ci Elf64_Addr addr = (rela->r_offset - va_kernel_link_pa_offset); 86962306a36Sopenharmony_ci Elf64_Addr relocated_addr = rela->r_addend; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (rela->r_info != R_RISCV_RELATIVE) 87262306a36Sopenharmony_ci continue; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* 87562306a36Sopenharmony_ci * Make sure to not relocate vdso symbols like rt_sigreturn 87662306a36Sopenharmony_ci * which are linked from the address 0 in vmlinux since 87762306a36Sopenharmony_ci * vdso symbol addresses are actually used as an offset from 87862306a36Sopenharmony_ci * mm->context.vdso in VDSO_OFFSET macro. 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_ci if (relocated_addr >= KERNEL_LINK_ADDR) 88162306a36Sopenharmony_ci relocated_addr += reloc_offset; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci *(Elf64_Addr *)addr = relocated_addr; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci#endif /* CONFIG_RELOCATABLE */ 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 88962306a36Sopenharmony_cistatic void __init create_kernel_page_table(pgd_t *pgdir, 89062306a36Sopenharmony_ci __always_unused bool early) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci uintptr_t va, end_va; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* Map the flash resident part */ 89562306a36Sopenharmony_ci end_va = kernel_map.virt_addr + kernel_map.xiprom_sz; 89662306a36Sopenharmony_ci for (va = kernel_map.virt_addr; va < end_va; va += PMD_SIZE) 89762306a36Sopenharmony_ci create_pgd_mapping(pgdir, va, 89862306a36Sopenharmony_ci kernel_map.xiprom + (va - kernel_map.virt_addr), 89962306a36Sopenharmony_ci PMD_SIZE, PAGE_KERNEL_EXEC); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* Map the data in RAM */ 90262306a36Sopenharmony_ci end_va = kernel_map.virt_addr + XIP_OFFSET + kernel_map.size; 90362306a36Sopenharmony_ci for (va = kernel_map.virt_addr + XIP_OFFSET; va < end_va; va += PMD_SIZE) 90462306a36Sopenharmony_ci create_pgd_mapping(pgdir, va, 90562306a36Sopenharmony_ci kernel_map.phys_addr + (va - (kernel_map.virt_addr + XIP_OFFSET)), 90662306a36Sopenharmony_ci PMD_SIZE, PAGE_KERNEL); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci#else 90962306a36Sopenharmony_cistatic void __init create_kernel_page_table(pgd_t *pgdir, bool early) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci uintptr_t va, end_va; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci end_va = kernel_map.virt_addr + kernel_map.size; 91462306a36Sopenharmony_ci for (va = kernel_map.virt_addr; va < end_va; va += PMD_SIZE) 91562306a36Sopenharmony_ci create_pgd_mapping(pgdir, va, 91662306a36Sopenharmony_ci kernel_map.phys_addr + (va - kernel_map.virt_addr), 91762306a36Sopenharmony_ci PMD_SIZE, 91862306a36Sopenharmony_ci early ? 91962306a36Sopenharmony_ci PAGE_KERNEL_EXEC : pgprot_from_va(va)); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci#endif 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/* 92462306a36Sopenharmony_ci * Setup a 4MB mapping that encompasses the device tree: for 64-bit kernel, 92562306a36Sopenharmony_ci * this means 2 PMD entries whereas for 32-bit kernel, this is only 1 PGDIR 92662306a36Sopenharmony_ci * entry. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_cistatic void __init create_fdt_early_page_table(uintptr_t fix_fdt_va, 92962306a36Sopenharmony_ci uintptr_t dtb_pa) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci#ifndef CONFIG_BUILTIN_DTB 93262306a36Sopenharmony_ci uintptr_t pa = dtb_pa & ~(PMD_SIZE - 1); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* Make sure the fdt fixmap address is always aligned on PMD size */ 93562306a36Sopenharmony_ci BUILD_BUG_ON(FIX_FDT % (PMD_SIZE / PAGE_SIZE)); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* In 32-bit only, the fdt lies in its own PGD */ 93862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_64BIT)) { 93962306a36Sopenharmony_ci create_pgd_mapping(early_pg_dir, fix_fdt_va, 94062306a36Sopenharmony_ci pa, MAX_FDT_SIZE, PAGE_KERNEL); 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci create_pmd_mapping(fixmap_pmd, fix_fdt_va, 94362306a36Sopenharmony_ci pa, PMD_SIZE, PAGE_KERNEL); 94462306a36Sopenharmony_ci create_pmd_mapping(fixmap_pmd, fix_fdt_va + PMD_SIZE, 94562306a36Sopenharmony_ci pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci dtb_early_va = (void *)fix_fdt_va + (dtb_pa & (PMD_SIZE - 1)); 94962306a36Sopenharmony_ci#else 95062306a36Sopenharmony_ci /* 95162306a36Sopenharmony_ci * For 64-bit kernel, __va can't be used since it would return a linear 95262306a36Sopenharmony_ci * mapping address whereas dtb_early_va will be used before 95362306a36Sopenharmony_ci * setup_vm_final installs the linear mapping. For 32-bit kernel, as the 95462306a36Sopenharmony_ci * kernel is mapped in the linear mapping, that makes no difference. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci dtb_early_va = kernel_mapping_pa_to_va(dtb_pa); 95762306a36Sopenharmony_ci#endif 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci dtb_early_pa = dtb_pa; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/* 96362306a36Sopenharmony_ci * MMU is not enabled, the page tables are allocated directly using 96462306a36Sopenharmony_ci * early_pmd/pud/p4d and the address returned is the physical one. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_cistatic void __init pt_ops_set_early(void) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci pt_ops.alloc_pte = alloc_pte_early; 96962306a36Sopenharmony_ci pt_ops.get_pte_virt = get_pte_virt_early; 97062306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 97162306a36Sopenharmony_ci pt_ops.alloc_pmd = alloc_pmd_early; 97262306a36Sopenharmony_ci pt_ops.get_pmd_virt = get_pmd_virt_early; 97362306a36Sopenharmony_ci pt_ops.alloc_pud = alloc_pud_early; 97462306a36Sopenharmony_ci pt_ops.get_pud_virt = get_pud_virt_early; 97562306a36Sopenharmony_ci pt_ops.alloc_p4d = alloc_p4d_early; 97662306a36Sopenharmony_ci pt_ops.get_p4d_virt = get_p4d_virt_early; 97762306a36Sopenharmony_ci#endif 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci/* 98162306a36Sopenharmony_ci * MMU is enabled but page table setup is not complete yet. 98262306a36Sopenharmony_ci * fixmap page table alloc functions must be used as a means to temporarily 98362306a36Sopenharmony_ci * map the allocated physical pages since the linear mapping does not exist yet. 98462306a36Sopenharmony_ci * 98562306a36Sopenharmony_ci * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va, 98662306a36Sopenharmony_ci * but it will be used as described above. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_cistatic void __init pt_ops_set_fixmap(void) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci pt_ops.alloc_pte = kernel_mapping_pa_to_va(alloc_pte_fixmap); 99162306a36Sopenharmony_ci pt_ops.get_pte_virt = kernel_mapping_pa_to_va(get_pte_virt_fixmap); 99262306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 99362306a36Sopenharmony_ci pt_ops.alloc_pmd = kernel_mapping_pa_to_va(alloc_pmd_fixmap); 99462306a36Sopenharmony_ci pt_ops.get_pmd_virt = kernel_mapping_pa_to_va(get_pmd_virt_fixmap); 99562306a36Sopenharmony_ci pt_ops.alloc_pud = kernel_mapping_pa_to_va(alloc_pud_fixmap); 99662306a36Sopenharmony_ci pt_ops.get_pud_virt = kernel_mapping_pa_to_va(get_pud_virt_fixmap); 99762306a36Sopenharmony_ci pt_ops.alloc_p4d = kernel_mapping_pa_to_va(alloc_p4d_fixmap); 99862306a36Sopenharmony_ci pt_ops.get_p4d_virt = kernel_mapping_pa_to_va(get_p4d_virt_fixmap); 99962306a36Sopenharmony_ci#endif 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci/* 100362306a36Sopenharmony_ci * MMU is enabled and page table setup is complete, so from now, we can use 100462306a36Sopenharmony_ci * generic page allocation functions to setup page table. 100562306a36Sopenharmony_ci */ 100662306a36Sopenharmony_cistatic void __init pt_ops_set_late(void) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci pt_ops.alloc_pte = alloc_pte_late; 100962306a36Sopenharmony_ci pt_ops.get_pte_virt = get_pte_virt_late; 101062306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 101162306a36Sopenharmony_ci pt_ops.alloc_pmd = alloc_pmd_late; 101262306a36Sopenharmony_ci pt_ops.get_pmd_virt = get_pmd_virt_late; 101362306a36Sopenharmony_ci pt_ops.alloc_pud = alloc_pud_late; 101462306a36Sopenharmony_ci pt_ops.get_pud_virt = get_pud_virt_late; 101562306a36Sopenharmony_ci pt_ops.alloc_p4d = alloc_p4d_late; 101662306a36Sopenharmony_ci pt_ops.get_p4d_virt = get_p4d_virt_late; 101762306a36Sopenharmony_ci#endif 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci#ifdef CONFIG_RANDOMIZE_BASE 102162306a36Sopenharmony_ciextern bool __init __pi_set_nokaslr_from_cmdline(uintptr_t dtb_pa); 102262306a36Sopenharmony_ciextern u64 __init __pi_get_kaslr_seed(uintptr_t dtb_pa); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic int __init print_nokaslr(char *p) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci pr_info("Disabled KASLR"); 102762306a36Sopenharmony_ci return 0; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ciearly_param("nokaslr", print_nokaslr); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ciunsigned long kaslr_offset(void) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci return kernel_map.virt_offset; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci#endif 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ciasmlinkage void __init setup_vm(uintptr_t dtb_pa) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci pmd_t __maybe_unused fix_bmap_spmd, fix_bmap_epmd; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci#ifdef CONFIG_RANDOMIZE_BASE 104262306a36Sopenharmony_ci if (!__pi_set_nokaslr_from_cmdline(dtb_pa)) { 104362306a36Sopenharmony_ci u64 kaslr_seed = __pi_get_kaslr_seed(dtb_pa); 104462306a36Sopenharmony_ci u32 kernel_size = (uintptr_t)(&_end) - (uintptr_t)(&_start); 104562306a36Sopenharmony_ci u32 nr_pos; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* 104862306a36Sopenharmony_ci * Compute the number of positions available: we are limited 104962306a36Sopenharmony_ci * by the early page table that only has one PUD and we must 105062306a36Sopenharmony_ci * be aligned on PMD_SIZE. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci nr_pos = (PUD_SIZE - kernel_size) / PMD_SIZE; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci kernel_map.virt_offset = (kaslr_seed % nr_pos) * PMD_SIZE; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci#endif 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci kernel_map.virt_addr = KERNEL_LINK_ADDR + kernel_map.virt_offset; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 106162306a36Sopenharmony_ci#ifdef CONFIG_64BIT 106262306a36Sopenharmony_ci kernel_map.page_offset = PAGE_OFFSET_L3; 106362306a36Sopenharmony_ci#else 106462306a36Sopenharmony_ci kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); 106562306a36Sopenharmony_ci#endif 106662306a36Sopenharmony_ci kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR; 106762306a36Sopenharmony_ci kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci phys_ram_base = CONFIG_PHYS_RAM_BASE; 107062306a36Sopenharmony_ci kernel_map.phys_addr = (uintptr_t)CONFIG_PHYS_RAM_BASE; 107162306a36Sopenharmony_ci kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_sdata); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom; 107462306a36Sopenharmony_ci#else 107562306a36Sopenharmony_ci kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); 107662306a36Sopenharmony_ci kernel_map.phys_addr = (uintptr_t)(&_start); 107762306a36Sopenharmony_ci kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr; 107862306a36Sopenharmony_ci#endif 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci#if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL) 108162306a36Sopenharmony_ci set_satp_mode(dtb_pa); 108262306a36Sopenharmony_ci#endif 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci /* 108562306a36Sopenharmony_ci * In 64-bit, we defer the setup of va_pa_offset to setup_bootmem, 108662306a36Sopenharmony_ci * where we have the system memory layout: this allows us to align 108762306a36Sopenharmony_ci * the physical and virtual mappings and then make use of PUD/P4D/PGD 108862306a36Sopenharmony_ci * for the linear mapping. This is only possible because the kernel 108962306a36Sopenharmony_ci * mapping lies outside the linear mapping. 109062306a36Sopenharmony_ci * In 32-bit however, as the kernel resides in the linear mapping, 109162306a36Sopenharmony_ci * setup_vm_final can not change the mapping established here, 109262306a36Sopenharmony_ci * otherwise the same kernel addresses would get mapped to different 109362306a36Sopenharmony_ci * physical addresses (if the start of dram is different from the 109462306a36Sopenharmony_ci * kernel physical address start). 109562306a36Sopenharmony_ci */ 109662306a36Sopenharmony_ci kernel_map.va_pa_offset = IS_ENABLED(CONFIG_64BIT) ? 109762306a36Sopenharmony_ci 0UL : PAGE_OFFSET - kernel_map.phys_addr; 109862306a36Sopenharmony_ci kernel_map.va_kernel_pa_offset = kernel_map.virt_addr - kernel_map.phys_addr; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* 110162306a36Sopenharmony_ci * The default maximal physical memory size is KERN_VIRT_SIZE for 32-bit 110262306a36Sopenharmony_ci * kernel, whereas for 64-bit kernel, the end of the virtual address 110362306a36Sopenharmony_ci * space is occupied by the modules/BPF/kernel mappings which reduces 110462306a36Sopenharmony_ci * the available size of the linear mapping. 110562306a36Sopenharmony_ci */ 110662306a36Sopenharmony_ci memory_limit = KERN_VIRT_SIZE - (IS_ENABLED(CONFIG_64BIT) ? SZ_4G : 0); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* Sanity check alignment and size */ 110962306a36Sopenharmony_ci BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0); 111062306a36Sopenharmony_ci BUG_ON((kernel_map.phys_addr % PMD_SIZE) != 0); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci#ifdef CONFIG_64BIT 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * The last 4K bytes of the addressable memory can not be mapped because 111562306a36Sopenharmony_ci * of IS_ERR_VALUE macro. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci BUG_ON((kernel_map.virt_addr + kernel_map.size) > ADDRESS_SPACE_END - SZ_4K); 111862306a36Sopenharmony_ci#endif 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci#ifdef CONFIG_RELOCATABLE 112162306a36Sopenharmony_ci /* 112262306a36Sopenharmony_ci * Early page table uses only one PUD, which makes it possible 112362306a36Sopenharmony_ci * to map PUD_SIZE aligned on PUD_SIZE: if the relocation offset 112462306a36Sopenharmony_ci * makes the kernel cross over a PUD_SIZE boundary, raise a bug 112562306a36Sopenharmony_ci * since a part of the kernel would not get mapped. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci BUG_ON(PUD_SIZE - (kernel_map.virt_addr & (PUD_SIZE - 1)) < kernel_map.size); 112862306a36Sopenharmony_ci relocate_kernel(); 112962306a36Sopenharmony_ci#endif 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci apply_early_boot_alternatives(); 113262306a36Sopenharmony_ci pt_ops_set_early(); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* Setup early PGD for fixmap */ 113562306a36Sopenharmony_ci create_pgd_mapping(early_pg_dir, FIXADDR_START, 113662306a36Sopenharmony_ci fixmap_pgd_next, PGDIR_SIZE, PAGE_TABLE); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 113962306a36Sopenharmony_ci /* Setup fixmap P4D and PUD */ 114062306a36Sopenharmony_ci if (pgtable_l5_enabled) 114162306a36Sopenharmony_ci create_p4d_mapping(fixmap_p4d, FIXADDR_START, 114262306a36Sopenharmony_ci (uintptr_t)fixmap_pud, P4D_SIZE, PAGE_TABLE); 114362306a36Sopenharmony_ci /* Setup fixmap PUD and PMD */ 114462306a36Sopenharmony_ci if (pgtable_l4_enabled) 114562306a36Sopenharmony_ci create_pud_mapping(fixmap_pud, FIXADDR_START, 114662306a36Sopenharmony_ci (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE); 114762306a36Sopenharmony_ci create_pmd_mapping(fixmap_pmd, FIXADDR_START, 114862306a36Sopenharmony_ci (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE); 114962306a36Sopenharmony_ci /* Setup trampoline PGD and PMD */ 115062306a36Sopenharmony_ci create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr, 115162306a36Sopenharmony_ci trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE); 115262306a36Sopenharmony_ci if (pgtable_l5_enabled) 115362306a36Sopenharmony_ci create_p4d_mapping(trampoline_p4d, kernel_map.virt_addr, 115462306a36Sopenharmony_ci (uintptr_t)trampoline_pud, P4D_SIZE, PAGE_TABLE); 115562306a36Sopenharmony_ci if (pgtable_l4_enabled) 115662306a36Sopenharmony_ci create_pud_mapping(trampoline_pud, kernel_map.virt_addr, 115762306a36Sopenharmony_ci (uintptr_t)trampoline_pmd, PUD_SIZE, PAGE_TABLE); 115862306a36Sopenharmony_ci#ifdef CONFIG_XIP_KERNEL 115962306a36Sopenharmony_ci create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr, 116062306a36Sopenharmony_ci kernel_map.xiprom, PMD_SIZE, PAGE_KERNEL_EXEC); 116162306a36Sopenharmony_ci#else 116262306a36Sopenharmony_ci create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr, 116362306a36Sopenharmony_ci kernel_map.phys_addr, PMD_SIZE, PAGE_KERNEL_EXEC); 116462306a36Sopenharmony_ci#endif 116562306a36Sopenharmony_ci#else 116662306a36Sopenharmony_ci /* Setup trampoline PGD */ 116762306a36Sopenharmony_ci create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr, 116862306a36Sopenharmony_ci kernel_map.phys_addr, PGDIR_SIZE, PAGE_KERNEL_EXEC); 116962306a36Sopenharmony_ci#endif 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci /* 117262306a36Sopenharmony_ci * Setup early PGD covering entire kernel which will allow 117362306a36Sopenharmony_ci * us to reach paging_init(). We map all memory banks later 117462306a36Sopenharmony_ci * in setup_vm_final() below. 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_ci create_kernel_page_table(early_pg_dir, true); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* Setup early mapping for FDT early scan */ 117962306a36Sopenharmony_ci create_fdt_early_page_table(__fix_to_virt(FIX_FDT), dtb_pa); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* 118262306a36Sopenharmony_ci * Bootime fixmap only can handle PMD_SIZE mapping. Thus, boot-ioremap 118362306a36Sopenharmony_ci * range can not span multiple pmds. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) 118662306a36Sopenharmony_ci != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 118962306a36Sopenharmony_ci /* 119062306a36Sopenharmony_ci * Early ioremap fixmap is already created as it lies within first 2MB 119162306a36Sopenharmony_ci * of fixmap region. We always map PMD_SIZE. Thus, both FIX_BTMAP_END 119262306a36Sopenharmony_ci * FIX_BTMAP_BEGIN should lie in the same pmd. Verify that and warn 119362306a36Sopenharmony_ci * the user if not. 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_ci fix_bmap_spmd = fixmap_pmd[pmd_index(__fix_to_virt(FIX_BTMAP_BEGIN))]; 119662306a36Sopenharmony_ci fix_bmap_epmd = fixmap_pmd[pmd_index(__fix_to_virt(FIX_BTMAP_END))]; 119762306a36Sopenharmony_ci if (pmd_val(fix_bmap_spmd) != pmd_val(fix_bmap_epmd)) { 119862306a36Sopenharmony_ci WARN_ON(1); 119962306a36Sopenharmony_ci pr_warn("fixmap btmap start [%08lx] != end [%08lx]\n", 120062306a36Sopenharmony_ci pmd_val(fix_bmap_spmd), pmd_val(fix_bmap_epmd)); 120162306a36Sopenharmony_ci pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", 120262306a36Sopenharmony_ci fix_to_virt(FIX_BTMAP_BEGIN)); 120362306a36Sopenharmony_ci pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n", 120462306a36Sopenharmony_ci fix_to_virt(FIX_BTMAP_END)); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END); 120762306a36Sopenharmony_ci pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci#endif 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci pt_ops_set_fixmap(); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic void __init create_linear_mapping_range(phys_addr_t start, 121562306a36Sopenharmony_ci phys_addr_t end, 121662306a36Sopenharmony_ci uintptr_t fixed_map_size) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci phys_addr_t pa; 121962306a36Sopenharmony_ci uintptr_t va, map_size; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci for (pa = start; pa < end; pa += map_size) { 122262306a36Sopenharmony_ci va = (uintptr_t)__va(pa); 122362306a36Sopenharmony_ci map_size = fixed_map_size ? fixed_map_size : 122462306a36Sopenharmony_ci best_map_size(pa, va, end - pa); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci create_pgd_mapping(swapper_pg_dir, va, pa, map_size, 122762306a36Sopenharmony_ci pgprot_from_va(va)); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic void __init create_linear_mapping_page_table(void) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci phys_addr_t start, end; 123462306a36Sopenharmony_ci phys_addr_t kfence_pool __maybe_unused; 123562306a36Sopenharmony_ci u64 i; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci#ifdef CONFIG_STRICT_KERNEL_RWX 123862306a36Sopenharmony_ci phys_addr_t ktext_start = __pa_symbol(_start); 123962306a36Sopenharmony_ci phys_addr_t ktext_size = __init_data_begin - _start; 124062306a36Sopenharmony_ci phys_addr_t krodata_start = __pa_symbol(__start_rodata); 124162306a36Sopenharmony_ci phys_addr_t krodata_size = _data - __start_rodata; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* Isolate kernel text and rodata so they don't get mapped with a PUD */ 124462306a36Sopenharmony_ci memblock_mark_nomap(ktext_start, ktext_size); 124562306a36Sopenharmony_ci memblock_mark_nomap(krodata_start, krodata_size); 124662306a36Sopenharmony_ci#endif 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci#ifdef CONFIG_KFENCE 124962306a36Sopenharmony_ci /* 125062306a36Sopenharmony_ci * kfence pool must be backed by PAGE_SIZE mappings, so allocate it 125162306a36Sopenharmony_ci * before we setup the linear mapping so that we avoid using hugepages 125262306a36Sopenharmony_ci * for this region. 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_ci kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE); 125562306a36Sopenharmony_ci BUG_ON(!kfence_pool); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE); 125862306a36Sopenharmony_ci __kfence_pool = __va(kfence_pool); 125962306a36Sopenharmony_ci#endif 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* Map all memory banks in the linear mapping */ 126262306a36Sopenharmony_ci for_each_mem_range(i, &start, &end) { 126362306a36Sopenharmony_ci if (start >= end) 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci if (start <= __pa(PAGE_OFFSET) && 126662306a36Sopenharmony_ci __pa(PAGE_OFFSET) < end) 126762306a36Sopenharmony_ci start = __pa(PAGE_OFFSET); 126862306a36Sopenharmony_ci if (end >= __pa(PAGE_OFFSET) + memory_limit) 126962306a36Sopenharmony_ci end = __pa(PAGE_OFFSET) + memory_limit; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci create_linear_mapping_range(start, end, 0); 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci#ifdef CONFIG_STRICT_KERNEL_RWX 127562306a36Sopenharmony_ci create_linear_mapping_range(ktext_start, ktext_start + ktext_size, 0); 127662306a36Sopenharmony_ci create_linear_mapping_range(krodata_start, 127762306a36Sopenharmony_ci krodata_start + krodata_size, 0); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci memblock_clear_nomap(ktext_start, ktext_size); 128062306a36Sopenharmony_ci memblock_clear_nomap(krodata_start, krodata_size); 128162306a36Sopenharmony_ci#endif 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci#ifdef CONFIG_KFENCE 128462306a36Sopenharmony_ci create_linear_mapping_range(kfence_pool, 128562306a36Sopenharmony_ci kfence_pool + KFENCE_POOL_SIZE, 128662306a36Sopenharmony_ci PAGE_SIZE); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE); 128962306a36Sopenharmony_ci#endif 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic void __init setup_vm_final(void) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci /* Setup swapper PGD for fixmap */ 129562306a36Sopenharmony_ci#if !defined(CONFIG_64BIT) 129662306a36Sopenharmony_ci /* 129762306a36Sopenharmony_ci * In 32-bit, the device tree lies in a pgd entry, so it must be copied 129862306a36Sopenharmony_ci * directly in swapper_pg_dir in addition to the pgd entry that points 129962306a36Sopenharmony_ci * to fixmap_pte. 130062306a36Sopenharmony_ci */ 130162306a36Sopenharmony_ci unsigned long idx = pgd_index(__fix_to_virt(FIX_FDT)); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci set_pgd(&swapper_pg_dir[idx], early_pg_dir[idx]); 130462306a36Sopenharmony_ci#endif 130562306a36Sopenharmony_ci create_pgd_mapping(swapper_pg_dir, FIXADDR_START, 130662306a36Sopenharmony_ci __pa_symbol(fixmap_pgd_next), 130762306a36Sopenharmony_ci PGDIR_SIZE, PAGE_TABLE); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* Map the linear mapping */ 131062306a36Sopenharmony_ci create_linear_mapping_page_table(); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* Map the kernel */ 131362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 131462306a36Sopenharmony_ci create_kernel_page_table(swapper_pg_dir, false); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci#ifdef CONFIG_KASAN 131762306a36Sopenharmony_ci kasan_swapper_init(); 131862306a36Sopenharmony_ci#endif 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* Clear fixmap PTE and PMD mappings */ 132162306a36Sopenharmony_ci clear_fixmap(FIX_PTE); 132262306a36Sopenharmony_ci clear_fixmap(FIX_PMD); 132362306a36Sopenharmony_ci clear_fixmap(FIX_PUD); 132462306a36Sopenharmony_ci clear_fixmap(FIX_P4D); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* Move to swapper page table */ 132762306a36Sopenharmony_ci csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | satp_mode); 132862306a36Sopenharmony_ci local_flush_tlb_all(); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci pt_ops_set_late(); 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci#else 133362306a36Sopenharmony_ciasmlinkage void __init setup_vm(uintptr_t dtb_pa) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci dtb_early_va = (void *)dtb_pa; 133662306a36Sopenharmony_ci dtb_early_pa = dtb_pa; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic inline void setup_vm_final(void) 134062306a36Sopenharmony_ci{ 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci#endif /* CONFIG_MMU */ 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci/* Reserve 128M low memory by default for swiotlb buffer */ 134562306a36Sopenharmony_ci#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20) 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int __init reserve_crashkernel_low(unsigned long long low_size) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci unsigned long long low_base; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit); 135262306a36Sopenharmony_ci if (!low_base) { 135362306a36Sopenharmony_ci pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size); 135462306a36Sopenharmony_ci return -ENOMEM; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n", 135862306a36Sopenharmony_ci low_base, low_base + low_size, low_size >> 20); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci crashk_low_res.start = low_base; 136162306a36Sopenharmony_ci crashk_low_res.end = low_base + low_size - 1; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return 0; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/* 136762306a36Sopenharmony_ci * reserve_crashkernel() - reserves memory for crash kernel 136862306a36Sopenharmony_ci * 136962306a36Sopenharmony_ci * This function reserves memory area given in "crashkernel=" kernel command 137062306a36Sopenharmony_ci * line parameter. The memory reserved is used by dump capture kernel when 137162306a36Sopenharmony_ci * primary kernel is crashing. 137262306a36Sopenharmony_ci */ 137362306a36Sopenharmony_cistatic void __init reserve_crashkernel(void) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci unsigned long long crash_base = 0; 137662306a36Sopenharmony_ci unsigned long long crash_size = 0; 137762306a36Sopenharmony_ci unsigned long long crash_low_size = 0; 137862306a36Sopenharmony_ci unsigned long search_start = memblock_start_of_DRAM(); 137962306a36Sopenharmony_ci unsigned long search_end = (unsigned long)dma32_phys_limit; 138062306a36Sopenharmony_ci char *cmdline = boot_command_line; 138162306a36Sopenharmony_ci bool fixed_base = false; 138262306a36Sopenharmony_ci bool high = false; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci int ret = 0; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_KEXEC_CORE)) 138762306a36Sopenharmony_ci return; 138862306a36Sopenharmony_ci /* 138962306a36Sopenharmony_ci * Don't reserve a region for a crash kernel on a crash kernel 139062306a36Sopenharmony_ci * since it doesn't make much sense and we have limited memory 139162306a36Sopenharmony_ci * resources. 139262306a36Sopenharmony_ci */ 139362306a36Sopenharmony_ci if (is_kdump_kernel()) { 139462306a36Sopenharmony_ci pr_info("crashkernel: ignoring reservation request\n"); 139562306a36Sopenharmony_ci return; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci ret = parse_crashkernel(cmdline, memblock_phys_mem_size(), 139962306a36Sopenharmony_ci &crash_size, &crash_base); 140062306a36Sopenharmony_ci if (ret == -ENOENT) { 140162306a36Sopenharmony_ci /* Fallback to crashkernel=X,[high,low] */ 140262306a36Sopenharmony_ci ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base); 140362306a36Sopenharmony_ci if (ret || !crash_size) 140462306a36Sopenharmony_ci return; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* 140762306a36Sopenharmony_ci * crashkernel=Y,low is valid only when crashkernel=X,high 140862306a36Sopenharmony_ci * is passed. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base); 141162306a36Sopenharmony_ci if (ret == -ENOENT) 141262306a36Sopenharmony_ci crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE; 141362306a36Sopenharmony_ci else if (ret) 141462306a36Sopenharmony_ci return; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci search_start = (unsigned long)dma32_phys_limit; 141762306a36Sopenharmony_ci search_end = memblock_end_of_DRAM(); 141862306a36Sopenharmony_ci high = true; 141962306a36Sopenharmony_ci } else if (ret || !crash_size) { 142062306a36Sopenharmony_ci /* Invalid argument value specified */ 142162306a36Sopenharmony_ci return; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci crash_size = PAGE_ALIGN(crash_size); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (crash_base) { 142762306a36Sopenharmony_ci fixed_base = true; 142862306a36Sopenharmony_ci search_start = crash_base; 142962306a36Sopenharmony_ci search_end = crash_base + crash_size; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* 143362306a36Sopenharmony_ci * Current riscv boot protocol requires 2MB alignment for 143462306a36Sopenharmony_ci * RV64 and 4MB alignment for RV32 (hugepage size) 143562306a36Sopenharmony_ci * 143662306a36Sopenharmony_ci * Try to alloc from 32bit addressible physical memory so that 143762306a36Sopenharmony_ci * swiotlb can work on the crash kernel. 143862306a36Sopenharmony_ci */ 143962306a36Sopenharmony_ci crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE, 144062306a36Sopenharmony_ci search_start, search_end); 144162306a36Sopenharmony_ci if (crash_base == 0) { 144262306a36Sopenharmony_ci /* 144362306a36Sopenharmony_ci * For crashkernel=size[KMG]@offset[KMG], print out failure 144462306a36Sopenharmony_ci * message if can't reserve the specified region. 144562306a36Sopenharmony_ci */ 144662306a36Sopenharmony_ci if (fixed_base) { 144762306a36Sopenharmony_ci pr_warn("crashkernel: allocating failed with given size@offset\n"); 144862306a36Sopenharmony_ci return; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (high) { 145262306a36Sopenharmony_ci /* 145362306a36Sopenharmony_ci * For crashkernel=size[KMG],high, if the first attempt was 145462306a36Sopenharmony_ci * for high memory, fall back to low memory. 145562306a36Sopenharmony_ci */ 145662306a36Sopenharmony_ci search_start = memblock_start_of_DRAM(); 145762306a36Sopenharmony_ci search_end = (unsigned long)dma32_phys_limit; 145862306a36Sopenharmony_ci } else { 145962306a36Sopenharmony_ci /* 146062306a36Sopenharmony_ci * For crashkernel=size[KMG], if the first attempt was for 146162306a36Sopenharmony_ci * low memory, fall back to high memory, the minimum required 146262306a36Sopenharmony_ci * low memory will be reserved later. 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_ci search_start = (unsigned long)dma32_phys_limit; 146562306a36Sopenharmony_ci search_end = memblock_end_of_DRAM(); 146662306a36Sopenharmony_ci crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE, 147062306a36Sopenharmony_ci search_start, search_end); 147162306a36Sopenharmony_ci if (crash_base == 0) { 147262306a36Sopenharmony_ci pr_warn("crashkernel: couldn't allocate %lldKB\n", 147362306a36Sopenharmony_ci crash_size >> 10); 147462306a36Sopenharmony_ci return; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if ((crash_base >= dma32_phys_limit) && crash_low_size && 147962306a36Sopenharmony_ci reserve_crashkernel_low(crash_low_size)) { 148062306a36Sopenharmony_ci memblock_phys_free(crash_base, crash_size); 148162306a36Sopenharmony_ci return; 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n", 148562306a36Sopenharmony_ci crash_base, crash_base + crash_size, crash_size >> 20); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci crashk_res.start = crash_base; 148862306a36Sopenharmony_ci crashk_res.end = crash_base + crash_size - 1; 148962306a36Sopenharmony_ci} 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_civoid __init paging_init(void) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci setup_bootmem(); 149462306a36Sopenharmony_ci setup_vm_final(); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Depend on that Linear Mapping is ready */ 149762306a36Sopenharmony_ci memblock_allow_resize(); 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_civoid __init misc_mem_init(void) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT); 150362306a36Sopenharmony_ci arch_numa_init(); 150462306a36Sopenharmony_ci sparse_init(); 150562306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 150662306a36Sopenharmony_ci /* The entire VMEMMAP region has been populated. Flush TLB for this region */ 150762306a36Sopenharmony_ci local_flush_tlb_kernel_range(VMEMMAP_START, VMEMMAP_END); 150862306a36Sopenharmony_ci#endif 150962306a36Sopenharmony_ci zone_sizes_init(); 151062306a36Sopenharmony_ci reserve_crashkernel(); 151162306a36Sopenharmony_ci memblock_dump_all(); 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 151562306a36Sopenharmony_ciint __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, 151662306a36Sopenharmony_ci struct vmem_altmap *altmap) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci return vmemmap_populate_basepages(start, end, node, NULL); 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci#endif 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci#if defined(CONFIG_MMU) && defined(CONFIG_64BIT) 152362306a36Sopenharmony_ci/* 152462306a36Sopenharmony_ci * Pre-allocates page-table pages for a specific area in the kernel 152562306a36Sopenharmony_ci * page-table. Only the level which needs to be synchronized between 152662306a36Sopenharmony_ci * all page-tables is allocated because the synchronization can be 152762306a36Sopenharmony_ci * expensive. 152862306a36Sopenharmony_ci */ 152962306a36Sopenharmony_cistatic void __init preallocate_pgd_pages_range(unsigned long start, unsigned long end, 153062306a36Sopenharmony_ci const char *area) 153162306a36Sopenharmony_ci{ 153262306a36Sopenharmony_ci unsigned long addr; 153362306a36Sopenharmony_ci const char *lvl; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci for (addr = start; addr < end && addr >= start; addr = ALIGN(addr + 1, PGDIR_SIZE)) { 153662306a36Sopenharmony_ci pgd_t *pgd = pgd_offset_k(addr); 153762306a36Sopenharmony_ci p4d_t *p4d; 153862306a36Sopenharmony_ci pud_t *pud; 153962306a36Sopenharmony_ci pmd_t *pmd; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci lvl = "p4d"; 154262306a36Sopenharmony_ci p4d = p4d_alloc(&init_mm, pgd, addr); 154362306a36Sopenharmony_ci if (!p4d) 154462306a36Sopenharmony_ci goto failed; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (pgtable_l5_enabled) 154762306a36Sopenharmony_ci continue; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci lvl = "pud"; 155062306a36Sopenharmony_ci pud = pud_alloc(&init_mm, p4d, addr); 155162306a36Sopenharmony_ci if (!pud) 155262306a36Sopenharmony_ci goto failed; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (pgtable_l4_enabled) 155562306a36Sopenharmony_ci continue; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci lvl = "pmd"; 155862306a36Sopenharmony_ci pmd = pmd_alloc(&init_mm, pud, addr); 155962306a36Sopenharmony_ci if (!pmd) 156062306a36Sopenharmony_ci goto failed; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci return; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cifailed: 156562306a36Sopenharmony_ci /* 156662306a36Sopenharmony_ci * The pages have to be there now or they will be missing in 156762306a36Sopenharmony_ci * process page-tables later. 156862306a36Sopenharmony_ci */ 156962306a36Sopenharmony_ci panic("Failed to pre-allocate %s pages for %s area\n", lvl, area); 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_civoid __init pgtable_cache_init(void) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci preallocate_pgd_pages_range(VMALLOC_START, VMALLOC_END, "vmalloc"); 157562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_MODULES)) 157662306a36Sopenharmony_ci preallocate_pgd_pages_range(MODULES_VADDR, MODULES_END, "bpf/modules"); 157762306a36Sopenharmony_ci} 157862306a36Sopenharmony_ci#endif 1579