12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 217312f25SChristophe Leroy /* 317312f25SChristophe Leroy * This file contains the routines for handling the MMU on those 417312f25SChristophe Leroy * PowerPC implementations where the MMU substantially follows the 517312f25SChristophe Leroy * architecture specification. This includes the 6xx, 7xx, 7xxx, 617312f25SChristophe Leroy * and 8260 implementations but excludes the 8xx and 4xx. 717312f25SChristophe Leroy * -- paulus 817312f25SChristophe Leroy * 917312f25SChristophe Leroy * Derived from arch/ppc/mm/init.c: 1017312f25SChristophe Leroy * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 1117312f25SChristophe Leroy * 1217312f25SChristophe Leroy * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 1317312f25SChristophe Leroy * and Cort Dougan (PReP) (cort@cs.nmt.edu) 1417312f25SChristophe Leroy * Copyright (C) 1996 Paul Mackerras 1517312f25SChristophe Leroy * 1617312f25SChristophe Leroy * Derived from "arch/i386/mm/init.c" 1717312f25SChristophe Leroy * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 1817312f25SChristophe Leroy */ 1917312f25SChristophe Leroy 2017312f25SChristophe Leroy #include <linux/mm.h> 2117312f25SChristophe Leroy #include <linux/init.h> 2217312f25SChristophe Leroy #include <linux/export.h> 2317312f25SChristophe Leroy 2417312f25SChristophe Leroy #include <asm/mmu_context.h> 2517312f25SChristophe Leroy 2617312f25SChristophe Leroy /* 27863771a2SChristophe Leroy * Room for two PTE pointers, usually the kernel and current user pointers 28863771a2SChristophe Leroy * to their respective root page table. 29863771a2SChristophe Leroy */ 30863771a2SChristophe Leroy void *abatron_pteptrs[2]; 31863771a2SChristophe Leroy 32863771a2SChristophe Leroy /* 3317312f25SChristophe Leroy * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs 3417312f25SChristophe Leroy * (virtual segment identifiers) for each context. Although the 3517312f25SChristophe Leroy * hardware supports 24-bit VSIDs, and thus >1 million contexts, 3617312f25SChristophe Leroy * we only use 32,768 of them. That is ample, since there can be 3717312f25SChristophe Leroy * at most around 30,000 tasks in the system anyway, and it means 3817312f25SChristophe Leroy * that we can use a bitmap to indicate which contexts are in use. 3917312f25SChristophe Leroy * Using a bitmap means that we entirely avoid all of the problems 4017312f25SChristophe Leroy * that we used to have when the context number overflowed, 4117312f25SChristophe Leroy * particularly on SMP systems. 4217312f25SChristophe Leroy * -- paulus. 4317312f25SChristophe Leroy */ 4417312f25SChristophe Leroy #define NO_CONTEXT ((unsigned long) -1) 4517312f25SChristophe Leroy #define LAST_CONTEXT 32767 4617312f25SChristophe Leroy #define FIRST_CONTEXT 1 4717312f25SChristophe Leroy 4817312f25SChristophe Leroy static unsigned long next_mmu_context; 4917312f25SChristophe Leroy static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; 5017312f25SChristophe Leroy 5117312f25SChristophe Leroy unsigned long __init_new_context(void) 5217312f25SChristophe Leroy { 5317312f25SChristophe Leroy unsigned long ctx = next_mmu_context; 5417312f25SChristophe Leroy 5517312f25SChristophe Leroy while (test_and_set_bit(ctx, context_map)) { 5617312f25SChristophe Leroy ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); 5717312f25SChristophe Leroy if (ctx > LAST_CONTEXT) 5817312f25SChristophe Leroy ctx = 0; 5917312f25SChristophe Leroy } 6017312f25SChristophe Leroy next_mmu_context = (ctx + 1) & LAST_CONTEXT; 6117312f25SChristophe Leroy 6217312f25SChristophe Leroy return ctx; 6317312f25SChristophe Leroy } 6417312f25SChristophe Leroy EXPORT_SYMBOL_GPL(__init_new_context); 6517312f25SChristophe Leroy 6617312f25SChristophe Leroy /* 6717312f25SChristophe Leroy * Set up the context for a new address space. 6817312f25SChristophe Leroy */ 6917312f25SChristophe Leroy int init_new_context(struct task_struct *t, struct mm_struct *mm) 7017312f25SChristophe Leroy { 7117312f25SChristophe Leroy mm->context.id = __init_new_context(); 72*70428da9SChristophe Leroy mm->context.sr0 = CTX_TO_VSID(mm->context.id, 0); 73*70428da9SChristophe Leroy 74*70428da9SChristophe Leroy if (!kuep_is_disabled()) 75*70428da9SChristophe Leroy mm->context.sr0 |= SR_NX; 76*70428da9SChristophe Leroy if (!kuap_is_disabled()) 77*70428da9SChristophe Leroy mm->context.sr0 |= SR_KS; 7817312f25SChristophe Leroy 7917312f25SChristophe Leroy return 0; 8017312f25SChristophe Leroy } 8117312f25SChristophe Leroy 8217312f25SChristophe Leroy /* 8317312f25SChristophe Leroy * Free a context ID. Make sure to call this with preempt disabled! 8417312f25SChristophe Leroy */ 8517312f25SChristophe Leroy void __destroy_context(unsigned long ctx) 8617312f25SChristophe Leroy { 8717312f25SChristophe Leroy clear_bit(ctx, context_map); 8817312f25SChristophe Leroy } 8917312f25SChristophe Leroy EXPORT_SYMBOL_GPL(__destroy_context); 9017312f25SChristophe Leroy 9117312f25SChristophe Leroy /* 9217312f25SChristophe Leroy * We're finished using the context for an address space. 9317312f25SChristophe Leroy */ 9417312f25SChristophe Leroy void destroy_context(struct mm_struct *mm) 9517312f25SChristophe Leroy { 9617312f25SChristophe Leroy preempt_disable(); 9717312f25SChristophe Leroy if (mm->context.id != NO_CONTEXT) { 9817312f25SChristophe Leroy __destroy_context(mm->context.id); 9917312f25SChristophe Leroy mm->context.id = NO_CONTEXT; 10017312f25SChristophe Leroy } 10117312f25SChristophe Leroy preempt_enable(); 10217312f25SChristophe Leroy } 10317312f25SChristophe Leroy 10417312f25SChristophe Leroy /* 10517312f25SChristophe Leroy * Initialize the context management stuff. 10617312f25SChristophe Leroy */ 10717312f25SChristophe Leroy void __init mmu_context_init(void) 10817312f25SChristophe Leroy { 10917312f25SChristophe Leroy /* Reserve context 0 for kernel use */ 11017312f25SChristophe Leroy context_map[0] = (1 << FIRST_CONTEXT) - 1; 11117312f25SChristophe Leroy next_mmu_context = FIRST_CONTEXT; 11217312f25SChristophe Leroy } 113863771a2SChristophe Leroy 114863771a2SChristophe Leroy void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) 115863771a2SChristophe Leroy { 116863771a2SChristophe Leroy long id = next->context.id; 117863771a2SChristophe Leroy 118863771a2SChristophe Leroy if (id < 0) 119863771a2SChristophe Leroy panic("mm_struct %p has no context ID", next); 120863771a2SChristophe Leroy 121863771a2SChristophe Leroy isync(); 122863771a2SChristophe Leroy 123*70428da9SChristophe Leroy update_user_segments(next->context.sr0); 124863771a2SChristophe Leroy 125863771a2SChristophe Leroy if (IS_ENABLED(CONFIG_BDI_SWITCH)) 126863771a2SChristophe Leroy abatron_pteptrs[1] = next->pgd; 127863771a2SChristophe Leroy 128863771a2SChristophe Leroy if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) 129863771a2SChristophe Leroy mtspr(SPRN_SDR1, rol32(__pa(next->pgd), 4) & 0xffff01ff); 130863771a2SChristophe Leroy 131863771a2SChristophe Leroy mb(); /* sync */ 132863771a2SChristophe Leroy isync(); 133863771a2SChristophe Leroy } 134863771a2SChristophe Leroy EXPORT_SYMBOL(switch_mmu_context); 135