Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * This file contains the routines for handling the MMU on those
0004  * PowerPC implementations where the MMU substantially follows the
0005  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
0006  * and 8260 implementations but excludes the 8xx and 4xx.
0007  *  -- paulus
0008  *
0009  *  Derived from arch/ppc/mm/init.c:
0010  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
0011  *
0012  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
0013  *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
0014  *    Copyright (C) 1996 Paul Mackerras
0015  *
0016  *  Derived from "arch/i386/mm/init.c"
0017  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
0018  */
0019 
0020 #include <linux/mm.h>
0021 #include <linux/init.h>
0022 #include <linux/export.h>
0023 
0024 #include <asm/mmu_context.h>
0025 
0026 /*
0027  * Room for two PTE pointers, usually the kernel and current user pointers
0028  * to their respective root page table.
0029  */
0030 void *abatron_pteptrs[2];
0031 
0032 /*
0033  * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
0034  * (virtual segment identifiers) for each context.  Although the
0035  * hardware supports 24-bit VSIDs, and thus >1 million contexts,
0036  * we only use 32,768 of them.  That is ample, since there can be
0037  * at most around 30,000 tasks in the system anyway, and it means
0038  * that we can use a bitmap to indicate which contexts are in use.
0039  * Using a bitmap means that we entirely avoid all of the problems
0040  * that we used to have when the context number overflowed,
0041  * particularly on SMP systems.
0042  *  -- paulus.
0043  */
0044 #define NO_CONTEXT          ((unsigned long) -1)
0045 #define LAST_CONTEXT        32767
0046 #define FIRST_CONTEXT       1
0047 
0048 static unsigned long next_mmu_context;
0049 static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
0050 
0051 unsigned long __init_new_context(void)
0052 {
0053     unsigned long ctx = next_mmu_context;
0054 
0055     while (test_and_set_bit(ctx, context_map)) {
0056         ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
0057         if (ctx > LAST_CONTEXT)
0058             ctx = 0;
0059     }
0060     next_mmu_context = (ctx + 1) & LAST_CONTEXT;
0061 
0062     return ctx;
0063 }
0064 EXPORT_SYMBOL_GPL(__init_new_context);
0065 
0066 /*
0067  * Set up the context for a new address space.
0068  */
0069 int init_new_context(struct task_struct *t, struct mm_struct *mm)
0070 {
0071     mm->context.id = __init_new_context();
0072     mm->context.sr0 = CTX_TO_VSID(mm->context.id, 0);
0073 
0074     if (!kuep_is_disabled())
0075         mm->context.sr0 |= SR_NX;
0076     if (!kuap_is_disabled())
0077         mm->context.sr0 |= SR_KS;
0078 
0079     return 0;
0080 }
0081 
0082 /*
0083  * Free a context ID. Make sure to call this with preempt disabled!
0084  */
0085 void __destroy_context(unsigned long ctx)
0086 {
0087     clear_bit(ctx, context_map);
0088 }
0089 EXPORT_SYMBOL_GPL(__destroy_context);
0090 
0091 /*
0092  * We're finished using the context for an address space.
0093  */
0094 void destroy_context(struct mm_struct *mm)
0095 {
0096     preempt_disable();
0097     if (mm->context.id != NO_CONTEXT) {
0098         __destroy_context(mm->context.id);
0099         mm->context.id = NO_CONTEXT;
0100     }
0101     preempt_enable();
0102 }
0103 
0104 /*
0105  * Initialize the context management stuff.
0106  */
0107 void __init mmu_context_init(void)
0108 {
0109     /* Reserve context 0 for kernel use */
0110     context_map[0] = (1 << FIRST_CONTEXT) - 1;
0111     next_mmu_context = FIRST_CONTEXT;
0112 }
0113 
0114 void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
0115 {
0116     long id = next->context.id;
0117 
0118     if (id < 0)
0119         panic("mm_struct %p has no context ID", next);
0120 
0121     isync();
0122 
0123     update_user_segments(next->context.sr0);
0124 
0125     if (IS_ENABLED(CONFIG_BDI_SWITCH))
0126         abatron_pteptrs[1] = next->pgd;
0127 
0128     if (!mmu_has_feature(MMU_FTR_HPTE_TABLE))
0129         mtspr(SPRN_SDR1, rol32(__pa(next->pgd), 4) & 0xffff01ff);
0130 
0131     mb();   /* sync */
0132     isync();
0133 }
0134 EXPORT_SYMBOL(switch_mmu_context);