18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Modifications by Kumar Gala (galak@kernel.crashing.org) to support 48c2ecf20Sopenharmony_ci * E500 Book E processors. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2004,2010 Freescale Semiconductor, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file contains the routines for initializing the MMU 98c2ecf20Sopenharmony_ci * on the 4xx series of chips. 108c2ecf20Sopenharmony_ci * -- paulus 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Derived from arch/ppc/mm/init.c: 138c2ecf20Sopenharmony_ci * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 168c2ecf20Sopenharmony_ci * and Cort Dougan (PReP) (cort@cs.nmt.edu) 178c2ecf20Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Derived from "arch/i386/mm/init.c" 208c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/signal.h> 248c2ecf20Sopenharmony_ci#include <linux/sched.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/errno.h> 278c2ecf20Sopenharmony_ci#include <linux/string.h> 288c2ecf20Sopenharmony_ci#include <linux/types.h> 298c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 308c2ecf20Sopenharmony_ci#include <linux/mman.h> 318c2ecf20Sopenharmony_ci#include <linux/mm.h> 328c2ecf20Sopenharmony_ci#include <linux/swap.h> 338c2ecf20Sopenharmony_ci#include <linux/stddef.h> 348c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 358c2ecf20Sopenharmony_ci#include <linux/init.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/highmem.h> 388c2ecf20Sopenharmony_ci#include <linux/memblock.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <asm/prom.h> 418c2ecf20Sopenharmony_ci#include <asm/io.h> 428c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 438c2ecf20Sopenharmony_ci#include <asm/mmu.h> 448c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 458c2ecf20Sopenharmony_ci#include <asm/smp.h> 468c2ecf20Sopenharmony_ci#include <asm/machdep.h> 478c2ecf20Sopenharmony_ci#include <asm/setup.h> 488c2ecf20Sopenharmony_ci#include <asm/paca.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciunsigned int tlbcam_index; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define NUM_TLBCAMS (64) 558c2ecf20Sopenharmony_cistruct tlbcam TLBCAM[NUM_TLBCAMS]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct tlbcamrange { 588c2ecf20Sopenharmony_ci unsigned long start; 598c2ecf20Sopenharmony_ci unsigned long limit; 608c2ecf20Sopenharmony_ci phys_addr_t phys; 618c2ecf20Sopenharmony_ci} tlbcam_addrs[NUM_TLBCAMS]; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciunsigned long tlbcam_sz(int idx) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return tlbcam_addrs[idx].limit - tlbcam_addrs[idx].start + 1; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_BOOKE 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * Return PA for this VA if it is mapped by a CAM, or 0 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ciphys_addr_t v_block_mapped(unsigned long va) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci int b; 758c2ecf20Sopenharmony_ci for (b = 0; b < tlbcam_index; ++b) 768c2ecf20Sopenharmony_ci if (va >= tlbcam_addrs[b].start && va < tlbcam_addrs[b].limit) 778c2ecf20Sopenharmony_ci return tlbcam_addrs[b].phys + (va - tlbcam_addrs[b].start); 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * Return VA for a given PA or 0 if not mapped 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ciunsigned long p_block_mapped(phys_addr_t pa) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int b; 878c2ecf20Sopenharmony_ci for (b = 0; b < tlbcam_index; ++b) 888c2ecf20Sopenharmony_ci if (pa >= tlbcam_addrs[b].phys 898c2ecf20Sopenharmony_ci && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) 908c2ecf20Sopenharmony_ci +tlbcam_addrs[b].phys) 918c2ecf20Sopenharmony_ci return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Set up a variable-size TLB entry (tlbcam). The parameters are not checked; 988c2ecf20Sopenharmony_ci * in particular size must be a power of 4 between 4k and the max supported by 998c2ecf20Sopenharmony_ci * an implementation; max may further be limited by what can be represented in 1008c2ecf20Sopenharmony_ci * an unsigned long (for example, 32-bit implementations cannot support a 4GB 1018c2ecf20Sopenharmony_ci * size). 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic void settlbcam(int index, unsigned long virt, phys_addr_t phys, 1048c2ecf20Sopenharmony_ci unsigned long size, unsigned long flags, unsigned int pid) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci unsigned int tsize; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci tsize = __ilog2(size) - 10; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP) || defined(CONFIG_PPC_E500MC) 1118c2ecf20Sopenharmony_ci if ((flags & _PAGE_NO_CACHE) == 0) 1128c2ecf20Sopenharmony_ci flags |= _PAGE_COHERENT; 1138c2ecf20Sopenharmony_ci#endif 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1); 1168c2ecf20Sopenharmony_ci TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid); 1178c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 = virt & PAGE_MASK; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 |= (flags & _PAGE_WRITETHRU) ? MAS2_W : 0; 1208c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 |= (flags & _PAGE_NO_CACHE) ? MAS2_I : 0; 1218c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 |= (flags & _PAGE_COHERENT) ? MAS2_M : 0; 1228c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; 1238c2ecf20Sopenharmony_ci TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci TLBCAM[index].MAS3 = (phys & MAS3_RPN) | MAS3_SX | MAS3_SR; 1268c2ecf20Sopenharmony_ci TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); 1278c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_BIG_PHYS)) 1288c2ecf20Sopenharmony_ci TLBCAM[index].MAS7 = (u64)phys >> 32; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Below is unlikely -- only for large user pages or similar */ 1318c2ecf20Sopenharmony_ci if (pte_user(__pte(flags))) { 1328c2ecf20Sopenharmony_ci TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; 1338c2ecf20Sopenharmony_ci TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci tlbcam_addrs[index].start = virt; 1378c2ecf20Sopenharmony_ci tlbcam_addrs[index].limit = virt + size - 1; 1388c2ecf20Sopenharmony_ci tlbcam_addrs[index].phys = phys; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciunsigned long calc_cam_sz(unsigned long ram, unsigned long virt, 1428c2ecf20Sopenharmony_ci phys_addr_t phys) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci unsigned int camsize = __ilog2(ram); 1458c2ecf20Sopenharmony_ci unsigned int align = __ffs(virt | phys); 1468c2ecf20Sopenharmony_ci unsigned long max_cam; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { 1498c2ecf20Sopenharmony_ci /* Convert (4^max) kB to (2^max) bytes */ 1508c2ecf20Sopenharmony_ci max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; 1518c2ecf20Sopenharmony_ci camsize &= ~1U; 1528c2ecf20Sopenharmony_ci align &= ~1U; 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci /* Convert (2^max) kB to (2^max) bytes */ 1558c2ecf20Sopenharmony_ci max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (camsize > align) 1598c2ecf20Sopenharmony_ci camsize = align; 1608c2ecf20Sopenharmony_ci if (camsize > max_cam) 1618c2ecf20Sopenharmony_ci camsize = max_cam; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 1UL << camsize; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt, 1678c2ecf20Sopenharmony_ci unsigned long ram, int max_cam_idx, 1688c2ecf20Sopenharmony_ci bool dryrun) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int i; 1718c2ecf20Sopenharmony_ci unsigned long amount_mapped = 0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Calculate CAM values */ 1748c2ecf20Sopenharmony_ci for (i = 0; ram && i < max_cam_idx; i++) { 1758c2ecf20Sopenharmony_ci unsigned long cam_sz; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci cam_sz = calc_cam_sz(ram, virt, phys); 1788c2ecf20Sopenharmony_ci if (!dryrun) 1798c2ecf20Sopenharmony_ci settlbcam(i, virt, phys, cam_sz, 1808c2ecf20Sopenharmony_ci pgprot_val(PAGE_KERNEL_X), 0); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ram -= cam_sz; 1838c2ecf20Sopenharmony_ci amount_mapped += cam_sz; 1848c2ecf20Sopenharmony_ci virt += cam_sz; 1858c2ecf20Sopenharmony_ci phys += cam_sz; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (dryrun) 1898c2ecf20Sopenharmony_ci return amount_mapped; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci loadcam_multi(0, i, max_cam_idx); 1928c2ecf20Sopenharmony_ci tlbcam_index = i; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 1958c2ecf20Sopenharmony_ci get_paca()->tcd.esel_next = i; 1968c2ecf20Sopenharmony_ci get_paca()->tcd.esel_max = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; 1978c2ecf20Sopenharmony_ci get_paca()->tcd.esel_first = i; 1988c2ecf20Sopenharmony_ci#endif 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return amount_mapped; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciunsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx, bool dryrun) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci unsigned long virt = PAGE_OFFSET; 2068c2ecf20Sopenharmony_ci phys_addr_t phys = memstart_addr; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return map_mem_in_cams_addr(phys, virt, ram, max_cam_idx, dryrun); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) 2148c2ecf20Sopenharmony_ci#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" 2158c2ecf20Sopenharmony_ci#endif 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciunsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_civoid flush_instruction_cache(void) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci unsigned long tmp; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_E200)) { 2278c2ecf20Sopenharmony_ci tmp = mfspr(SPRN_L1CSR0); 2288c2ecf20Sopenharmony_ci tmp |= L1CSR0_CFI | L1CSR0_CLFC; 2298c2ecf20Sopenharmony_ci mtspr(SPRN_L1CSR0, tmp); 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci tmp = mfspr(SPRN_L1CSR1); 2328c2ecf20Sopenharmony_ci tmp |= L1CSR1_ICFI | L1CSR1_ICLFR; 2338c2ecf20Sopenharmony_ci mtspr(SPRN_L1CSR1, tmp); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci isync(); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * MMU_init_hw does the chip-specific initialization of the MMU hardware. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_civoid __init MMU_init_hw(void) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci flush_instruction_cache(); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_civoid __init adjust_total_lowmem(void) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci unsigned long ram; 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* adjust lowmem size to __max_low_memory */ 2528c2ecf20Sopenharmony_ci ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci i = switch_to_as1(); 2558c2ecf20Sopenharmony_ci __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM, false); 2568c2ecf20Sopenharmony_ci restore_to_as0(i, 0, 0, 1); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci pr_info("Memory CAM mapping: "); 2598c2ecf20Sopenharmony_ci for (i = 0; i < tlbcam_index - 1; i++) 2608c2ecf20Sopenharmony_ci pr_cont("%lu/", tlbcam_sz(i) >> 20); 2618c2ecf20Sopenharmony_ci pr_cont("%lu Mb, residual: %dMb\n", tlbcam_sz(tlbcam_index - 1) >> 20, 2628c2ecf20Sopenharmony_ci (unsigned int)((total_lowmem - __max_low_memory) >> 20)); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci memblock_set_current_limit(memstart_addr + __max_low_memory); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_civoid setup_initial_memory_limit(phys_addr_t first_memblock_base, 2688c2ecf20Sopenharmony_ci phys_addr_t first_memblock_size) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci phys_addr_t limit = first_memblock_base + first_memblock_size; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 64M mapped initially according to head_fsl_booke.S */ 2738c2ecf20Sopenharmony_ci memblock_set_current_limit(min_t(u64, limit, 0x04000000)); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci#ifdef CONFIG_RELOCATABLE 2778c2ecf20Sopenharmony_ciint __initdata is_second_reloc; 2788c2ecf20Sopenharmony_cinotrace void __init relocate_init(u64 dt_ptr, phys_addr_t start) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci unsigned long base = kernstart_virt_addr; 2818c2ecf20Sopenharmony_ci phys_addr_t size; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci kernstart_addr = start; 2848c2ecf20Sopenharmony_ci if (is_second_reloc) { 2858c2ecf20Sopenharmony_ci virt_phys_offset = PAGE_OFFSET - memstart_addr; 2868c2ecf20Sopenharmony_ci kaslr_late_init(); 2878c2ecf20Sopenharmony_ci return; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Relocatable kernel support based on processing of dynamic 2928c2ecf20Sopenharmony_ci * relocation entries. Before we get the real memstart_addr, 2938c2ecf20Sopenharmony_ci * We will compute the virt_phys_offset like this: 2948c2ecf20Sopenharmony_ci * virt_phys_offset = stext.run - kernstart_addr 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * stext.run = (KERNELBASE & ~0x3ffffff) + 2978c2ecf20Sopenharmony_ci * (kernstart_addr & 0x3ffffff) 2988c2ecf20Sopenharmony_ci * When we relocate, we have : 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * (kernstart_addr & 0x3ffffff) = (stext.run & 0x3ffffff) 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * hence: 3038c2ecf20Sopenharmony_ci * virt_phys_offset = (KERNELBASE & ~0x3ffffff) - 3048c2ecf20Sopenharmony_ci * (kernstart_addr & ~0x3ffffff) 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci start &= ~0x3ffffff; 3088c2ecf20Sopenharmony_ci base &= ~0x3ffffff; 3098c2ecf20Sopenharmony_ci virt_phys_offset = base - start; 3108c2ecf20Sopenharmony_ci early_get_first_memblock_info(__va(dt_ptr), &size); 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * We now get the memstart_addr, then we should check if this 3138c2ecf20Sopenharmony_ci * address is the same as what the PAGE_OFFSET map to now. If 3148c2ecf20Sopenharmony_ci * not we have to change the map of PAGE_OFFSET to memstart_addr 3158c2ecf20Sopenharmony_ci * and do a second relocation. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci if (start != memstart_addr) { 3188c2ecf20Sopenharmony_ci int n; 3198c2ecf20Sopenharmony_ci long offset = start - memstart_addr; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci is_second_reloc = 1; 3228c2ecf20Sopenharmony_ci n = switch_to_as1(); 3238c2ecf20Sopenharmony_ci /* map a 64M area for the second relocation */ 3248c2ecf20Sopenharmony_ci if (memstart_addr > start) 3258c2ecf20Sopenharmony_ci map_mem_in_cams(0x4000000, CONFIG_LOWMEM_CAM_NUM, 3268c2ecf20Sopenharmony_ci false); 3278c2ecf20Sopenharmony_ci else 3288c2ecf20Sopenharmony_ci map_mem_in_cams_addr(start, PAGE_OFFSET + offset, 3298c2ecf20Sopenharmony_ci 0x4000000, CONFIG_LOWMEM_CAM_NUM, 3308c2ecf20Sopenharmony_ci false); 3318c2ecf20Sopenharmony_ci restore_to_as0(n, offset, __va(dt_ptr), 1); 3328c2ecf20Sopenharmony_ci /* We should never reach here */ 3338c2ecf20Sopenharmony_ci panic("Relocation error"); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci kaslr_early_init(__va(dt_ptr), size); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci#endif 3398c2ecf20Sopenharmony_ci#endif 340