xref: /netbsd-src/sys/arch/arm/arm32/arm32_tlb.c (revision bf021c82f6b40c86d86f89b25c499079ffa896bd)
1a7b613d4Smatt /*-
2a7b613d4Smatt  * Copyright (c) 2013 The NetBSD Foundation, Inc.
3a7b613d4Smatt  * All rights reserved.
4a7b613d4Smatt  *
5a7b613d4Smatt  * This code is derived from software contributed to The NetBSD Foundation
6a7b613d4Smatt  * by Matt Thomas of 3am Software Foundry.
7a7b613d4Smatt  *
8a7b613d4Smatt  * Redistribution and use in source and binary forms, with or without
9a7b613d4Smatt  * modification, are permitted provided that the following conditions
10a7b613d4Smatt  * are met:
11a7b613d4Smatt  * 1. Redistributions of source code must retain the above copyright
12a7b613d4Smatt  *    notice, this list of conditions and the following disclaimer.
13a7b613d4Smatt  * 2. Redistributions in binary form must reproduce the above copyright
14a7b613d4Smatt  *    notice, this list of conditions and the following disclaimer in the
15a7b613d4Smatt  *    documentation and/or other materials provided with the distribution.
16a7b613d4Smatt  *
17a7b613d4Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18a7b613d4Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19a7b613d4Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20a7b613d4Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21a7b613d4Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22a7b613d4Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23a7b613d4Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24a7b613d4Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25a7b613d4Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26a7b613d4Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27a7b613d4Smatt  * POSSIBILITY OF SUCH DAMAGE.
28a7b613d4Smatt  */
29cd0fc78fSskrll 
30fee210abSskrll #include "opt_cputypes.h"
31cd0fc78fSskrll #include "opt_multiprocessor.h"
32cd0fc78fSskrll 
33a7b613d4Smatt #include <sys/cdefs.h>
34*bf021c82Sskrll __KERNEL_RCSID(1, "$NetBSD: arm32_tlb.c,v 1.15 2021/10/02 14:28:04 skrll Exp $");
35a7b613d4Smatt 
36a7b613d4Smatt #include <sys/param.h>
37a7b613d4Smatt #include <sys/types.h>
38a7b613d4Smatt 
39a7b613d4Smatt #include <uvm/uvm.h>
40a7b613d4Smatt 
41a7b613d4Smatt #include <arm/locore.h>
42a7b613d4Smatt 
43a7b613d4Smatt bool arm_has_tlbiasid_p;	// CPU supports TLBIASID system coprocessor op
4491a285acSjmcneill bool arm_has_mpext_p;		// CPU supports MP extensions
45a7b613d4Smatt 
46a7b613d4Smatt tlb_asid_t
tlb_get_asid(void)47a7b613d4Smatt tlb_get_asid(void)
48a7b613d4Smatt {
49a7b613d4Smatt 	return armreg_contextidr_read() & 0xff;
50a7b613d4Smatt }
51a7b613d4Smatt 
52a7b613d4Smatt void
tlb_set_asid(tlb_asid_t asid,pmap_t pm)53*bf021c82Sskrll tlb_set_asid(tlb_asid_t asid, pmap_t pm)
54a7b613d4Smatt {
55ce993bccSskrll 	dsb(sy);
566e760360Sskrll 	if (asid == KERNEL_PID) {
57a7b613d4Smatt 		armreg_ttbcr_write(armreg_ttbcr_read() | TTBCR_S_PD0);
58ce993bccSskrll 		isb();
59a7b613d4Smatt 	}
60a7b613d4Smatt 	armreg_contextidr_write(asid);
61ce993bccSskrll 	isb();
62a7b613d4Smatt }
63a7b613d4Smatt 
64a7b613d4Smatt void
tlb_invalidate_all(void)65a7b613d4Smatt tlb_invalidate_all(void)
66a7b613d4Smatt {
6713066d82Smatt 	const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
68ce993bccSskrll 	dsb(sy);
6991a285acSjmcneill 	if (arm_has_mpext_p) {
7015819bafSmatt 		armreg_tlbiallis_write(0);
7191a285acSjmcneill 	} else {
72a7b613d4Smatt 		armreg_tlbiall_write(0);
7391a285acSjmcneill 	}
74ce993bccSskrll 	isb();
7513066d82Smatt 	if (__predict_false(vivt_icache_p)) {
7613066d82Smatt 		if (arm_has_tlbiasid_p) {
7713066d82Smatt 			armreg_icialluis_write(0);
7813066d82Smatt 		} else {
7913066d82Smatt 			armreg_iciallu_write(0);
8013066d82Smatt 		}
8113066d82Smatt 	}
82ce993bccSskrll 	dsb(sy);
83ce993bccSskrll 	isb();
84a7b613d4Smatt }
85a7b613d4Smatt 
86a7b613d4Smatt void
tlb_invalidate_globals(void)87a7b613d4Smatt tlb_invalidate_globals(void)
88a7b613d4Smatt {
89a7b613d4Smatt 	tlb_invalidate_all();
90a7b613d4Smatt }
91a7b613d4Smatt 
92a7b613d4Smatt void
tlb_invalidate_asids(tlb_asid_t lo,tlb_asid_t hi)93a7b613d4Smatt tlb_invalidate_asids(tlb_asid_t lo, tlb_asid_t hi)
94a7b613d4Smatt {
9513066d82Smatt 	const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
96ce993bccSskrll 	dsb(sy);
97a7b613d4Smatt 	if (arm_has_tlbiasid_p) {
98a7b613d4Smatt 		for (; lo <= hi; lo++) {
9991a285acSjmcneill 			if (arm_has_mpext_p) {
100b33445f5Smatt 				armreg_tlbiasidis_write(lo);
10191a285acSjmcneill 			} else {
102a3f6924aShsuenaga 				armreg_tlbiasid_write(lo);
10391a285acSjmcneill 			}
104a7b613d4Smatt 		}
105ce993bccSskrll 		dsb(sy);
106ce993bccSskrll 		isb();
10713066d82Smatt 		if (__predict_false(vivt_icache_p)) {
10891a285acSjmcneill 			if (arm_has_mpext_p) {
10913066d82Smatt 				armreg_icialluis_write(0);
11091a285acSjmcneill 			} else {
111a3f6924aShsuenaga 				armreg_iciallu_write(0);
11291a285acSjmcneill 			}
11313066d82Smatt 		}
11413066d82Smatt 	} else {
11513066d82Smatt 		armreg_tlbiall_write(0);
116ce993bccSskrll 		isb();
11713066d82Smatt 		if (__predict_false(vivt_icache_p)) {
11813066d82Smatt 			armreg_iciallu_write(0);
11913066d82Smatt 		}
120a7b613d4Smatt 	}
121ce993bccSskrll 	isb();
122a7b613d4Smatt }
123a7b613d4Smatt 
124a7b613d4Smatt void
tlb_invalidate_addr(vaddr_t va,tlb_asid_t asid)125a7b613d4Smatt tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
126a7b613d4Smatt {
127ce993bccSskrll 	dsb(sy);
128a7b613d4Smatt 	va = trunc_page(va) | asid;
129a7b613d4Smatt 	for (vaddr_t eva = va + PAGE_SIZE; va < eva; va += L2_S_SIZE) {
13091a285acSjmcneill 		if (arm_has_mpext_p) {
13115819bafSmatt 			armreg_tlbimvais_write(va);
13291a285acSjmcneill 		} else {
133a7b613d4Smatt 			armreg_tlbimva_write(va);
13491a285acSjmcneill 		}
135a7b613d4Smatt 	}
136ce993bccSskrll 	isb();
137a7b613d4Smatt }
138a7b613d4Smatt 
139a7b613d4Smatt bool
tlb_update_addr(vaddr_t va,tlb_asid_t asid,pt_entry_t pte,bool insert_p)140a7b613d4Smatt tlb_update_addr(vaddr_t va, tlb_asid_t asid, pt_entry_t pte, bool insert_p)
141a7b613d4Smatt {
142a7b613d4Smatt 	tlb_invalidate_addr(va, asid);
143a7b613d4Smatt 	return true;
144a7b613d4Smatt }
145a7b613d4Smatt 
14629299275Sjmcneill #if !defined(MULTIPROCESSOR)
147a7b613d4Smatt static u_int
tlb_cortex_a5_record_asids(u_long * mapp,tlb_asid_t asid_max)148fc444195Smatt tlb_cortex_a5_record_asids(u_long *mapp, tlb_asid_t asid_max)
149a7b613d4Smatt {
150a7b613d4Smatt 	u_int nasids = 0;
151a7b613d4Smatt 	for (size_t va_index = 0; va_index < 63; va_index++) {
152a7b613d4Smatt 		for (size_t way = 0; way < 2; way++) {
153a7b613d4Smatt 			armreg_tlbdataop_write(
154a7b613d4Smatt 			     __SHIFTIN(way, ARM_TLBDATAOP_WAY)
155a7b613d4Smatt 			     | __SHIFTIN(va_index, ARM_A5_TLBDATAOP_INDEX));
156ce993bccSskrll 			isb();
157a7b613d4Smatt 			const uint64_t d = ((uint64_t) armreg_tlbdata1_read())
158a7b613d4Smatt 			    | armreg_tlbdata0_read();
159a7b613d4Smatt 			if (!(d & ARM_TLBDATA_VALID)
16075034e42Sjmcneill 			    || !(d & ARM_A5_TLBDATA_nG))
161a7b613d4Smatt 				continue;
162a7b613d4Smatt 
163a7b613d4Smatt 			const tlb_asid_t asid = __SHIFTOUT(d,
16475034e42Sjmcneill 			    ARM_A5_TLBDATA_ASID);
165a7b613d4Smatt 			const u_long mask = 1L << (asid & 31);
166a7b613d4Smatt 			const size_t idx = asid >> 5;
167a7b613d4Smatt 			if (mapp[idx] & mask)
168a7b613d4Smatt 				continue;
169a7b613d4Smatt 
170a7b613d4Smatt 			mapp[idx] |= mask;
171a7b613d4Smatt 			nasids++;
172a7b613d4Smatt 		}
173a7b613d4Smatt 	}
174a7b613d4Smatt 	return nasids;
175a7b613d4Smatt }
176a7b613d4Smatt #endif
177a7b613d4Smatt 
17829299275Sjmcneill #if !defined(MULTIPROCESSOR)
179a7b613d4Smatt static u_int
tlb_cortex_a7_record_asids(u_long * mapp,tlb_asid_t asid_max)180fc444195Smatt tlb_cortex_a7_record_asids(u_long *mapp, tlb_asid_t asid_max)
181a7b613d4Smatt {
182a7b613d4Smatt 	u_int nasids = 0;
183a7b613d4Smatt 	for (size_t va_index = 0; va_index < 128; va_index++) {
184a7b613d4Smatt 		for (size_t way = 0; way < 2; way++) {
185a7b613d4Smatt 			armreg_tlbdataop_write(
186a7b613d4Smatt 			     __SHIFTIN(way, ARM_TLBDATAOP_WAY)
187a7b613d4Smatt 			     | __SHIFTIN(va_index, ARM_A7_TLBDATAOP_INDEX));
188ce993bccSskrll 			isb();
189a7b613d4Smatt 			const uint32_t d0 = armreg_tlbdata0_read();
190a7b613d4Smatt 			const uint32_t d1 = armreg_tlbdata1_read();
191a7b613d4Smatt 			if (!(d0 & ARM_TLBDATA_VALID)
192a7b613d4Smatt 			    || !(d1 & ARM_A7_TLBDATA1_nG))
193a7b613d4Smatt 				continue;
194a7b613d4Smatt 
195a7b613d4Smatt 			const uint64_t d01 = ((uint64_t) d1)|d0;
196a7b613d4Smatt 			const tlb_asid_t asid = __SHIFTOUT(d01,
197a7b613d4Smatt 			    ARM_A7_TLBDATA01_ASID);
198a7b613d4Smatt 			const u_long mask = 1L << (asid & 31);
199a7b613d4Smatt 			const size_t idx = asid >> 5;
200a7b613d4Smatt 			if (mapp[idx] & mask)
201a7b613d4Smatt 				continue;
202a7b613d4Smatt 
203a7b613d4Smatt 			mapp[idx] |= mask;
204a7b613d4Smatt 			nasids++;
205a7b613d4Smatt 		}
206a7b613d4Smatt 	}
207a7b613d4Smatt 	return nasids;
208a7b613d4Smatt }
209a7b613d4Smatt #endif
210a7b613d4Smatt 
211a7b613d4Smatt u_int
tlb_record_asids(u_long * mapp,tlb_asid_t asid_max)212fc444195Smatt tlb_record_asids(u_long *mapp, tlb_asid_t asid_max)
213a7b613d4Smatt {
214a7b613d4Smatt #ifndef MULTIPROCESSOR
215a7b613d4Smatt 	if (CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid))
216fc444195Smatt 		return tlb_cortex_a5_record_asids(mapp, asid_max);
217a7b613d4Smatt 	if (CPU_ID_CORTEX_A7_P(curcpu()->ci_arm_cpuid))
218fc444195Smatt 		return tlb_cortex_a7_record_asids(mapp, asid_max);
219a7b613d4Smatt #endif /* MULTIPROCESSOR */
220a7b613d4Smatt #ifdef DIAGNOSTIC
221a7b613d4Smatt 	mapp[0] = 0xfffffffe;
222a7b613d4Smatt 	mapp[1] = 0xffffffff;
223a7b613d4Smatt 	mapp[2] = 0xffffffff;
224a7b613d4Smatt 	mapp[3] = 0xffffffff;
225a7b613d4Smatt 	mapp[4] = 0xffffffff;
226a7b613d4Smatt 	mapp[5] = 0xffffffff;
227a7b613d4Smatt 	mapp[6] = 0xffffffff;
228a7b613d4Smatt 	mapp[7] = 0xffffffff;
229a7b613d4Smatt #endif
230a7b613d4Smatt 	return 255;
231a7b613d4Smatt }
232a7b613d4Smatt 
233a7b613d4Smatt void
tlb_walk(void * ctx,bool (* func)(void *,vaddr_t,tlb_asid_t,pt_entry_t))234a7b613d4Smatt tlb_walk(void *ctx, bool (*func)(void *, vaddr_t, tlb_asid_t, pt_entry_t))
235a7b613d4Smatt {
236a7b613d4Smatt 	/* no way to view the TLB */
237a7b613d4Smatt }
238