18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Based on arch/arm/mm/init.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995-2005 Russell King 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/swap.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/cache.h> 158c2ecf20Sopenharmony_ci#include <linux/mman.h> 168c2ecf20Sopenharmony_ci#include <linux/nodemask.h> 178c2ecf20Sopenharmony_ci#include <linux/initrd.h> 188c2ecf20Sopenharmony_ci#include <linux/gfp.h> 198c2ecf20Sopenharmony_ci#include <linux/memblock.h> 208c2ecf20Sopenharmony_ci#include <linux/sort.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/of_fdt.h> 238c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> 248c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 258c2ecf20Sopenharmony_ci#include <linux/efi.h> 268c2ecf20Sopenharmony_ci#include <linux/swiotlb.h> 278c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 288c2ecf20Sopenharmony_ci#include <linux/mm.h> 298c2ecf20Sopenharmony_ci#include <linux/kexec.h> 308c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 318c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 328c2ecf20Sopenharmony_ci#include <linux/acpi_iort.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/boot.h> 358c2ecf20Sopenharmony_ci#include <asm/fixmap.h> 368c2ecf20Sopenharmony_ci#include <asm/kasan.h> 378c2ecf20Sopenharmony_ci#include <asm/kernel-pgtable.h> 388c2ecf20Sopenharmony_ci#include <asm/memory.h> 398c2ecf20Sopenharmony_ci#include <asm/numa.h> 408c2ecf20Sopenharmony_ci#include <asm/sections.h> 418c2ecf20Sopenharmony_ci#include <asm/setup.h> 428c2ecf20Sopenharmony_ci#include <linux/sizes.h> 438c2ecf20Sopenharmony_ci#include <asm/tlb.h> 448c2ecf20Sopenharmony_ci#include <asm/alternative.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * We need to be able to catch inadvertent references to memstart_addr 488c2ecf20Sopenharmony_ci * that occur (potentially in generic code) before arm64_memblock_init() 498c2ecf20Sopenharmony_ci * executes, which assigns it its actual value. So use a default value 508c2ecf20Sopenharmony_ci * that cannot be mistaken for a real physical address. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cis64 memstart_addr __ro_after_init = -1; 538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memstart_addr); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * If the corresponding config options are enabled, we create both ZONE_DMA 578c2ecf20Sopenharmony_ci * and ZONE_DMA32. By default ZONE_DMA covers the 32-bit addressable memory 588c2ecf20Sopenharmony_ci * unless restricted on specific platforms (e.g. 30-bit on Raspberry Pi 4). 598c2ecf20Sopenharmony_ci * In such case, ZONE_DMA32 covers the rest of the 32-bit addressable memory, 608c2ecf20Sopenharmony_ci * otherwise it is empty. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Memory reservation for crash kernel either done early or deferred 638c2ecf20Sopenharmony_ci * depending on DMA memory zones configs (ZONE_DMA) -- 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * In absence of ZONE_DMA configs arm64_dma_phys_limit initialized 668c2ecf20Sopenharmony_ci * here instead of max_zone_phys(). This lets early reservation of 678c2ecf20Sopenharmony_ci * crash kernel memory which has a dependency on arm64_dma_phys_limit. 688c2ecf20Sopenharmony_ci * Reserving memory early for crash kernel allows linear creation of block 698c2ecf20Sopenharmony_ci * mappings (greater than page-granularity) for all the memory bank rangs. 708c2ecf20Sopenharmony_ci * In this scheme a comparatively quicker boot is observed. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * If ZONE_DMA configs are defined, crash kernel memory reservation 738c2ecf20Sopenharmony_ci * is delayed until DMA zone memory range size initilazation performed in 748c2ecf20Sopenharmony_ci * zone_sizes_init(). The defer is necessary to steer clear of DMA zone 758c2ecf20Sopenharmony_ci * memory range to avoid overlap allocation. So crash kernel memory boundaries 768c2ecf20Sopenharmony_ci * are not known when mapping all bank memory ranges, which otherwise means 778c2ecf20Sopenharmony_ci * not possible to exclude crash kernel range from creating block mappings 788c2ecf20Sopenharmony_ci * so page-granularity mappings are created for the entire memory range. 798c2ecf20Sopenharmony_ci * Hence a slightly slower boot is observed. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Note: Page-granularity mapppings are necessary for crash kernel memory 828c2ecf20Sopenharmony_ci * range for shrinking its size via /sys/kernel/kexec_crash_size interface. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32) 858c2ecf20Sopenharmony_ciphys_addr_t __ro_after_init arm64_dma_phys_limit; 868c2ecf20Sopenharmony_ci#else 878c2ecf20Sopenharmony_ciphys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1; 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC_CORE 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * reserve_crashkernel() - reserves memory for crash kernel 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * This function reserves memory area given in "crashkernel=" kernel command 958c2ecf20Sopenharmony_ci * line parameter. The memory reserved is used by dump capture kernel when 968c2ecf20Sopenharmony_ci * primary kernel is crashing. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic void __init reserve_crashkernel(void) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci unsigned long long crash_base, crash_size; 1018c2ecf20Sopenharmony_ci int ret; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 1048c2ecf20Sopenharmony_ci &crash_size, &crash_base); 1058c2ecf20Sopenharmony_ci /* no crashkernel= or invalid value specified */ 1068c2ecf20Sopenharmony_ci if (ret || !crash_size) 1078c2ecf20Sopenharmony_ci return; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci crash_size = PAGE_ALIGN(crash_size); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (crash_base == 0) { 1128c2ecf20Sopenharmony_ci /* Current arm64 boot protocol requires 2MB alignment */ 1138c2ecf20Sopenharmony_ci crash_base = memblock_find_in_range(0, arm64_dma_phys_limit, 1148c2ecf20Sopenharmony_ci crash_size, SZ_2M); 1158c2ecf20Sopenharmony_ci if (crash_base == 0) { 1168c2ecf20Sopenharmony_ci pr_warn("cannot allocate crashkernel (size:0x%llx)\n", 1178c2ecf20Sopenharmony_ci crash_size); 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci /* User specifies base address explicitly. */ 1228c2ecf20Sopenharmony_ci if (!memblock_is_region_memory(crash_base, crash_size)) { 1238c2ecf20Sopenharmony_ci pr_warn("cannot reserve crashkernel: region is not memory\n"); 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (memblock_is_region_reserved(crash_base, crash_size)) { 1288c2ecf20Sopenharmony_ci pr_warn("cannot reserve crashkernel: region overlaps reserved memory\n"); 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!IS_ALIGNED(crash_base, SZ_2M)) { 1338c2ecf20Sopenharmony_ci pr_warn("cannot reserve crashkernel: base address is not 2MB aligned\n"); 1348c2ecf20Sopenharmony_ci return; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci memblock_reserve(crash_base, crash_size); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n", 1408c2ecf20Sopenharmony_ci crash_base, crash_base + crash_size, crash_size >> 20); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci crashk_res.start = crash_base; 1438c2ecf20Sopenharmony_ci crashk_res.end = crash_base + crash_size - 1; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci#else 1468c2ecf20Sopenharmony_cistatic void __init reserve_crashkernel(void) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci#endif /* CONFIG_KEXEC_CORE */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#ifdef CONFIG_CRASH_DUMP 1528c2ecf20Sopenharmony_cistatic int __init early_init_dt_scan_elfcorehdr(unsigned long node, 1538c2ecf20Sopenharmony_ci const char *uname, int depth, void *data) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci const __be32 *reg; 1568c2ecf20Sopenharmony_ci int len; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (depth != 1 || strcmp(uname, "chosen") != 0) 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci reg = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len); 1628c2ecf20Sopenharmony_ci if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells))) 1638c2ecf20Sopenharmony_ci return 1; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, ®); 1668c2ecf20Sopenharmony_ci elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, ®); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 1; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * reserve_elfcorehdr() - reserves memory for elf core header 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * This function reserves the memory occupied by an elf core header 1758c2ecf20Sopenharmony_ci * described in the device tree. This region contains all the 1768c2ecf20Sopenharmony_ci * information about primary kernel's core image and is used by a dump 1778c2ecf20Sopenharmony_ci * capture kernel to access the system memory on primary kernel. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void __init reserve_elfcorehdr(void) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci of_scan_flat_dt(early_init_dt_scan_elfcorehdr, NULL); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!elfcorehdr_size) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) { 1878c2ecf20Sopenharmony_ci pr_warn("elfcorehdr is overlapped\n"); 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci memblock_reserve(elfcorehdr_addr, elfcorehdr_size); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci pr_info("Reserving %lldKB of memory at 0x%llx for elfcorehdr\n", 1948c2ecf20Sopenharmony_ci elfcorehdr_size >> 10, elfcorehdr_addr); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci#else 1978c2ecf20Sopenharmony_cistatic void __init reserve_elfcorehdr(void) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci#endif /* CONFIG_CRASH_DUMP */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * Return the maximum physical address for a zone accessible by the given bits 2048c2ecf20Sopenharmony_ci * limit. If DRAM starts above 32-bit, expand the zone to the maximum 2058c2ecf20Sopenharmony_ci * available memory, otherwise cap it at 32-bit. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_cistatic phys_addr_t __init max_zone_phys(unsigned int zone_bits) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci phys_addr_t zone_mask = DMA_BIT_MASK(zone_bits); 2108c2ecf20Sopenharmony_ci phys_addr_t phys_start = memblock_start_of_DRAM(); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (phys_start > U32_MAX) 2138c2ecf20Sopenharmony_ci zone_mask = PHYS_ADDR_MAX; 2148c2ecf20Sopenharmony_ci else if (phys_start > zone_mask) 2158c2ecf20Sopenharmony_ci zone_mask = U32_MAX; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return min(zone_mask, memblock_end_of_DRAM() - 1) + 1; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void __init zone_sizes_init(unsigned long min, unsigned long max) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; 2238c2ecf20Sopenharmony_ci unsigned int __maybe_unused acpi_zone_dma_bits; 2248c2ecf20Sopenharmony_ci unsigned int __maybe_unused dt_zone_dma_bits; 2258c2ecf20Sopenharmony_ci phys_addr_t __maybe_unused dma32_phys_limit = max_zone_phys(32); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA 2288c2ecf20Sopenharmony_ci acpi_zone_dma_bits = fls64(acpi_iort_dma_get_max_cpu_address()); 2298c2ecf20Sopenharmony_ci dt_zone_dma_bits = fls64(of_dma_get_max_cpu_address(NULL)); 2308c2ecf20Sopenharmony_ci zone_dma_bits = min3(32U, dt_zone_dma_bits, acpi_zone_dma_bits); 2318c2ecf20Sopenharmony_ci arm64_dma_phys_limit = max_zone_phys(zone_dma_bits); 2328c2ecf20Sopenharmony_ci max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); 2338c2ecf20Sopenharmony_ci#endif 2348c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32 2358c2ecf20Sopenharmony_ci max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit); 2368c2ecf20Sopenharmony_ci if (!arm64_dma_phys_limit) 2378c2ecf20Sopenharmony_ci arm64_dma_phys_limit = dma32_phys_limit; 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci max_zone_pfns[ZONE_NORMAL] = max; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci free_area_init(max_zone_pfns); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciint pfn_valid(unsigned long pfn) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci phys_addr_t addr = pfn << PAGE_SHIFT; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if ((addr >> PAGE_SHIFT) != pfn) 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM 2528c2ecf20Sopenharmony_ci if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!valid_section(__pfn_to_section(pfn))) 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * ZONE_DEVICE memory does not have the memblock entries. 2608c2ecf20Sopenharmony_ci * memblock_is_map_memory() check for ZONE_DEVICE based 2618c2ecf20Sopenharmony_ci * addresses will always fail. Even the normal hotplugged 2628c2ecf20Sopenharmony_ci * memory will never have MEMBLOCK_NOMAP flag set in their 2638c2ecf20Sopenharmony_ci * memblock entries. Skip memblock search for all non early 2648c2ecf20Sopenharmony_ci * memory sections covering all of hotplug memory including 2658c2ecf20Sopenharmony_ci * both normal and ZONE_DEVICE based. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (!early_section(__pfn_to_section(pfn))) 2688c2ecf20Sopenharmony_ci return pfn_section_valid(__pfn_to_section(pfn), pfn); 2698c2ecf20Sopenharmony_ci#endif 2708c2ecf20Sopenharmony_ci return memblock_is_map_memory(addr); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pfn_valid); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic phys_addr_t memory_limit = PHYS_ADDR_MAX; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* 2778c2ecf20Sopenharmony_ci * Limit the memory size that was specified via FDT. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_cistatic int __init early_mem(char *p) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci if (!p) 2828c2ecf20Sopenharmony_ci return 1; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci memory_limit = memparse(p, &p) & PAGE_MASK; 2858c2ecf20Sopenharmony_ci pr_notice("Memory limited to %lldMB\n", memory_limit >> 20); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ciearly_param("mem", early_mem); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int __init early_init_dt_scan_usablemem(unsigned long node, 2928c2ecf20Sopenharmony_ci const char *uname, int depth, void *data) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct memblock_region *usablemem = data; 2958c2ecf20Sopenharmony_ci const __be32 *reg; 2968c2ecf20Sopenharmony_ci int len; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (depth != 1 || strcmp(uname, "chosen") != 0) 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci reg = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len); 3028c2ecf20Sopenharmony_ci if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells))) 3038c2ecf20Sopenharmony_ci return 1; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci usablemem->base = dt_mem_next_cell(dt_root_addr_cells, ®); 3068c2ecf20Sopenharmony_ci usablemem->size = dt_mem_next_cell(dt_root_size_cells, ®); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 1; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void __init fdt_enforce_memory_region(void) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct memblock_region reg = { 3148c2ecf20Sopenharmony_ci .size = 0, 3158c2ecf20Sopenharmony_ci }; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci of_scan_flat_dt(early_init_dt_scan_usablemem, ®); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (reg.size) 3208c2ecf20Sopenharmony_ci memblock_cap_memory_range(reg.base, reg.size); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_civoid __init arm64_memblock_init(void) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci const s64 linear_region_size = BIT(vabits_actual - 1); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Handle linux,usable-memory-range property */ 3288c2ecf20Sopenharmony_ci fdt_enforce_memory_region(); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Remove memory above our supported physical address size */ 3318c2ecf20Sopenharmony_ci memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Select a suitable value for the base of physical memory. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci memstart_addr = round_down(memblock_start_of_DRAM(), 3378c2ecf20Sopenharmony_ci ARM64_MEMSTART_ALIGN); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Remove the memory that we will not be able to cover with the 3418c2ecf20Sopenharmony_ci * linear mapping. Take care not to clip the kernel which may be 3428c2ecf20Sopenharmony_ci * high in memory. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci memblock_remove(max_t(u64, memstart_addr + linear_region_size, 3458c2ecf20Sopenharmony_ci __pa_symbol(_end)), ULLONG_MAX); 3468c2ecf20Sopenharmony_ci if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) { 3478c2ecf20Sopenharmony_ci /* ensure that memstart_addr remains sufficiently aligned */ 3488c2ecf20Sopenharmony_ci memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size, 3498c2ecf20Sopenharmony_ci ARM64_MEMSTART_ALIGN); 3508c2ecf20Sopenharmony_ci memblock_remove(0, memstart_addr); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * If we are running with a 52-bit kernel VA config on a system that 3558c2ecf20Sopenharmony_ci * does not support it, we have to place the available physical 3568c2ecf20Sopenharmony_ci * memory in the 48-bit addressable part of the linear region, i.e., 3578c2ecf20Sopenharmony_ci * we have to move it upward. Since memstart_addr represents the 3588c2ecf20Sopenharmony_ci * physical address of PAGE_OFFSET, we have to *subtract* from it. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) 3618c2ecf20Sopenharmony_ci memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * Apply the memory limit if it was set. Since the kernel may be loaded 3658c2ecf20Sopenharmony_ci * high up in memory, add back the kernel region that must be accessible 3668c2ecf20Sopenharmony_ci * via the linear mapping. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (memory_limit != PHYS_ADDR_MAX) { 3698c2ecf20Sopenharmony_ci memblock_mem_limit_remove_map(memory_limit); 3708c2ecf20Sopenharmony_ci memblock_add(__pa_symbol(_text), (u64)(_end - _text)); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size) { 3748c2ecf20Sopenharmony_ci /* 3758c2ecf20Sopenharmony_ci * Add back the memory we just removed if it results in the 3768c2ecf20Sopenharmony_ci * initrd to become inaccessible via the linear mapping. 3778c2ecf20Sopenharmony_ci * Otherwise, this is a no-op 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci u64 base = phys_initrd_start & PAGE_MASK; 3808c2ecf20Sopenharmony_ci u64 size = PAGE_ALIGN(phys_initrd_start + phys_initrd_size) - base; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * We can only add back the initrd memory if we don't end up 3848c2ecf20Sopenharmony_ci * with more memory than we can address via the linear mapping. 3858c2ecf20Sopenharmony_ci * It is up to the bootloader to position the kernel and the 3868c2ecf20Sopenharmony_ci * initrd reasonably close to each other (i.e., within 32 GB of 3878c2ecf20Sopenharmony_ci * each other) so that all granule/#levels combinations can 3888c2ecf20Sopenharmony_ci * always access both. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci if (WARN(base < memblock_start_of_DRAM() || 3918c2ecf20Sopenharmony_ci base + size > memblock_start_of_DRAM() + 3928c2ecf20Sopenharmony_ci linear_region_size, 3938c2ecf20Sopenharmony_ci "initrd not fully accessible via the linear mapping -- please check your bootloader ...\n")) { 3948c2ecf20Sopenharmony_ci phys_initrd_size = 0; 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci memblock_remove(base, size); /* clear MEMBLOCK_ flags */ 3978c2ecf20Sopenharmony_ci memblock_add(base, size); 3988c2ecf20Sopenharmony_ci memblock_reserve(base, size); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { 4038c2ecf20Sopenharmony_ci extern u16 memstart_offset_seed; 4048c2ecf20Sopenharmony_ci u64 range = linear_region_size - 4058c2ecf20Sopenharmony_ci (memblock_end_of_DRAM() - memblock_start_of_DRAM()); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * If the size of the linear region exceeds, by a sufficient 4098c2ecf20Sopenharmony_ci * margin, the size of the region that the available physical 4108c2ecf20Sopenharmony_ci * memory spans, randomize the linear region as well. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) { 4138c2ecf20Sopenharmony_ci range /= ARM64_MEMSTART_ALIGN; 4148c2ecf20Sopenharmony_ci memstart_addr -= ARM64_MEMSTART_ALIGN * 4158c2ecf20Sopenharmony_ci ((range * memstart_offset_seed) >> 16); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * Register the kernel text, kernel data, initrd, and initial 4218c2ecf20Sopenharmony_ci * pagetables with memblock. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci memblock_reserve(__pa_symbol(_text), _end - _text); 4248c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size) { 4258c2ecf20Sopenharmony_ci /* the generic initrd code expects virtual addresses */ 4268c2ecf20Sopenharmony_ci initrd_start = __phys_to_virt(phys_initrd_start); 4278c2ecf20Sopenharmony_ci initrd_end = initrd_start + phys_initrd_size; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci early_init_fdt_scan_reserved_mem(); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci reserve_elfcorehdr(); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) 4358c2ecf20Sopenharmony_ci reserve_crashkernel(); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci high_memory = __va(memblock_end_of_DRAM() - 1) + 1; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_civoid __init bootmem_init(void) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci unsigned long min, max; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci min = PFN_UP(memblock_start_of_DRAM()); 4458c2ecf20Sopenharmony_ci max = PFN_DOWN(memblock_end_of_DRAM()); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci max_pfn = max_low_pfn = max; 4508c2ecf20Sopenharmony_ci min_low_pfn = min; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci arm64_numa_init(); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * must be done after arm64_numa_init() which calls numa_init() to 4568c2ecf20Sopenharmony_ci * initialize node_online_map that gets used in hugetlb_cma_reserve() 4578c2ecf20Sopenharmony_ci * while allocating required CMA size across online nodes. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_CMA) 4608c2ecf20Sopenharmony_ci arm64_hugetlb_cma_reserve(); 4618c2ecf20Sopenharmony_ci#endif 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci dma_pernuma_cma_reserve(); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * sparse_init() tries to allocate memory from memblock, so must be 4678c2ecf20Sopenharmony_ci * done after the fixed reservations 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci sparse_init(); 4708c2ecf20Sopenharmony_ci zone_sizes_init(min, max); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * Reserve the CMA area after arm64_dma_phys_limit was initialised. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci dma_contiguous_reserve(arm64_dma_phys_limit); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * request_standard_resources() depends on crashkernel's memory being 4798c2ecf20Sopenharmony_ci * reserved, so do it here. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32)) 4828c2ecf20Sopenharmony_ci reserve_crashkernel(); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci memblock_dump_all(); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci#ifndef CONFIG_SPARSEMEM_VMEMMAP 4888c2ecf20Sopenharmony_cistatic inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct page *start_pg, *end_pg; 4918c2ecf20Sopenharmony_ci unsigned long pg, pgend; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * Convert start_pfn/end_pfn to a struct page pointer. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci start_pg = pfn_to_page(start_pfn - 1) + 1; 4978c2ecf20Sopenharmony_ci end_pg = pfn_to_page(end_pfn - 1) + 1; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * Convert to physical addresses, and round start upwards and end 5018c2ecf20Sopenharmony_ci * downwards. 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci pg = (unsigned long)PAGE_ALIGN(__pa(start_pg)); 5048c2ecf20Sopenharmony_ci pgend = (unsigned long)__pa(end_pg) & PAGE_MASK; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* 5078c2ecf20Sopenharmony_ci * If there are free pages between these, free the section of the 5088c2ecf20Sopenharmony_ci * memmap array. 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_ci if (pg < pgend) 5118c2ecf20Sopenharmony_ci memblock_free(pg, pgend - pg); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * The mem_map array can get very big. Free the unused area of the memory map. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_cistatic void __init free_unused_memmap(void) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci unsigned long start, end, prev_end = 0; 5208c2ecf20Sopenharmony_ci int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) { 5238c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM 5248c2ecf20Sopenharmony_ci /* 5258c2ecf20Sopenharmony_ci * Take care not to free memmap entries that don't exist due 5268c2ecf20Sopenharmony_ci * to SPARSEMEM sections which aren't present. 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_ci start = min(start, ALIGN(prev_end, PAGES_PER_SECTION)); 5298c2ecf20Sopenharmony_ci#endif 5308c2ecf20Sopenharmony_ci /* 5318c2ecf20Sopenharmony_ci * If we had a previous bank, and there is a space between the 5328c2ecf20Sopenharmony_ci * current bank and the previous, free it. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci if (prev_end && prev_end < start) 5358c2ecf20Sopenharmony_ci free_memmap(prev_end, start); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * Align up here since the VM subsystem insists that the 5398c2ecf20Sopenharmony_ci * memmap entries are valid from the bank end aligned to 5408c2ecf20Sopenharmony_ci * MAX_ORDER_NR_PAGES. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci prev_end = ALIGN(end, MAX_ORDER_NR_PAGES); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM 5468c2ecf20Sopenharmony_ci if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) 5478c2ecf20Sopenharmony_ci free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION)); 5488c2ecf20Sopenharmony_ci#endif 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci#endif /* !CONFIG_SPARSEMEM_VMEMMAP */ 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci/* 5538c2ecf20Sopenharmony_ci * mem_init() marks the free areas in the mem_map and tells us how much memory 5548c2ecf20Sopenharmony_ci * is free. This is done after various parts of the system have claimed their 5558c2ecf20Sopenharmony_ci * memory after the kernel image. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_civoid __init mem_init(void) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci if (swiotlb_force == SWIOTLB_FORCE || 5608c2ecf20Sopenharmony_ci max_pfn > PFN_DOWN(arm64_dma_phys_limit)) 5618c2ecf20Sopenharmony_ci swiotlb_init(1); 5628c2ecf20Sopenharmony_ci else 5638c2ecf20Sopenharmony_ci swiotlb_force = SWIOTLB_NO_FORCE; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci set_max_mapnr(max_pfn - PHYS_PFN_OFFSET); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci#ifndef CONFIG_SPARSEMEM_VMEMMAP 5688c2ecf20Sopenharmony_ci free_unused_memmap(); 5698c2ecf20Sopenharmony_ci#endif 5708c2ecf20Sopenharmony_ci /* this will put all unused low memory onto the freelists */ 5718c2ecf20Sopenharmony_ci memblock_free_all(); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci mem_init_print_info(NULL); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Check boundaries twice: Some fundamental inconsistencies can be 5778c2ecf20Sopenharmony_ci * detected at build time already. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 5808c2ecf20Sopenharmony_ci BUILD_BUG_ON(TASK_SIZE_32 > DEFAULT_MAP_WINDOW_64); 5818c2ecf20Sopenharmony_ci#endif 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) { 5848c2ecf20Sopenharmony_ci extern int sysctl_overcommit_memory; 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * On a machine this small we won't get anywhere without 5878c2ecf20Sopenharmony_ci * overcommit, so turn it on by default. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_civoid free_initmem(void) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci free_reserved_area(lm_alias(__init_begin), 5968c2ecf20Sopenharmony_ci lm_alias(__init_end), 5978c2ecf20Sopenharmony_ci POISON_FREE_INITMEM, "unused kernel"); 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * Unmap the __init region but leave the VM area in place. This 6008c2ecf20Sopenharmony_ci * prevents the region from being reused for kernel modules, which 6018c2ecf20Sopenharmony_ci * is not supported by kallsyms. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci unmap_kernel_range((u64)__init_begin, (u64)(__init_end - __init_begin)); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_civoid dump_mem_limit(void) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci if (memory_limit != PHYS_ADDR_MAX) { 6098c2ecf20Sopenharmony_ci pr_emerg("Memory Limit: %llu MB\n", memory_limit >> 20); 6108c2ecf20Sopenharmony_ci } else { 6118c2ecf20Sopenharmony_ci pr_emerg("Memory Limit: none\n"); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci} 614