18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PowerPC64 SLB support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM 68c2ecf20Sopenharmony_ci * Based on earlier code written by: 78c2ecf20Sopenharmony_ci * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com 88c2ecf20Sopenharmony_ci * Copyright (c) 2001 Dave Engebretsen 98c2ecf20Sopenharmony_ci * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/asm-prototypes.h> 138c2ecf20Sopenharmony_ci#include <asm/mmu.h> 148c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 158c2ecf20Sopenharmony_ci#include <asm/paca.h> 168c2ecf20Sopenharmony_ci#include <asm/lppaca.h> 178c2ecf20Sopenharmony_ci#include <asm/ppc-opcode.h> 188c2ecf20Sopenharmony_ci#include <asm/cputable.h> 198c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 208c2ecf20Sopenharmony_ci#include <asm/smp.h> 218c2ecf20Sopenharmony_ci#include <linux/compiler.h> 228c2ecf20Sopenharmony_ci#include <linux/context_tracking.h> 238c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 248c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/udbg.h> 278c2ecf20Sopenharmony_ci#include <asm/code-patching.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "internal.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cienum slb_index { 338c2ecf20Sopenharmony_ci LINEAR_INDEX = 0, /* Kernel linear map (0xc000000000000000) */ 348c2ecf20Sopenharmony_ci KSTACK_INDEX = 1, /* Kernel stack map */ 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic long slb_allocate_user(struct mm_struct *mm, unsigned long ea); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define slb_esid_mask(ssize) \ 408c2ecf20Sopenharmony_ci (((ssize) == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline unsigned long mk_esid_data(unsigned long ea, int ssize, 438c2ecf20Sopenharmony_ci enum slb_index index) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | index; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline unsigned long __mk_vsid_data(unsigned long vsid, int ssize, 498c2ecf20Sopenharmony_ci unsigned long flags) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return (vsid << slb_vsid_shift(ssize)) | flags | 528c2ecf20Sopenharmony_ci ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline unsigned long mk_vsid_data(unsigned long ea, int ssize, 568c2ecf20Sopenharmony_ci unsigned long flags) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cibool stress_slb_enabled __initdata; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int __init parse_stress_slb(char *p) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci stress_slb_enabled = true; 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ciearly_param("stress_slb", parse_stress_slb); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci__ro_after_init DEFINE_STATIC_KEY_FALSE(stress_slb_key); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void assert_slb_presence(bool present, unsigned long ea) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VM 758c2ecf20Sopenharmony_ci unsigned long tmp; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci WARN_ON_ONCE(mfmsr() & MSR_EE); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_206)) 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * slbfee. requires bit 24 (PPC bit 39) be clear in RB. Hardware 848c2ecf20Sopenharmony_ci * ignores all other bits from 0-27, so just clear them all. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci ea &= ~((1UL << SID_SHIFT) - 1); 878c2ecf20Sopenharmony_ci asm volatile(__PPC_SLBFEE_DOT(%0, %1) : "=r"(tmp) : "r"(ea) : "cr0"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci WARN_ON(present == (tmp == 0)); 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline void slb_shadow_update(unsigned long ea, int ssize, 948c2ecf20Sopenharmony_ci unsigned long flags, 958c2ecf20Sopenharmony_ci enum slb_index index) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct slb_shadow *p = get_slb_shadow(); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Clear the ESID first so the entry is not valid while we are 1018c2ecf20Sopenharmony_ci * updating it. No write barriers are needed here, provided 1028c2ecf20Sopenharmony_ci * we only update the current CPU's SLB shadow buffer. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci WRITE_ONCE(p->save_area[index].esid, 0); 1058c2ecf20Sopenharmony_ci WRITE_ONCE(p->save_area[index].vsid, cpu_to_be64(mk_vsid_data(ea, ssize, flags))); 1068c2ecf20Sopenharmony_ci WRITE_ONCE(p->save_area[index].esid, cpu_to_be64(mk_esid_data(ea, ssize, index))); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void slb_shadow_clear(enum slb_index index) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci WRITE_ONCE(get_slb_shadow()->save_area[index].esid, cpu_to_be64(index)); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic inline void create_shadowed_slbe(unsigned long ea, int ssize, 1158c2ecf20Sopenharmony_ci unsigned long flags, 1168c2ecf20Sopenharmony_ci enum slb_index index) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * Updating the shadow buffer before writing the SLB ensures 1208c2ecf20Sopenharmony_ci * we don't get a stale entry here if we get preempted by PHYP 1218c2ecf20Sopenharmony_ci * between these two statements. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci slb_shadow_update(ea, ssize, flags, index); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci assert_slb_presence(false, ea); 1268c2ecf20Sopenharmony_ci asm volatile("slbmte %0,%1" : 1278c2ecf20Sopenharmony_ci : "r" (mk_vsid_data(ea, ssize, flags)), 1288c2ecf20Sopenharmony_ci "r" (mk_esid_data(ea, ssize, index)) 1298c2ecf20Sopenharmony_ci : "memory" ); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * Insert bolted entries into SLB (which may not be empty, so don't clear 1348c2ecf20Sopenharmony_ci * slb_cache_ptr). 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_civoid __slb_restore_bolted_realmode(void) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct slb_shadow *p = get_slb_shadow(); 1398c2ecf20Sopenharmony_ci enum slb_index index; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* No isync needed because realmode. */ 1428c2ecf20Sopenharmony_ci for (index = 0; index < SLB_NUM_BOLTED; index++) { 1438c2ecf20Sopenharmony_ci asm volatile("slbmte %0,%1" : 1448c2ecf20Sopenharmony_ci : "r" (be64_to_cpu(p->save_area[index].vsid)), 1458c2ecf20Sopenharmony_ci "r" (be64_to_cpu(p->save_area[index].esid))); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci assert_slb_presence(true, local_paca->kstack); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * Insert the bolted entries into an empty SLB. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_civoid slb_restore_bolted_realmode(void) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci __slb_restore_bolted_realmode(); 1578c2ecf20Sopenharmony_ci get_paca()->slb_cache_ptr = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; 1608c2ecf20Sopenharmony_ci get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * This flushes all SLB entries including 0, so it must be realmode. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_civoid slb_flush_all_realmode(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci asm volatile("slbmte %0,%0; slbia" : : "r" (0)); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic __always_inline void __slb_flush_and_restore_bolted(bool preserve_kernel_lookaside) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct slb_shadow *p = get_slb_shadow(); 1748c2ecf20Sopenharmony_ci unsigned long ksp_esid_data, ksp_vsid_data; 1758c2ecf20Sopenharmony_ci u32 ih; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * SLBIA IH=1 on ISA v2.05 and newer processors may preserve lookaside 1798c2ecf20Sopenharmony_ci * information created with Class=0 entries, which we use for kernel 1808c2ecf20Sopenharmony_ci * SLB entries (the SLB entries themselves are still invalidated). 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Older processors will ignore this optimisation. Over-invalidation 1838c2ecf20Sopenharmony_ci * is fine because we never rely on lookaside information existing. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci if (preserve_kernel_lookaside) 1868c2ecf20Sopenharmony_ci ih = 1; 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci ih = 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ksp_esid_data = be64_to_cpu(p->save_area[KSTACK_INDEX].esid); 1918c2ecf20Sopenharmony_ci ksp_vsid_data = be64_to_cpu(p->save_area[KSTACK_INDEX].vsid); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci asm volatile(PPC_SLBIA(%0)" \n" 1948c2ecf20Sopenharmony_ci "slbmte %1, %2 \n" 1958c2ecf20Sopenharmony_ci :: "i" (ih), 1968c2ecf20Sopenharmony_ci "r" (ksp_vsid_data), 1978c2ecf20Sopenharmony_ci "r" (ksp_esid_data) 1988c2ecf20Sopenharmony_ci : "memory"); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * This flushes non-bolted entries, it can be run in virtual mode. Must 2038c2ecf20Sopenharmony_ci * be called with interrupts disabled. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_civoid slb_flush_and_restore_bolted(void) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci BUILD_BUG_ON(SLB_NUM_BOLTED != 2); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci WARN_ON(!irqs_disabled()); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * We can't take a PMU exception in the following code, so hard 2138c2ecf20Sopenharmony_ci * disable interrupts. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci hard_irq_disable(); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci isync(); 2188c2ecf20Sopenharmony_ci __slb_flush_and_restore_bolted(false); 2198c2ecf20Sopenharmony_ci isync(); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci assert_slb_presence(true, get_paca()->kstack); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci get_paca()->slb_cache_ptr = 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; 2268c2ecf20Sopenharmony_ci get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_civoid slb_save_contents(struct slb_entry *slb_ptr) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int i; 2328c2ecf20Sopenharmony_ci unsigned long e, v; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Save slb_cache_ptr value. */ 2358c2ecf20Sopenharmony_ci get_paca()->slb_save_cache_ptr = get_paca()->slb_cache_ptr; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (!slb_ptr) 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci for (i = 0; i < mmu_slb_size; i++) { 2418c2ecf20Sopenharmony_ci asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); 2428c2ecf20Sopenharmony_ci asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); 2438c2ecf20Sopenharmony_ci slb_ptr->esid = e; 2448c2ecf20Sopenharmony_ci slb_ptr->vsid = v; 2458c2ecf20Sopenharmony_ci slb_ptr++; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_civoid slb_dump_contents(struct slb_entry *slb_ptr) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int i, n; 2528c2ecf20Sopenharmony_ci unsigned long e, v; 2538c2ecf20Sopenharmony_ci unsigned long llp; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!slb_ptr) 2568c2ecf20Sopenharmony_ci return; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci pr_err("SLB contents of cpu 0x%x\n", smp_processor_id()); 2598c2ecf20Sopenharmony_ci pr_err("Last SLB entry inserted at slot %d\n", get_paca()->stab_rr); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (i = 0; i < mmu_slb_size; i++) { 2628c2ecf20Sopenharmony_ci e = slb_ptr->esid; 2638c2ecf20Sopenharmony_ci v = slb_ptr->vsid; 2648c2ecf20Sopenharmony_ci slb_ptr++; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!e && !v) 2678c2ecf20Sopenharmony_ci continue; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci pr_err("%02d %016lx %016lx\n", i, e, v); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (!(e & SLB_ESID_V)) { 2728c2ecf20Sopenharmony_ci pr_err("\n"); 2738c2ecf20Sopenharmony_ci continue; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci llp = v & SLB_VSID_LLP; 2768c2ecf20Sopenharmony_ci if (v & SLB_VSID_B_1T) { 2778c2ecf20Sopenharmony_ci pr_err(" 1T ESID=%9lx VSID=%13lx LLP:%3lx\n", 2788c2ecf20Sopenharmony_ci GET_ESID_1T(e), 2798c2ecf20Sopenharmony_ci (v & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T, llp); 2808c2ecf20Sopenharmony_ci } else { 2818c2ecf20Sopenharmony_ci pr_err(" 256M ESID=%9lx VSID=%13lx LLP:%3lx\n", 2828c2ecf20Sopenharmony_ci GET_ESID(e), 2838c2ecf20Sopenharmony_ci (v & ~SLB_VSID_B) >> SLB_VSID_SHIFT, llp); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci pr_err("----------------------------------\n"); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Dump slb cache entires as well. */ 2898c2ecf20Sopenharmony_ci pr_err("SLB cache ptr value = %d\n", get_paca()->slb_save_cache_ptr); 2908c2ecf20Sopenharmony_ci pr_err("Valid SLB cache entries:\n"); 2918c2ecf20Sopenharmony_ci n = min_t(int, get_paca()->slb_save_cache_ptr, SLB_CACHE_ENTRIES); 2928c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 2938c2ecf20Sopenharmony_ci pr_err("%02d EA[0-35]=%9x\n", i, get_paca()->slb_cache[i]); 2948c2ecf20Sopenharmony_ci pr_err("Rest of SLB cache entries:\n"); 2958c2ecf20Sopenharmony_ci for (i = n; i < SLB_CACHE_ENTRIES; i++) 2968c2ecf20Sopenharmony_ci pr_err("%02d EA[0-35]=%9x\n", i, get_paca()->slb_cache[i]); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_civoid slb_vmalloc_update(void) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * vmalloc is not bolted, so just have to flush non-bolted. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci slb_flush_and_restore_bolted(); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic bool preload_hit(struct thread_info *ti, unsigned long esid) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci unsigned char i; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci for (i = 0; i < ti->slb_preload_nr; i++) { 3128c2ecf20Sopenharmony_ci unsigned char idx; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; 3158c2ecf20Sopenharmony_ci if (esid == ti->slb_preload_esid[idx]) 3168c2ecf20Sopenharmony_ci return true; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci return false; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic bool preload_add(struct thread_info *ti, unsigned long ea) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci unsigned char idx; 3248c2ecf20Sopenharmony_ci unsigned long esid; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { 3278c2ecf20Sopenharmony_ci /* EAs are stored >> 28 so 256MB segments don't need clearing */ 3288c2ecf20Sopenharmony_ci if (ea & ESID_MASK_1T) 3298c2ecf20Sopenharmony_ci ea &= ESID_MASK_1T; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci esid = ea >> SID_SHIFT; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (preload_hit(ti, esid)) 3358c2ecf20Sopenharmony_ci return false; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci idx = (ti->slb_preload_tail + ti->slb_preload_nr) % SLB_PRELOAD_NR; 3388c2ecf20Sopenharmony_ci ti->slb_preload_esid[idx] = esid; 3398c2ecf20Sopenharmony_ci if (ti->slb_preload_nr == SLB_PRELOAD_NR) 3408c2ecf20Sopenharmony_ci ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; 3418c2ecf20Sopenharmony_ci else 3428c2ecf20Sopenharmony_ci ti->slb_preload_nr++; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return true; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic void preload_age(struct thread_info *ti) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci if (!ti->slb_preload_nr) 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci ti->slb_preload_nr--; 3528c2ecf20Sopenharmony_ci ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_civoid slb_setup_new_exec(void) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct thread_info *ti = current_thread_info(); 3588c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 3598c2ecf20Sopenharmony_ci unsigned long exec = 0x10000000; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci WARN_ON(irqs_disabled()); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * preload cache can only be used to determine whether a SLB 3658c2ecf20Sopenharmony_ci * entry exists if it does not start to overflow. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci if (ti->slb_preload_nr + 2 > SLB_PRELOAD_NR) 3688c2ecf20Sopenharmony_ci return; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci hard_irq_disable(); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * We have no good place to clear the slb preload cache on exec, 3748c2ecf20Sopenharmony_ci * flush_thread is about the earliest arch hook but that happens 3758c2ecf20Sopenharmony_ci * after we switch to the mm and have aleady preloaded the SLBEs. 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * For the most part that's probably okay to use entries from the 3788c2ecf20Sopenharmony_ci * previous exec, they will age out if unused. It may turn out to 3798c2ecf20Sopenharmony_ci * be an advantage to clear the cache before switching to it, 3808c2ecf20Sopenharmony_ci * however. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * preload some userspace segments into the SLB. 3858c2ecf20Sopenharmony_ci * Almost all 32 and 64bit PowerPC executables are linked at 3868c2ecf20Sopenharmony_ci * 0x10000000 so it makes sense to preload this segment. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci if (!is_kernel_addr(exec)) { 3898c2ecf20Sopenharmony_ci if (preload_add(ti, exec)) 3908c2ecf20Sopenharmony_ci slb_allocate_user(mm, exec); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Libraries and mmaps. */ 3948c2ecf20Sopenharmony_ci if (!is_kernel_addr(mm->mmap_base)) { 3958c2ecf20Sopenharmony_ci if (preload_add(ti, mm->mmap_base)) 3968c2ecf20Sopenharmony_ci slb_allocate_user(mm, mm->mmap_base); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* see switch_slb */ 4008c2ecf20Sopenharmony_ci asm volatile("isync" : : : "memory"); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci local_irq_enable(); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_civoid preload_new_slb_context(unsigned long start, unsigned long sp) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct thread_info *ti = current_thread_info(); 4088c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 4098c2ecf20Sopenharmony_ci unsigned long heap = mm->start_brk; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci WARN_ON(irqs_disabled()); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* see above */ 4148c2ecf20Sopenharmony_ci if (ti->slb_preload_nr + 3 > SLB_PRELOAD_NR) 4158c2ecf20Sopenharmony_ci return; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci hard_irq_disable(); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Userspace entry address. */ 4208c2ecf20Sopenharmony_ci if (!is_kernel_addr(start)) { 4218c2ecf20Sopenharmony_ci if (preload_add(ti, start)) 4228c2ecf20Sopenharmony_ci slb_allocate_user(mm, start); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Top of stack, grows down. */ 4268c2ecf20Sopenharmony_ci if (!is_kernel_addr(sp)) { 4278c2ecf20Sopenharmony_ci if (preload_add(ti, sp)) 4288c2ecf20Sopenharmony_ci slb_allocate_user(mm, sp); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Bottom of heap, grows up. */ 4328c2ecf20Sopenharmony_ci if (heap && !is_kernel_addr(heap)) { 4338c2ecf20Sopenharmony_ci if (preload_add(ti, heap)) 4348c2ecf20Sopenharmony_ci slb_allocate_user(mm, heap); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* see switch_slb */ 4388c2ecf20Sopenharmony_ci asm volatile("isync" : : : "memory"); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci local_irq_enable(); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void slb_cache_slbie_kernel(unsigned int index) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci unsigned long slbie_data = get_paca()->slb_cache[index]; 4468c2ecf20Sopenharmony_ci unsigned long ksp = get_paca()->kstack; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci slbie_data <<= SID_SHIFT; 4498c2ecf20Sopenharmony_ci slbie_data |= 0xc000000000000000ULL; 4508c2ecf20Sopenharmony_ci if ((ksp & slb_esid_mask(mmu_kernel_ssize)) == slbie_data) 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci slbie_data |= mmu_kernel_ssize << SLBIE_SSIZE_SHIFT; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci asm volatile("slbie %0" : : "r" (slbie_data)); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic void slb_cache_slbie_user(unsigned int index) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci unsigned long slbie_data = get_paca()->slb_cache[index]; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci slbie_data <<= SID_SHIFT; 4628c2ecf20Sopenharmony_ci slbie_data |= user_segment_size(slbie_data) << SLBIE_SSIZE_SHIFT; 4638c2ecf20Sopenharmony_ci slbie_data |= SLBIE_C; /* user slbs have C=1 */ 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci asm volatile("slbie %0" : : "r" (slbie_data)); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* Flush all user entries from the segment table of the current processor. */ 4698c2ecf20Sopenharmony_civoid switch_slb(struct task_struct *tsk, struct mm_struct *mm) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct thread_info *ti = task_thread_info(tsk); 4728c2ecf20Sopenharmony_ci unsigned char i; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * We need interrupts hard-disabled here, not just soft-disabled, 4768c2ecf20Sopenharmony_ci * so that a PMU interrupt can't occur, which might try to access 4778c2ecf20Sopenharmony_ci * user memory (to get a stack trace) and possible cause an SLB miss 4788c2ecf20Sopenharmony_ci * which would update the slb_cache/slb_cache_ptr fields in the PACA. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci hard_irq_disable(); 4818c2ecf20Sopenharmony_ci isync(); 4828c2ecf20Sopenharmony_ci if (stress_slb()) { 4838c2ecf20Sopenharmony_ci __slb_flush_and_restore_bolted(false); 4848c2ecf20Sopenharmony_ci isync(); 4858c2ecf20Sopenharmony_ci get_paca()->slb_cache_ptr = 0; 4868c2ecf20Sopenharmony_ci get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci } else if (cpu_has_feature(CPU_FTR_ARCH_300)) { 4898c2ecf20Sopenharmony_ci /* 4908c2ecf20Sopenharmony_ci * SLBIA IH=3 invalidates all Class=1 SLBEs and their 4918c2ecf20Sopenharmony_ci * associated lookaside structures, which matches what 4928c2ecf20Sopenharmony_ci * switch_slb wants. So ARCH_300 does not use the slb 4938c2ecf20Sopenharmony_ci * cache. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ci asm volatile(PPC_SLBIA(3)); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci unsigned long offset = get_paca()->slb_cache_ptr; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && 5018c2ecf20Sopenharmony_ci offset <= SLB_CACHE_ENTRIES) { 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * Could assert_slb_presence(true) here, but 5048c2ecf20Sopenharmony_ci * hypervisor or machine check could have come 5058c2ecf20Sopenharmony_ci * in and removed the entry at this point. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci for (i = 0; i < offset; i++) 5098c2ecf20Sopenharmony_ci slb_cache_slbie_user(i); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Workaround POWER5 < DD2.1 issue */ 5128c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_207S) && offset == 1) 5138c2ecf20Sopenharmony_ci slb_cache_slbie_user(0); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci } else { 5168c2ecf20Sopenharmony_ci /* Flush but retain kernel lookaside information */ 5178c2ecf20Sopenharmony_ci __slb_flush_and_restore_bolted(true); 5188c2ecf20Sopenharmony_ci isync(); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci get_paca()->slb_cache_ptr = 0; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci copy_mm_to_paca(mm); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* 5308c2ecf20Sopenharmony_ci * We gradually age out SLBs after a number of context switches to 5318c2ecf20Sopenharmony_ci * reduce reload overhead of unused entries (like we do with FP/VEC 5328c2ecf20Sopenharmony_ci * reload). Each time we wrap 256 switches, take an entry out of the 5338c2ecf20Sopenharmony_ci * SLB preload cache. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci tsk->thread.load_slb++; 5368c2ecf20Sopenharmony_ci if (!tsk->thread.load_slb) { 5378c2ecf20Sopenharmony_ci unsigned long pc = KSTK_EIP(tsk); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci preload_age(ti); 5408c2ecf20Sopenharmony_ci preload_add(ti, pc); 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci for (i = 0; i < ti->slb_preload_nr; i++) { 5448c2ecf20Sopenharmony_ci unsigned char idx; 5458c2ecf20Sopenharmony_ci unsigned long ea; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; 5488c2ecf20Sopenharmony_ci ea = (unsigned long)ti->slb_preload_esid[idx] << SID_SHIFT; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci slb_allocate_user(mm, ea); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * Synchronize slbmte preloads with possible subsequent user memory 5558c2ecf20Sopenharmony_ci * address accesses by the kernel (user mode won't happen until 5568c2ecf20Sopenharmony_ci * rfid, which is safe). 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci isync(); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_civoid slb_set_size(u16 size) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci mmu_slb_size = size; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_civoid slb_initialize(void) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci unsigned long linear_llp, vmalloc_llp, io_llp; 5698c2ecf20Sopenharmony_ci unsigned long lflags; 5708c2ecf20Sopenharmony_ci static int slb_encoding_inited; 5718c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 5728c2ecf20Sopenharmony_ci unsigned long vmemmap_llp; 5738c2ecf20Sopenharmony_ci#endif 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Prepare our SLB miss handler based on our page size */ 5768c2ecf20Sopenharmony_ci linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; 5778c2ecf20Sopenharmony_ci io_llp = mmu_psize_defs[mmu_io_psize].sllp; 5788c2ecf20Sopenharmony_ci vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp; 5798c2ecf20Sopenharmony_ci get_paca()->vmalloc_sllp = SLB_VSID_KERNEL | vmalloc_llp; 5808c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 5818c2ecf20Sopenharmony_ci vmemmap_llp = mmu_psize_defs[mmu_vmemmap_psize].sllp; 5828c2ecf20Sopenharmony_ci#endif 5838c2ecf20Sopenharmony_ci if (!slb_encoding_inited) { 5848c2ecf20Sopenharmony_ci slb_encoding_inited = 1; 5858c2ecf20Sopenharmony_ci pr_devel("SLB: linear LLP = %04lx\n", linear_llp); 5868c2ecf20Sopenharmony_ci pr_devel("SLB: io LLP = %04lx\n", io_llp); 5878c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 5888c2ecf20Sopenharmony_ci pr_devel("SLB: vmemmap LLP = %04lx\n", vmemmap_llp); 5898c2ecf20Sopenharmony_ci#endif 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci get_paca()->stab_rr = SLB_NUM_BOLTED - 1; 5938c2ecf20Sopenharmony_ci get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; 5948c2ecf20Sopenharmony_ci get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci lflags = SLB_VSID_KERNEL | linear_llp; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Invalidate the entire SLB (even entry 0) & all the ERATS */ 5998c2ecf20Sopenharmony_ci asm volatile("isync":::"memory"); 6008c2ecf20Sopenharmony_ci asm volatile("slbmte %0,%0"::"r" (0) : "memory"); 6018c2ecf20Sopenharmony_ci asm volatile("isync; slbia; isync":::"memory"); 6028c2ecf20Sopenharmony_ci create_shadowed_slbe(PAGE_OFFSET, mmu_kernel_ssize, lflags, LINEAR_INDEX); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * For the boot cpu, we're running on the stack in init_thread_union, 6068c2ecf20Sopenharmony_ci * which is in the first segment of the linear mapping, and also 6078c2ecf20Sopenharmony_ci * get_paca()->kstack hasn't been initialized yet. 6088c2ecf20Sopenharmony_ci * For secondary cpus, we need to bolt the kernel stack entry now. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_ci slb_shadow_clear(KSTACK_INDEX); 6118c2ecf20Sopenharmony_ci if (raw_smp_processor_id() != boot_cpuid && 6128c2ecf20Sopenharmony_ci (get_paca()->kstack & slb_esid_mask(mmu_kernel_ssize)) > PAGE_OFFSET) 6138c2ecf20Sopenharmony_ci create_shadowed_slbe(get_paca()->kstack, 6148c2ecf20Sopenharmony_ci mmu_kernel_ssize, lflags, KSTACK_INDEX); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci asm volatile("isync":::"memory"); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void slb_cache_update(unsigned long esid_data) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci int slb_cache_index; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_300)) 6248c2ecf20Sopenharmony_ci return; /* ISAv3.0B and later does not use slb_cache */ 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (stress_slb()) 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * Now update slb cache entries 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci slb_cache_index = local_paca->slb_cache_ptr; 6338c2ecf20Sopenharmony_ci if (slb_cache_index < SLB_CACHE_ENTRIES) { 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * We have space in slb cache for optimized switch_slb(). 6368c2ecf20Sopenharmony_ci * Top 36 bits from esid_data as per ISA 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci local_paca->slb_cache[slb_cache_index++] = esid_data >> SID_SHIFT; 6398c2ecf20Sopenharmony_ci local_paca->slb_cache_ptr++; 6408c2ecf20Sopenharmony_ci } else { 6418c2ecf20Sopenharmony_ci /* 6428c2ecf20Sopenharmony_ci * Our cache is full and the current cache content strictly 6438c2ecf20Sopenharmony_ci * doesn't indicate the active SLB conents. Bump the ptr 6448c2ecf20Sopenharmony_ci * so that switch_slb() will ignore the cache. 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci local_paca->slb_cache_ptr = SLB_CACHE_ENTRIES + 1; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic enum slb_index alloc_slb_index(bool kernel) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci enum slb_index index; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * The allocation bitmaps can become out of synch with the SLB 6568c2ecf20Sopenharmony_ci * when the _switch code does slbie when bolting a new stack 6578c2ecf20Sopenharmony_ci * segment and it must not be anywhere else in the SLB. This leaves 6588c2ecf20Sopenharmony_ci * a kernel allocated entry that is unused in the SLB. With very 6598c2ecf20Sopenharmony_ci * large systems or small segment sizes, the bitmaps could slowly 6608c2ecf20Sopenharmony_ci * fill with these entries. They will eventually be cleared out 6618c2ecf20Sopenharmony_ci * by the round robin allocator in that case, so it's probably not 6628c2ecf20Sopenharmony_ci * worth accounting for. 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* 6668c2ecf20Sopenharmony_ci * SLBs beyond 32 entries are allocated with stab_rr only 6678c2ecf20Sopenharmony_ci * POWER7/8/9 have 32 SLB entries, this could be expanded if a 6688c2ecf20Sopenharmony_ci * future CPU has more. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci if (local_paca->slb_used_bitmap != U32_MAX) { 6718c2ecf20Sopenharmony_ci index = ffz(local_paca->slb_used_bitmap); 6728c2ecf20Sopenharmony_ci local_paca->slb_used_bitmap |= 1U << index; 6738c2ecf20Sopenharmony_ci if (kernel) 6748c2ecf20Sopenharmony_ci local_paca->slb_kern_bitmap |= 1U << index; 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ 6778c2ecf20Sopenharmony_ci index = local_paca->stab_rr; 6788c2ecf20Sopenharmony_ci if (index < (mmu_slb_size - 1)) 6798c2ecf20Sopenharmony_ci index++; 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci index = SLB_NUM_BOLTED; 6828c2ecf20Sopenharmony_ci local_paca->stab_rr = index; 6838c2ecf20Sopenharmony_ci if (index < 32) { 6848c2ecf20Sopenharmony_ci if (kernel) 6858c2ecf20Sopenharmony_ci local_paca->slb_kern_bitmap |= 1U << index; 6868c2ecf20Sopenharmony_ci else 6878c2ecf20Sopenharmony_ci local_paca->slb_kern_bitmap &= ~(1U << index); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci BUG_ON(index < SLB_NUM_BOLTED); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return index; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic long slb_insert_entry(unsigned long ea, unsigned long context, 6968c2ecf20Sopenharmony_ci unsigned long flags, int ssize, bool kernel) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned long vsid; 6998c2ecf20Sopenharmony_ci unsigned long vsid_data, esid_data; 7008c2ecf20Sopenharmony_ci enum slb_index index; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci vsid = get_vsid(context, ea, ssize); 7038c2ecf20Sopenharmony_ci if (!vsid) 7048c2ecf20Sopenharmony_ci return -EFAULT; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * There must not be a kernel SLB fault in alloc_slb_index or before 7088c2ecf20Sopenharmony_ci * slbmte here or the allocation bitmaps could get out of whack with 7098c2ecf20Sopenharmony_ci * the SLB. 7108c2ecf20Sopenharmony_ci * 7118c2ecf20Sopenharmony_ci * User SLB faults or preloads take this path which might get inlined 7128c2ecf20Sopenharmony_ci * into the caller, so add compiler barriers here to ensure unsafe 7138c2ecf20Sopenharmony_ci * memory accesses do not come between. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci barrier(); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci index = alloc_slb_index(kernel); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci vsid_data = __mk_vsid_data(vsid, ssize, flags); 7208c2ecf20Sopenharmony_ci esid_data = mk_esid_data(ea, ssize, index); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* 7238c2ecf20Sopenharmony_ci * No need for an isync before or after this slbmte. The exception 7248c2ecf20Sopenharmony_ci * we enter with and the rfid we exit with are context synchronizing. 7258c2ecf20Sopenharmony_ci * User preloads should add isync afterwards in case the kernel 7268c2ecf20Sopenharmony_ci * accesses user memory before it returns to userspace with rfid. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci assert_slb_presence(false, ea); 7298c2ecf20Sopenharmony_ci if (stress_slb()) { 7308c2ecf20Sopenharmony_ci int slb_cache_index = local_paca->slb_cache_ptr; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* 7338c2ecf20Sopenharmony_ci * stress_slb() does not use slb cache, repurpose as a 7348c2ecf20Sopenharmony_ci * cache of inserted (non-bolted) kernel SLB entries. All 7358c2ecf20Sopenharmony_ci * non-bolted kernel entries are flushed on any user fault, 7368c2ecf20Sopenharmony_ci * or if there are already 3 non-boled kernel entries. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci BUILD_BUG_ON(SLB_CACHE_ENTRIES < 3); 7398c2ecf20Sopenharmony_ci if (!kernel || slb_cache_index == 3) { 7408c2ecf20Sopenharmony_ci int i; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci for (i = 0; i < slb_cache_index; i++) 7438c2ecf20Sopenharmony_ci slb_cache_slbie_kernel(i); 7448c2ecf20Sopenharmony_ci slb_cache_index = 0; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (kernel) 7488c2ecf20Sopenharmony_ci local_paca->slb_cache[slb_cache_index++] = esid_data >> SID_SHIFT; 7498c2ecf20Sopenharmony_ci local_paca->slb_cache_ptr = slb_cache_index; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data)); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci barrier(); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (!kernel) 7568c2ecf20Sopenharmony_ci slb_cache_update(esid_data); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return 0; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic long slb_allocate_kernel(unsigned long ea, unsigned long id) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci unsigned long context; 7648c2ecf20Sopenharmony_ci unsigned long flags; 7658c2ecf20Sopenharmony_ci int ssize; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (id == LINEAR_MAP_REGION_ID) { 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* We only support upto H_MAX_PHYSMEM_BITS */ 7708c2ecf20Sopenharmony_ci if ((ea & EA_MASK) > (1UL << H_MAX_PHYSMEM_BITS)) 7718c2ecf20Sopenharmony_ci return -EFAULT; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 7768c2ecf20Sopenharmony_ci } else if (id == VMEMMAP_REGION_ID) { 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (ea >= H_VMEMMAP_END) 7798c2ecf20Sopenharmony_ci return -EFAULT; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmemmap_psize].sllp; 7828c2ecf20Sopenharmony_ci#endif 7838c2ecf20Sopenharmony_ci } else if (id == VMALLOC_REGION_ID) { 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (ea >= H_VMALLOC_END) 7868c2ecf20Sopenharmony_ci return -EFAULT; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci flags = local_paca->vmalloc_sllp; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci } else if (id == IO_REGION_ID) { 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (ea >= H_KERN_IO_END) 7938c2ecf20Sopenharmony_ci return -EFAULT; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_io_psize].sllp; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci } else { 7988c2ecf20Sopenharmony_ci return -EFAULT; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ssize = MMU_SEGSIZE_1T; 8028c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) 8038c2ecf20Sopenharmony_ci ssize = MMU_SEGSIZE_256M; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci context = get_kernel_context(ea); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci return slb_insert_entry(ea, context, flags, ssize, true); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic long slb_allocate_user(struct mm_struct *mm, unsigned long ea) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci unsigned long context; 8138c2ecf20Sopenharmony_ci unsigned long flags; 8148c2ecf20Sopenharmony_ci int bpsize; 8158c2ecf20Sopenharmony_ci int ssize; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* 8188c2ecf20Sopenharmony_ci * consider this as bad access if we take a SLB miss 8198c2ecf20Sopenharmony_ci * on an address above addr limit. 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci if (ea >= mm_ctx_slb_addr_limit(&mm->context)) 8228c2ecf20Sopenharmony_ci return -EFAULT; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci context = get_user_context(&mm->context, ea); 8258c2ecf20Sopenharmony_ci if (!context) 8268c2ecf20Sopenharmony_ci return -EFAULT; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (unlikely(ea >= H_PGTABLE_RANGE)) { 8298c2ecf20Sopenharmony_ci WARN_ON(1); 8308c2ecf20Sopenharmony_ci return -EFAULT; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ssize = user_segment_size(ea); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci bpsize = get_slice_psize(mm, ea); 8368c2ecf20Sopenharmony_ci flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return slb_insert_entry(ea, context, flags, ssize, false); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cilong do_slb_fault(struct pt_regs *regs, unsigned long ea) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci unsigned long id = get_region_id(ea); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* IRQs are not reconciled here, so can't check irqs_disabled */ 8468c2ecf20Sopenharmony_ci VM_WARN_ON(mfmsr() & MSR_EE); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (unlikely(!(regs->msr & MSR_RI))) 8498c2ecf20Sopenharmony_ci return -EINVAL; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * SLB kernel faults must be very careful not to touch anything 8538c2ecf20Sopenharmony_ci * that is not bolted. E.g., PACA and global variables are okay, 8548c2ecf20Sopenharmony_ci * mm->context stuff is not. 8558c2ecf20Sopenharmony_ci * 8568c2ecf20Sopenharmony_ci * SLB user faults can access all of kernel memory, but must be 8578c2ecf20Sopenharmony_ci * careful not to touch things like IRQ state because it is not 8588c2ecf20Sopenharmony_ci * "reconciled" here. The difficulty is that we must use 8598c2ecf20Sopenharmony_ci * fast_exception_return to return from kernel SLB faults without 8608c2ecf20Sopenharmony_ci * looking at possible non-bolted memory. We could test user vs 8618c2ecf20Sopenharmony_ci * kernel faults in the interrupt handler asm and do a full fault, 8628c2ecf20Sopenharmony_ci * reconcile, ret_from_except for user faults which would make them 8638c2ecf20Sopenharmony_ci * first class kernel code. But for performance it's probably nicer 8648c2ecf20Sopenharmony_ci * if they go via fast_exception_return too. 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci if (id >= LINEAR_MAP_REGION_ID) { 8678c2ecf20Sopenharmony_ci long err; 8688c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VM 8698c2ecf20Sopenharmony_ci /* Catch recursive kernel SLB faults. */ 8708c2ecf20Sopenharmony_ci BUG_ON(local_paca->in_kernel_slb_handler); 8718c2ecf20Sopenharmony_ci local_paca->in_kernel_slb_handler = 1; 8728c2ecf20Sopenharmony_ci#endif 8738c2ecf20Sopenharmony_ci err = slb_allocate_kernel(ea, id); 8748c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VM 8758c2ecf20Sopenharmony_ci local_paca->in_kernel_slb_handler = 0; 8768c2ecf20Sopenharmony_ci#endif 8778c2ecf20Sopenharmony_ci return err; 8788c2ecf20Sopenharmony_ci } else { 8798c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 8808c2ecf20Sopenharmony_ci long err; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (unlikely(!mm)) 8838c2ecf20Sopenharmony_ci return -EFAULT; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci err = slb_allocate_user(mm, ea); 8868c2ecf20Sopenharmony_ci if (!err) 8878c2ecf20Sopenharmony_ci preload_add(current_thread_info(), ea); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return err; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_civoid do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci if (err == -EFAULT) { 8968c2ecf20Sopenharmony_ci if (user_mode(regs)) 8978c2ecf20Sopenharmony_ci _exception(SIGSEGV, regs, SEGV_BNDERR, ea); 8988c2ecf20Sopenharmony_ci else 8998c2ecf20Sopenharmony_ci bad_page_fault(regs, ea, SIGSEGV); 9008c2ecf20Sopenharmony_ci } else if (err == -EINVAL) { 9018c2ecf20Sopenharmony_ci unrecoverable_exception(regs); 9028c2ecf20Sopenharmony_ci } else { 9038c2ecf20Sopenharmony_ci BUG(); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci} 906