1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/mm.h>
21#include <linux/init.h>
22#include <linux/export.h>
23
24#include <asm/mmu_context.h>
25
26
27
28
29
30void *abatron_pteptrs[2];
31
32
33
34
35
36
37
38
39
40
41
42
43
44#define NO_CONTEXT ((unsigned long) -1)
45#define LAST_CONTEXT 32767
46#define FIRST_CONTEXT 1
47
48static unsigned long next_mmu_context;
49static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
50
51unsigned long __init_new_context(void)
52{
53 unsigned long ctx = next_mmu_context;
54
55 while (test_and_set_bit(ctx, context_map)) {
56 ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
57 if (ctx > LAST_CONTEXT)
58 ctx = 0;
59 }
60 next_mmu_context = (ctx + 1) & LAST_CONTEXT;
61
62 return ctx;
63}
64EXPORT_SYMBOL_GPL(__init_new_context);
65
66
67
68
69int init_new_context(struct task_struct *t, struct mm_struct *mm)
70{
71 mm->context.id = __init_new_context();
72
73 return 0;
74}
75
76
77
78
79void __destroy_context(unsigned long ctx)
80{
81 clear_bit(ctx, context_map);
82}
83EXPORT_SYMBOL_GPL(__destroy_context);
84
85
86
87
88void destroy_context(struct mm_struct *mm)
89{
90 preempt_disable();
91 if (mm->context.id != NO_CONTEXT) {
92 __destroy_context(mm->context.id);
93 mm->context.id = NO_CONTEXT;
94 }
95 preempt_enable();
96}
97
98
99
100
101void __init mmu_context_init(void)
102{
103
104 context_map[0] = (1 << FIRST_CONTEXT) - 1;
105 next_mmu_context = FIRST_CONTEXT;
106}
107
108void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
109{
110 long id = next->context.id;
111 unsigned long val;
112
113 if (id < 0)
114 panic("mm_struct %p has no context ID", next);
115
116 isync();
117
118 val = CTX_TO_VSID(id, 0);
119 if (!kuep_is_disabled())
120 val |= SR_NX;
121 if (!kuap_is_disabled())
122 val |= SR_KS;
123
124 update_user_segments(val);
125
126 if (IS_ENABLED(CONFIG_BDI_SWITCH))
127 abatron_pteptrs[1] = next->pgd;
128
129 if (!mmu_has_feature(MMU_FTR_HPTE_TABLE))
130 mtspr(SPRN_SDR1, rol32(__pa(next->pgd), 4) & 0xffff01ff);
131
132 mb();
133 isync();
134}
135EXPORT_SYMBOL(switch_mmu_context);
136