162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file contains the routines for handling the MMU on those 462306a36Sopenharmony_ci * PowerPC implementations where the MMU substantially follows the 562306a36Sopenharmony_ci * architecture specification. This includes the 6xx, 7xx, 7xxx, 662306a36Sopenharmony_ci * and 8260 implementations but excludes the 8xx and 4xx. 762306a36Sopenharmony_ci * -- paulus 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Derived from arch/ppc/mm/init.c: 1062306a36Sopenharmony_ci * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 1362306a36Sopenharmony_ci * and Cort Dougan (PReP) (cort@cs.nmt.edu) 1462306a36Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Derived from "arch/i386/mm/init.c" 1762306a36Sopenharmony_ci * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/mm.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/export.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm/mmu_context.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Room for two PTE pointers, usually the kernel and current user pointers 2862306a36Sopenharmony_ci * to their respective root page table. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_civoid *abatron_pteptrs[2]; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs 3462306a36Sopenharmony_ci * (virtual segment identifiers) for each context. Although the 3562306a36Sopenharmony_ci * hardware supports 24-bit VSIDs, and thus >1 million contexts, 3662306a36Sopenharmony_ci * we only use 32,768 of them. That is ample, since there can be 3762306a36Sopenharmony_ci * at most around 30,000 tasks in the system anyway, and it means 3862306a36Sopenharmony_ci * that we can use a bitmap to indicate which contexts are in use. 3962306a36Sopenharmony_ci * Using a bitmap means that we entirely avoid all of the problems 4062306a36Sopenharmony_ci * that we used to have when the context number overflowed, 4162306a36Sopenharmony_ci * particularly on SMP systems. 4262306a36Sopenharmony_ci * -- paulus. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci#define NO_CONTEXT ((unsigned long) -1) 4562306a36Sopenharmony_ci#define LAST_CONTEXT 32767 4662306a36Sopenharmony_ci#define FIRST_CONTEXT 1 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic unsigned long next_mmu_context; 4962306a36Sopenharmony_cistatic unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciunsigned long __init_new_context(void) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned long ctx = next_mmu_context; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci while (test_and_set_bit(ctx, context_map)) { 5662306a36Sopenharmony_ci ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); 5762306a36Sopenharmony_ci if (ctx > LAST_CONTEXT) 5862306a36Sopenharmony_ci ctx = 0; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci next_mmu_context = (ctx + 1) & LAST_CONTEXT; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return ctx; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__init_new_context); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * Set up the context for a new address space. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ciint init_new_context(struct task_struct *t, struct mm_struct *mm) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci mm->context.id = __init_new_context(); 7262306a36Sopenharmony_ci mm->context.sr0 = CTX_TO_VSID(mm->context.id, 0); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC_KUEP)) 7562306a36Sopenharmony_ci mm->context.sr0 |= SR_NX; 7662306a36Sopenharmony_ci if (!kuap_is_disabled()) 7762306a36Sopenharmony_ci mm->context.sr0 |= SR_KS; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * Free a context ID. Make sure to call this with preempt disabled! 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_civoid __destroy_context(unsigned long ctx) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci clear_bit(ctx, context_map); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__destroy_context); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * We're finished using the context for an address space. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_civoid destroy_context(struct mm_struct *mm) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci preempt_disable(); 9762306a36Sopenharmony_ci if (mm->context.id != NO_CONTEXT) { 9862306a36Sopenharmony_ci __destroy_context(mm->context.id); 9962306a36Sopenharmony_ci mm->context.id = NO_CONTEXT; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci preempt_enable(); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * Initialize the context management stuff. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_civoid __init mmu_context_init(void) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci /* Reserve context 0 for kernel use */ 11062306a36Sopenharmony_ci context_map[0] = (1 << FIRST_CONTEXT) - 1; 11162306a36Sopenharmony_ci next_mmu_context = FIRST_CONTEXT; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_civoid switch_mmu_context(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci long id = next->context.id; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (id < 0) 11962306a36Sopenharmony_ci panic("mm_struct %p has no context ID", next); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci isync(); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci update_user_segments(next->context.sr0); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BDI_SWITCH)) 12662306a36Sopenharmony_ci abatron_pteptrs[1] = next->pgd; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) 12962306a36Sopenharmony_ci mtspr(SPRN_SDR1, rol32(__pa(next->pgd), 4) & 0xffff01ff); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci mb(); /* sync */ 13262306a36Sopenharmony_ci isync(); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL(switch_mmu_context); 135