xref: /OK3568_Linux_fs/kernel/arch/arm/mm/context.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/arch/arm/mm/context.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
6*4882a593Smuzhiyun  *  Copyright (C) 2012 ARM Limited
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  Author: Will Deacon <will.deacon@arm.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/sched.h>
12*4882a593Smuzhiyun #include <linux/mm.h>
13*4882a593Smuzhiyun #include <linux/smp.h>
14*4882a593Smuzhiyun #include <linux/percpu.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <asm/mmu_context.h>
17*4882a593Smuzhiyun #include <asm/smp_plat.h>
18*4882a593Smuzhiyun #include <asm/thread_notify.h>
19*4882a593Smuzhiyun #include <asm/tlbflush.h>
20*4882a593Smuzhiyun #include <asm/proc-fns.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * On ARMv6, we have the following structure in the Context ID:
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * 31                         7          0
26*4882a593Smuzhiyun  * +-------------------------+-----------+
27*4882a593Smuzhiyun  * |      process ID         |   ASID    |
28*4882a593Smuzhiyun  * +-------------------------+-----------+
29*4882a593Smuzhiyun  * |              context ID             |
30*4882a593Smuzhiyun  * +-------------------------------------+
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * The ASID is used to tag entries in the CPU caches and TLBs.
33*4882a593Smuzhiyun  * The context ID is used by debuggers and trace logic, and
34*4882a593Smuzhiyun  * should be unique within all running processes.
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * In big endian operation, the two 32 bit words are swapped if accessed
37*4882a593Smuzhiyun  * by non-64-bit operations.
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun #define ASID_FIRST_VERSION	(1ULL << ASID_BITS)
40*4882a593Smuzhiyun #define NUM_USER_ASIDS		ASID_FIRST_VERSION
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
43*4882a593Smuzhiyun static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION);
44*4882a593Smuzhiyun static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static DEFINE_PER_CPU(atomic64_t, active_asids);
47*4882a593Smuzhiyun static DEFINE_PER_CPU(u64, reserved_asids);
48*4882a593Smuzhiyun static cpumask_t tlb_flush_pending;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #ifdef CONFIG_ARM_ERRATA_798181
a15_erratum_get_cpumask(int this_cpu,struct mm_struct * mm,cpumask_t * mask)51*4882a593Smuzhiyun void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
52*4882a593Smuzhiyun 			     cpumask_t *mask)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	int cpu;
55*4882a593Smuzhiyun 	unsigned long flags;
56*4882a593Smuzhiyun 	u64 context_id, asid;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&cpu_asid_lock, flags);
59*4882a593Smuzhiyun 	context_id = mm->context.id.counter;
60*4882a593Smuzhiyun 	for_each_online_cpu(cpu) {
61*4882a593Smuzhiyun 		if (cpu == this_cpu)
62*4882a593Smuzhiyun 			continue;
63*4882a593Smuzhiyun 		/*
64*4882a593Smuzhiyun 		 * We only need to send an IPI if the other CPUs are
65*4882a593Smuzhiyun 		 * running the same ASID as the one being invalidated.
66*4882a593Smuzhiyun 		 */
67*4882a593Smuzhiyun 		asid = per_cpu(active_asids, cpu).counter;
68*4882a593Smuzhiyun 		if (asid == 0)
69*4882a593Smuzhiyun 			asid = per_cpu(reserved_asids, cpu);
70*4882a593Smuzhiyun 		if (context_id == asid)
71*4882a593Smuzhiyun 			cpumask_set_cpu(cpu, mask);
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun #endif
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #ifdef CONFIG_ARM_LPAE
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun  * With LPAE, the ASID and page tables are updated atomicly, so there is
80*4882a593Smuzhiyun  * no need for a reserved set of tables (the active ASID tracking prevents
81*4882a593Smuzhiyun  * any issues across a rollover).
82*4882a593Smuzhiyun  */
83*4882a593Smuzhiyun #define cpu_set_reserved_ttbr0()
84*4882a593Smuzhiyun #else
cpu_set_reserved_ttbr0(void)85*4882a593Smuzhiyun static void cpu_set_reserved_ttbr0(void)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	u32 ttb;
88*4882a593Smuzhiyun 	/*
89*4882a593Smuzhiyun 	 * Copy TTBR1 into TTBR0.
90*4882a593Smuzhiyun 	 * This points at swapper_pg_dir, which contains only global
91*4882a593Smuzhiyun 	 * entries so any speculative walks are perfectly safe.
92*4882a593Smuzhiyun 	 */
93*4882a593Smuzhiyun 	asm volatile(
94*4882a593Smuzhiyun 	"	mrc	p15, 0, %0, c2, c0, 1		@ read TTBR1\n"
95*4882a593Smuzhiyun 	"	mcr	p15, 0, %0, c2, c0, 0		@ set TTBR0\n"
96*4882a593Smuzhiyun 	: "=r" (ttb));
97*4882a593Smuzhiyun 	isb();
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun #endif
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #ifdef CONFIG_PID_IN_CONTEXTIDR
contextidr_notifier(struct notifier_block * unused,unsigned long cmd,void * t)102*4882a593Smuzhiyun static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd,
103*4882a593Smuzhiyun 			       void *t)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	u32 contextidr;
106*4882a593Smuzhiyun 	pid_t pid;
107*4882a593Smuzhiyun 	struct thread_info *thread = t;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (cmd != THREAD_NOTIFY_SWITCH)
110*4882a593Smuzhiyun 		return NOTIFY_DONE;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	pid = task_pid_nr(thread->task) << ASID_BITS;
113*4882a593Smuzhiyun 	asm volatile(
114*4882a593Smuzhiyun 	"	mrc	p15, 0, %0, c13, c0, 1\n"
115*4882a593Smuzhiyun 	"	and	%0, %0, %2\n"
116*4882a593Smuzhiyun 	"	orr	%0, %0, %1\n"
117*4882a593Smuzhiyun 	"	mcr	p15, 0, %0, c13, c0, 1\n"
118*4882a593Smuzhiyun 	: "=r" (contextidr), "+r" (pid)
119*4882a593Smuzhiyun 	: "I" (~ASID_MASK));
120*4882a593Smuzhiyun 	isb();
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return NOTIFY_OK;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static struct notifier_block contextidr_notifier_block = {
126*4882a593Smuzhiyun 	.notifier_call = contextidr_notifier,
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun 
contextidr_notifier_init(void)129*4882a593Smuzhiyun static int __init contextidr_notifier_init(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	return thread_register_notifier(&contextidr_notifier_block);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun arch_initcall(contextidr_notifier_init);
134*4882a593Smuzhiyun #endif
135*4882a593Smuzhiyun 
flush_context(unsigned int cpu)136*4882a593Smuzhiyun static void flush_context(unsigned int cpu)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	int i;
139*4882a593Smuzhiyun 	u64 asid;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Update the list of reserved ASIDs and the ASID bitmap. */
142*4882a593Smuzhiyun 	bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
143*4882a593Smuzhiyun 	for_each_possible_cpu(i) {
144*4882a593Smuzhiyun 		asid = atomic64_xchg(&per_cpu(active_asids, i), 0);
145*4882a593Smuzhiyun 		/*
146*4882a593Smuzhiyun 		 * If this CPU has already been through a
147*4882a593Smuzhiyun 		 * rollover, but hasn't run another task in
148*4882a593Smuzhiyun 		 * the meantime, we must preserve its reserved
149*4882a593Smuzhiyun 		 * ASID, as this is the only trace we have of
150*4882a593Smuzhiyun 		 * the process it is still running.
151*4882a593Smuzhiyun 		 */
152*4882a593Smuzhiyun 		if (asid == 0)
153*4882a593Smuzhiyun 			asid = per_cpu(reserved_asids, i);
154*4882a593Smuzhiyun 		__set_bit(asid & ~ASID_MASK, asid_map);
155*4882a593Smuzhiyun 		per_cpu(reserved_asids, i) = asid;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* Queue a TLB invalidate and flush the I-cache if necessary. */
159*4882a593Smuzhiyun 	cpumask_setall(&tlb_flush_pending);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	if (icache_is_vivt_asid_tagged())
162*4882a593Smuzhiyun 		__flush_icache_all();
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
check_update_reserved_asid(u64 asid,u64 newasid)165*4882a593Smuzhiyun static bool check_update_reserved_asid(u64 asid, u64 newasid)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	int cpu;
168*4882a593Smuzhiyun 	bool hit = false;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/*
171*4882a593Smuzhiyun 	 * Iterate over the set of reserved ASIDs looking for a match.
172*4882a593Smuzhiyun 	 * If we find one, then we can update our mm to use newasid
173*4882a593Smuzhiyun 	 * (i.e. the same ASID in the current generation) but we can't
174*4882a593Smuzhiyun 	 * exit the loop early, since we need to ensure that all copies
175*4882a593Smuzhiyun 	 * of the old ASID are updated to reflect the mm. Failure to do
176*4882a593Smuzhiyun 	 * so could result in us missing the reserved ASID in a future
177*4882a593Smuzhiyun 	 * generation.
178*4882a593Smuzhiyun 	 */
179*4882a593Smuzhiyun 	for_each_possible_cpu(cpu) {
180*4882a593Smuzhiyun 		if (per_cpu(reserved_asids, cpu) == asid) {
181*4882a593Smuzhiyun 			hit = true;
182*4882a593Smuzhiyun 			per_cpu(reserved_asids, cpu) = newasid;
183*4882a593Smuzhiyun 		}
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return hit;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
new_context(struct mm_struct * mm,unsigned int cpu)189*4882a593Smuzhiyun static u64 new_context(struct mm_struct *mm, unsigned int cpu)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	static u32 cur_idx = 1;
192*4882a593Smuzhiyun 	u64 asid = atomic64_read(&mm->context.id);
193*4882a593Smuzhiyun 	u64 generation = atomic64_read(&asid_generation);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (asid != 0) {
196*4882a593Smuzhiyun 		u64 newasid = generation | (asid & ~ASID_MASK);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		/*
199*4882a593Smuzhiyun 		 * If our current ASID was active during a rollover, we
200*4882a593Smuzhiyun 		 * can continue to use it and this was just a false alarm.
201*4882a593Smuzhiyun 		 */
202*4882a593Smuzhiyun 		if (check_update_reserved_asid(asid, newasid))
203*4882a593Smuzhiyun 			return newasid;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 		/*
206*4882a593Smuzhiyun 		 * We had a valid ASID in a previous life, so try to re-use
207*4882a593Smuzhiyun 		 * it if possible.,
208*4882a593Smuzhiyun 		 */
209*4882a593Smuzhiyun 		asid &= ~ASID_MASK;
210*4882a593Smuzhiyun 		if (!__test_and_set_bit(asid, asid_map))
211*4882a593Smuzhiyun 			return newasid;
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	/*
215*4882a593Smuzhiyun 	 * Allocate a free ASID. If we can't find one, take a note of the
216*4882a593Smuzhiyun 	 * currently active ASIDs and mark the TLBs as requiring flushes.
217*4882a593Smuzhiyun 	 * We always count from ASID #1, as we reserve ASID #0 to switch
218*4882a593Smuzhiyun 	 * via TTBR0 and to avoid speculative page table walks from hitting
219*4882a593Smuzhiyun 	 * in any partial walk caches, which could be populated from
220*4882a593Smuzhiyun 	 * overlapping level-1 descriptors used to map both the module
221*4882a593Smuzhiyun 	 * area and the userspace stack.
222*4882a593Smuzhiyun 	 */
223*4882a593Smuzhiyun 	asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
224*4882a593Smuzhiyun 	if (asid == NUM_USER_ASIDS) {
225*4882a593Smuzhiyun 		generation = atomic64_add_return(ASID_FIRST_VERSION,
226*4882a593Smuzhiyun 						 &asid_generation);
227*4882a593Smuzhiyun 		flush_context(cpu);
228*4882a593Smuzhiyun 		asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	__set_bit(asid, asid_map);
232*4882a593Smuzhiyun 	cur_idx = asid;
233*4882a593Smuzhiyun 	cpumask_clear(mm_cpumask(mm));
234*4882a593Smuzhiyun 	return asid | generation;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
check_and_switch_context(struct mm_struct * mm,struct task_struct * tsk)237*4882a593Smuzhiyun void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	unsigned long flags;
240*4882a593Smuzhiyun 	unsigned int cpu = smp_processor_id();
241*4882a593Smuzhiyun 	u64 asid;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq))
244*4882a593Smuzhiyun 		__check_vmalloc_seq(mm);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/*
247*4882a593Smuzhiyun 	 * We cannot update the pgd and the ASID atomicly with classic
248*4882a593Smuzhiyun 	 * MMU, so switch exclusively to global mappings to avoid
249*4882a593Smuzhiyun 	 * speculative page table walking with the wrong TTBR.
250*4882a593Smuzhiyun 	 */
251*4882a593Smuzhiyun 	cpu_set_reserved_ttbr0();
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	asid = atomic64_read(&mm->context.id);
254*4882a593Smuzhiyun 	if (!((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS)
255*4882a593Smuzhiyun 	    && atomic64_xchg(&per_cpu(active_asids, cpu), asid))
256*4882a593Smuzhiyun 		goto switch_mm_fastpath;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&cpu_asid_lock, flags);
259*4882a593Smuzhiyun 	/* Check that our ASID belongs to the current generation. */
260*4882a593Smuzhiyun 	asid = atomic64_read(&mm->context.id);
261*4882a593Smuzhiyun 	if ((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) {
262*4882a593Smuzhiyun 		asid = new_context(mm, cpu);
263*4882a593Smuzhiyun 		atomic64_set(&mm->context.id, asid);
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
267*4882a593Smuzhiyun 		local_flush_bp_all();
268*4882a593Smuzhiyun 		local_flush_tlb_all();
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	atomic64_set(&per_cpu(active_asids, cpu), asid);
272*4882a593Smuzhiyun 	cpumask_set_cpu(cpu, mm_cpumask(mm));
273*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun switch_mm_fastpath:
276*4882a593Smuzhiyun 	cpu_switch_mm(mm->pgd, mm);
277*4882a593Smuzhiyun }
278