162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Based on arch/arm/mm/proc.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001 Deep Blue Solutions Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 762306a36Sopenharmony_ci * Author: Catalin Marinas <catalin.marinas@arm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/linkage.h> 1262306a36Sopenharmony_ci#include <linux/pgtable.h> 1362306a36Sopenharmony_ci#include <linux/cfi_types.h> 1462306a36Sopenharmony_ci#include <asm/assembler.h> 1562306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1662306a36Sopenharmony_ci#include <asm/asm_pointer_auth.h> 1762306a36Sopenharmony_ci#include <asm/hwcap.h> 1862306a36Sopenharmony_ci#include <asm/kernel-pgtable.h> 1962306a36Sopenharmony_ci#include <asm/pgtable-hwdef.h> 2062306a36Sopenharmony_ci#include <asm/cpufeature.h> 2162306a36Sopenharmony_ci#include <asm/alternative.h> 2262306a36Sopenharmony_ci#include <asm/smp.h> 2362306a36Sopenharmony_ci#include <asm/sysreg.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef CONFIG_ARM64_64K_PAGES 2662306a36Sopenharmony_ci#define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K 2762306a36Sopenharmony_ci#elif defined(CONFIG_ARM64_16K_PAGES) 2862306a36Sopenharmony_ci#define TCR_TG_FLAGS TCR_TG0_16K | TCR_TG1_16K 2962306a36Sopenharmony_ci#else /* CONFIG_ARM64_4K_PAGES */ 3062306a36Sopenharmony_ci#define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#ifdef CONFIG_RANDOMIZE_BASE 3462306a36Sopenharmony_ci#define TCR_KASLR_FLAGS TCR_NFD1 3562306a36Sopenharmony_ci#else 3662306a36Sopenharmony_ci#define TCR_KASLR_FLAGS 0 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define TCR_SMP_FLAGS TCR_SHARED 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* PTWs cacheable, inner/outer WBWA */ 4262306a36Sopenharmony_ci#define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifdef CONFIG_KASAN_SW_TAGS 4562306a36Sopenharmony_ci#define TCR_KASAN_SW_FLAGS TCR_TBI1 | TCR_TBID1 4662306a36Sopenharmony_ci#else 4762306a36Sopenharmony_ci#define TCR_KASAN_SW_FLAGS 0 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#ifdef CONFIG_KASAN_HW_TAGS 5162306a36Sopenharmony_ci#define TCR_MTE_FLAGS TCR_TCMA1 | TCR_TBI1 | TCR_TBID1 5262306a36Sopenharmony_ci#elif defined(CONFIG_ARM64_MTE) 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * The mte_zero_clear_page_tags() implementation uses DC GZVA, which relies on 5562306a36Sopenharmony_ci * TBI being enabled at EL1. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define TCR_MTE_FLAGS TCR_TBI1 | TCR_TBID1 5862306a36Sopenharmony_ci#else 5962306a36Sopenharmony_ci#define TCR_MTE_FLAGS 0 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and 6462306a36Sopenharmony_ci * changed during mte_cpu_setup to Normal Tagged if the system supports MTE. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define MAIR_EL1_SET \ 6762306a36Sopenharmony_ci (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) | \ 6862306a36Sopenharmony_ci MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \ 6962306a36Sopenharmony_ci MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \ 7062306a36Sopenharmony_ci MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \ 7162306a36Sopenharmony_ci MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED)) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#ifdef CONFIG_CPU_PM 7462306a36Sopenharmony_ci/** 7562306a36Sopenharmony_ci * cpu_do_suspend - save CPU registers context 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * x0: virtual address of context pointer 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * This must be kept in sync with struct cpu_suspend_ctx in <asm/suspend.h>. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ciSYM_FUNC_START(cpu_do_suspend) 8262306a36Sopenharmony_ci mrs x2, tpidr_el0 8362306a36Sopenharmony_ci mrs x3, tpidrro_el0 8462306a36Sopenharmony_ci mrs x4, contextidr_el1 8562306a36Sopenharmony_ci mrs x5, osdlr_el1 8662306a36Sopenharmony_ci mrs x6, cpacr_el1 8762306a36Sopenharmony_ci mrs x7, tcr_el1 8862306a36Sopenharmony_ci mrs x8, vbar_el1 8962306a36Sopenharmony_ci mrs x9, mdscr_el1 9062306a36Sopenharmony_ci mrs x10, oslsr_el1 9162306a36Sopenharmony_ci mrs x11, sctlr_el1 9262306a36Sopenharmony_ci get_this_cpu_offset x12 9362306a36Sopenharmony_ci mrs x13, sp_el0 9462306a36Sopenharmony_ci stp x2, x3, [x0] 9562306a36Sopenharmony_ci stp x4, x5, [x0, #16] 9662306a36Sopenharmony_ci stp x6, x7, [x0, #32] 9762306a36Sopenharmony_ci stp x8, x9, [x0, #48] 9862306a36Sopenharmony_ci stp x10, x11, [x0, #64] 9962306a36Sopenharmony_ci stp x12, x13, [x0, #80] 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * Save x18 as it may be used as a platform register, e.g. by shadow 10262306a36Sopenharmony_ci * call stack. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci str x18, [x0, #96] 10562306a36Sopenharmony_ci ret 10662306a36Sopenharmony_ciSYM_FUNC_END(cpu_do_suspend) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/** 10962306a36Sopenharmony_ci * cpu_do_resume - restore CPU register context 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * x0: Address of context pointer 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ciSYM_FUNC_START(cpu_do_resume) 11462306a36Sopenharmony_ci ldp x2, x3, [x0] 11562306a36Sopenharmony_ci ldp x4, x5, [x0, #16] 11662306a36Sopenharmony_ci ldp x6, x8, [x0, #32] 11762306a36Sopenharmony_ci ldp x9, x10, [x0, #48] 11862306a36Sopenharmony_ci ldp x11, x12, [x0, #64] 11962306a36Sopenharmony_ci ldp x13, x14, [x0, #80] 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * Restore x18, as it may be used as a platform register, and clear 12262306a36Sopenharmony_ci * the buffer to minimize the risk of exposure when used for shadow 12362306a36Sopenharmony_ci * call stack. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci ldr x18, [x0, #96] 12662306a36Sopenharmony_ci str xzr, [x0, #96] 12762306a36Sopenharmony_ci msr tpidr_el0, x2 12862306a36Sopenharmony_ci msr tpidrro_el0, x3 12962306a36Sopenharmony_ci msr contextidr_el1, x4 13062306a36Sopenharmony_ci msr cpacr_el1, x6 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Don't change t0sz here, mask those bits when restoring */ 13362306a36Sopenharmony_ci mrs x7, tcr_el1 13462306a36Sopenharmony_ci bfi x8, x7, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci msr tcr_el1, x8 13762306a36Sopenharmony_ci msr vbar_el1, x9 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * __cpu_setup() cleared MDSCR_EL1.MDE and friends, before unmasking 14162306a36Sopenharmony_ci * debug exceptions. By restoring MDSCR_EL1 here, we may take a debug 14262306a36Sopenharmony_ci * exception. Mask them until local_daif_restore() in cpu_suspend() 14362306a36Sopenharmony_ci * resets them. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci disable_daif 14662306a36Sopenharmony_ci msr mdscr_el1, x10 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci msr sctlr_el1, x12 14962306a36Sopenharmony_ci set_this_cpu_offset x13 15062306a36Sopenharmony_ci msr sp_el0, x14 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * Restore oslsr_el1 by writing oslar_el1 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci msr osdlr_el1, x5 15562306a36Sopenharmony_ci ubfx x11, x11, #1, #1 15662306a36Sopenharmony_ci msr oslar_el1, x11 15762306a36Sopenharmony_ci reset_pmuserenr_el0 x0 // Disable PMU access from EL0 15862306a36Sopenharmony_ci reset_amuserenr_el0 x0 // Disable AMU access from EL0 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cialternative_if ARM64_HAS_RAS_EXTN 16162306a36Sopenharmony_ci msr_s SYS_DISR_EL1, xzr 16262306a36Sopenharmony_cialternative_else_nop_endif 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ptrauth_keys_install_kernel_nosync x14, x1, x2, x3 16562306a36Sopenharmony_ci isb 16662306a36Sopenharmony_ci ret 16762306a36Sopenharmony_ciSYM_FUNC_END(cpu_do_resume) 16862306a36Sopenharmony_ci#endif 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci .pushsection ".idmap.text", "a" 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 17362306a36Sopenharmony_ci adrp \tmp1, reserved_pg_dir 17462306a36Sopenharmony_ci phys_to_ttbr \tmp2, \tmp1 17562306a36Sopenharmony_ci offset_ttbr1 \tmp2, \tmp1 17662306a36Sopenharmony_ci msr ttbr1_el1, \tmp2 17762306a36Sopenharmony_ci isb 17862306a36Sopenharmony_ci tlbi vmalle1 17962306a36Sopenharmony_ci dsb nsh 18062306a36Sopenharmony_ci isb 18162306a36Sopenharmony_ci.endm 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * void idmap_cpu_replace_ttbr1(phys_addr_t ttbr1) 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * This is the low-level counterpart to cpu_replace_ttbr1, and should not be 18762306a36Sopenharmony_ci * called by anything else. It can only be executed from a TTBR0 mapping. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ciSYM_TYPED_FUNC_START(idmap_cpu_replace_ttbr1) 19062306a36Sopenharmony_ci __idmap_cpu_set_reserved_ttbr1 x1, x3 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci offset_ttbr1 x0, x3 19362306a36Sopenharmony_ci msr ttbr1_el1, x0 19462306a36Sopenharmony_ci isb 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci ret 19762306a36Sopenharmony_ciSYM_FUNC_END(idmap_cpu_replace_ttbr1) 19862306a36Sopenharmony_ci .popsection 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define KPTI_NG_PTE_FLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS | PTE_WRITE) 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci .pushsection ".idmap.text", "a" 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci .macro kpti_mk_tbl_ng, type, num_entries 20762306a36Sopenharmony_ci add end_\type\()p, cur_\type\()p, #\num_entries * 8 20862306a36Sopenharmony_ci.Ldo_\type: 20962306a36Sopenharmony_ci ldr \type, [cur_\type\()p] // Load the entry 21062306a36Sopenharmony_ci tbz \type, #0, .Lnext_\type // Skip invalid and 21162306a36Sopenharmony_ci tbnz \type, #11, .Lnext_\type // non-global entries 21262306a36Sopenharmony_ci orr \type, \type, #PTE_NG // Same bit for blocks and pages 21362306a36Sopenharmony_ci str \type, [cur_\type\()p] // Update the entry 21462306a36Sopenharmony_ci .ifnc \type, pte 21562306a36Sopenharmony_ci tbnz \type, #1, .Lderef_\type 21662306a36Sopenharmony_ci .endif 21762306a36Sopenharmony_ci.Lnext_\type: 21862306a36Sopenharmony_ci add cur_\type\()p, cur_\type\()p, #8 21962306a36Sopenharmony_ci cmp cur_\type\()p, end_\type\()p 22062306a36Sopenharmony_ci b.ne .Ldo_\type 22162306a36Sopenharmony_ci .endm 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * Dereference the current table entry and map it into the temporary 22562306a36Sopenharmony_ci * fixmap slot associated with the current level. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci .macro kpti_map_pgtbl, type, level 22862306a36Sopenharmony_ci str xzr, [temp_pte, #8 * (\level + 1)] // break before make 22962306a36Sopenharmony_ci dsb nshst 23062306a36Sopenharmony_ci add pte, temp_pte, #PAGE_SIZE * (\level + 1) 23162306a36Sopenharmony_ci lsr pte, pte, #12 23262306a36Sopenharmony_ci tlbi vaae1, pte 23362306a36Sopenharmony_ci dsb nsh 23462306a36Sopenharmony_ci isb 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci phys_to_pte pte, cur_\type\()p 23762306a36Sopenharmony_ci add cur_\type\()p, temp_pte, #PAGE_SIZE * (\level + 1) 23862306a36Sopenharmony_ci orr pte, pte, pte_flags 23962306a36Sopenharmony_ci str pte, [temp_pte, #8 * (\level + 1)] 24062306a36Sopenharmony_ci dsb nshst 24162306a36Sopenharmony_ci .endm 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* 24462306a36Sopenharmony_ci * void __kpti_install_ng_mappings(int cpu, int num_secondaries, phys_addr_t temp_pgd, 24562306a36Sopenharmony_ci * unsigned long temp_pte_va) 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * Called exactly once from stop_machine context by each CPU found during boot. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci .pushsection ".data", "aw", %progbits 25062306a36Sopenharmony_ciSYM_DATA(__idmap_kpti_flag, .long 1) 25162306a36Sopenharmony_ci .popsection 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciSYM_TYPED_FUNC_START(idmap_kpti_install_ng_mappings) 25462306a36Sopenharmony_ci cpu .req w0 25562306a36Sopenharmony_ci temp_pte .req x0 25662306a36Sopenharmony_ci num_cpus .req w1 25762306a36Sopenharmony_ci pte_flags .req x1 25862306a36Sopenharmony_ci temp_pgd_phys .req x2 25962306a36Sopenharmony_ci swapper_ttb .req x3 26062306a36Sopenharmony_ci flag_ptr .req x4 26162306a36Sopenharmony_ci cur_pgdp .req x5 26262306a36Sopenharmony_ci end_pgdp .req x6 26362306a36Sopenharmony_ci pgd .req x7 26462306a36Sopenharmony_ci cur_pudp .req x8 26562306a36Sopenharmony_ci end_pudp .req x9 26662306a36Sopenharmony_ci cur_pmdp .req x11 26762306a36Sopenharmony_ci end_pmdp .req x12 26862306a36Sopenharmony_ci cur_ptep .req x14 26962306a36Sopenharmony_ci end_ptep .req x15 27062306a36Sopenharmony_ci pte .req x16 27162306a36Sopenharmony_ci valid .req x17 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci mov x5, x3 // preserve temp_pte arg 27462306a36Sopenharmony_ci mrs swapper_ttb, ttbr1_el1 27562306a36Sopenharmony_ci adr_l flag_ptr, __idmap_kpti_flag 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci cbnz cpu, __idmap_kpti_secondary 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* We're the boot CPU. Wait for the others to catch up */ 28062306a36Sopenharmony_ci sevl 28162306a36Sopenharmony_ci1: wfe 28262306a36Sopenharmony_ci ldaxr w17, [flag_ptr] 28362306a36Sopenharmony_ci eor w17, w17, num_cpus 28462306a36Sopenharmony_ci cbnz w17, 1b 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Switch to the temporary page tables on this CPU only */ 28762306a36Sopenharmony_ci __idmap_cpu_set_reserved_ttbr1 x8, x9 28862306a36Sopenharmony_ci offset_ttbr1 temp_pgd_phys, x8 28962306a36Sopenharmony_ci msr ttbr1_el1, temp_pgd_phys 29062306a36Sopenharmony_ci isb 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci mov temp_pte, x5 29362306a36Sopenharmony_ci mov_q pte_flags, KPTI_NG_PTE_FLAGS 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Everybody is enjoying the idmap, so we can rewrite swapper. */ 29662306a36Sopenharmony_ci /* PGD */ 29762306a36Sopenharmony_ci adrp cur_pgdp, swapper_pg_dir 29862306a36Sopenharmony_ci kpti_map_pgtbl pgd, 0 29962306a36Sopenharmony_ci kpti_mk_tbl_ng pgd, PTRS_PER_PGD 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Ensure all the updated entries are visible to secondary CPUs */ 30262306a36Sopenharmony_ci dsb ishst 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* We're done: fire up swapper_pg_dir again */ 30562306a36Sopenharmony_ci __idmap_cpu_set_reserved_ttbr1 x8, x9 30662306a36Sopenharmony_ci msr ttbr1_el1, swapper_ttb 30762306a36Sopenharmony_ci isb 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Set the flag to zero to indicate that we're all done */ 31062306a36Sopenharmony_ci str wzr, [flag_ptr] 31162306a36Sopenharmony_ci ret 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci.Lderef_pgd: 31462306a36Sopenharmony_ci /* PUD */ 31562306a36Sopenharmony_ci .if CONFIG_PGTABLE_LEVELS > 3 31662306a36Sopenharmony_ci pud .req x10 31762306a36Sopenharmony_ci pte_to_phys cur_pudp, pgd 31862306a36Sopenharmony_ci kpti_map_pgtbl pud, 1 31962306a36Sopenharmony_ci kpti_mk_tbl_ng pud, PTRS_PER_PUD 32062306a36Sopenharmony_ci b .Lnext_pgd 32162306a36Sopenharmony_ci .else /* CONFIG_PGTABLE_LEVELS <= 3 */ 32262306a36Sopenharmony_ci pud .req pgd 32362306a36Sopenharmony_ci .set .Lnext_pud, .Lnext_pgd 32462306a36Sopenharmony_ci .endif 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci.Lderef_pud: 32762306a36Sopenharmony_ci /* PMD */ 32862306a36Sopenharmony_ci .if CONFIG_PGTABLE_LEVELS > 2 32962306a36Sopenharmony_ci pmd .req x13 33062306a36Sopenharmony_ci pte_to_phys cur_pmdp, pud 33162306a36Sopenharmony_ci kpti_map_pgtbl pmd, 2 33262306a36Sopenharmony_ci kpti_mk_tbl_ng pmd, PTRS_PER_PMD 33362306a36Sopenharmony_ci b .Lnext_pud 33462306a36Sopenharmony_ci .else /* CONFIG_PGTABLE_LEVELS <= 2 */ 33562306a36Sopenharmony_ci pmd .req pgd 33662306a36Sopenharmony_ci .set .Lnext_pmd, .Lnext_pgd 33762306a36Sopenharmony_ci .endif 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci.Lderef_pmd: 34062306a36Sopenharmony_ci /* PTE */ 34162306a36Sopenharmony_ci pte_to_phys cur_ptep, pmd 34262306a36Sopenharmony_ci kpti_map_pgtbl pte, 3 34362306a36Sopenharmony_ci kpti_mk_tbl_ng pte, PTRS_PER_PTE 34462306a36Sopenharmony_ci b .Lnext_pmd 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci .unreq cpu 34762306a36Sopenharmony_ci .unreq temp_pte 34862306a36Sopenharmony_ci .unreq num_cpus 34962306a36Sopenharmony_ci .unreq pte_flags 35062306a36Sopenharmony_ci .unreq temp_pgd_phys 35162306a36Sopenharmony_ci .unreq cur_pgdp 35262306a36Sopenharmony_ci .unreq end_pgdp 35362306a36Sopenharmony_ci .unreq pgd 35462306a36Sopenharmony_ci .unreq cur_pudp 35562306a36Sopenharmony_ci .unreq end_pudp 35662306a36Sopenharmony_ci .unreq pud 35762306a36Sopenharmony_ci .unreq cur_pmdp 35862306a36Sopenharmony_ci .unreq end_pmdp 35962306a36Sopenharmony_ci .unreq pmd 36062306a36Sopenharmony_ci .unreq cur_ptep 36162306a36Sopenharmony_ci .unreq end_ptep 36262306a36Sopenharmony_ci .unreq pte 36362306a36Sopenharmony_ci .unreq valid 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Secondary CPUs end up here */ 36662306a36Sopenharmony_ci__idmap_kpti_secondary: 36762306a36Sopenharmony_ci /* Uninstall swapper before surgery begins */ 36862306a36Sopenharmony_ci __idmap_cpu_set_reserved_ttbr1 x16, x17 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Increment the flag to let the boot CPU we're ready */ 37162306a36Sopenharmony_ci1: ldxr w16, [flag_ptr] 37262306a36Sopenharmony_ci add w16, w16, #1 37362306a36Sopenharmony_ci stxr w17, w16, [flag_ptr] 37462306a36Sopenharmony_ci cbnz w17, 1b 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Wait for the boot CPU to finish messing around with swapper */ 37762306a36Sopenharmony_ci sevl 37862306a36Sopenharmony_ci1: wfe 37962306a36Sopenharmony_ci ldxr w16, [flag_ptr] 38062306a36Sopenharmony_ci cbnz w16, 1b 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* All done, act like nothing happened */ 38362306a36Sopenharmony_ci msr ttbr1_el1, swapper_ttb 38462306a36Sopenharmony_ci isb 38562306a36Sopenharmony_ci ret 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci .unreq swapper_ttb 38862306a36Sopenharmony_ci .unreq flag_ptr 38962306a36Sopenharmony_ciSYM_FUNC_END(idmap_kpti_install_ng_mappings) 39062306a36Sopenharmony_ci .popsection 39162306a36Sopenharmony_ci#endif 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* 39462306a36Sopenharmony_ci * __cpu_setup 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * Initialise the processor for turning the MMU on. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * Input: 39962306a36Sopenharmony_ci * x0 - actual number of VA bits (ignored unless VA_BITS > 48) 40062306a36Sopenharmony_ci * Output: 40162306a36Sopenharmony_ci * Return in x0 the value of the SCTLR_EL1 register. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci .pushsection ".idmap.text", "a" 40462306a36Sopenharmony_ciSYM_FUNC_START(__cpu_setup) 40562306a36Sopenharmony_ci tlbi vmalle1 // Invalidate local TLB 40662306a36Sopenharmony_ci dsb nsh 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci mov x1, #3 << 20 40962306a36Sopenharmony_ci msr cpacr_el1, x1 // Enable FP/ASIMD 41062306a36Sopenharmony_ci mov x1, #1 << 12 // Reset mdscr_el1 and disable 41162306a36Sopenharmony_ci msr mdscr_el1, x1 // access to the DCC from EL0 41262306a36Sopenharmony_ci isb // Unmask debug exceptions now, 41362306a36Sopenharmony_ci enable_dbg // since this is per-cpu 41462306a36Sopenharmony_ci reset_pmuserenr_el0 x1 // Disable PMU access from EL0 41562306a36Sopenharmony_ci reset_amuserenr_el0 x1 // Disable AMU access from EL0 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * Default values for VMSA control registers. These will be adjusted 41962306a36Sopenharmony_ci * below depending on detected CPU features. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci mair .req x17 42262306a36Sopenharmony_ci tcr .req x16 42362306a36Sopenharmony_ci mov_q mair, MAIR_EL1_SET 42462306a36Sopenharmony_ci mov_q tcr, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ 42562306a36Sopenharmony_ci TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ 42662306a36Sopenharmony_ci TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci tcr_clear_errata_bits tcr, x9, x5 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci#ifdef CONFIG_ARM64_VA_BITS_52 43162306a36Sopenharmony_ci sub x9, xzr, x0 43262306a36Sopenharmony_ci add x9, x9, #64 43362306a36Sopenharmony_ci tcr_set_t1sz tcr, x9 43462306a36Sopenharmony_ci#else 43562306a36Sopenharmony_ci idmap_get_t0sz x9 43662306a36Sopenharmony_ci#endif 43762306a36Sopenharmony_ci tcr_set_t0sz tcr, x9 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* 44062306a36Sopenharmony_ci * Set the IPS bits in TCR_EL1. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci tcr_compute_pa_size tcr, #TCR_IPS_SHIFT, x5, x6 44362306a36Sopenharmony_ci#ifdef CONFIG_ARM64_HW_AFDBM 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * Enable hardware update of the Access Flags bit. 44662306a36Sopenharmony_ci * Hardware dirty bit management is enabled later, 44762306a36Sopenharmony_ci * via capabilities. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci mrs x9, ID_AA64MMFR1_EL1 45062306a36Sopenharmony_ci and x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK 45162306a36Sopenharmony_ci cbz x9, 1f 45262306a36Sopenharmony_ci orr tcr, tcr, #TCR_HA // hardware Access flag update 45362306a36Sopenharmony_ci1: 45462306a36Sopenharmony_ci#endif /* CONFIG_ARM64_HW_AFDBM */ 45562306a36Sopenharmony_ci msr mair_el1, mair 45662306a36Sopenharmony_ci msr tcr_el1, tcr 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci mrs_s x1, SYS_ID_AA64MMFR3_EL1 45962306a36Sopenharmony_ci ubfx x1, x1, #ID_AA64MMFR3_EL1_S1PIE_SHIFT, #4 46062306a36Sopenharmony_ci cbz x1, .Lskip_indirection 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci mov_q x0, PIE_E0 46362306a36Sopenharmony_ci msr REG_PIRE0_EL1, x0 46462306a36Sopenharmony_ci mov_q x0, PIE_E1 46562306a36Sopenharmony_ci msr REG_PIR_EL1, x0 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mov x0, TCR2_EL1x_PIE 46862306a36Sopenharmony_ci msr REG_TCR2_EL1, x0 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci.Lskip_indirection: 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * Prepare SCTLR 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci mov_q x0, INIT_SCTLR_EL1_MMU_ON 47662306a36Sopenharmony_ci ret // return to head.S 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci .unreq mair 47962306a36Sopenharmony_ci .unreq tcr 48062306a36Sopenharmony_ciSYM_FUNC_END(__cpu_setup) 481