xref: /netbsd-src/sys/arch/arm/arm32/arm32_tlb.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*-
2  * Copyright (c) 2013 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Matt Thomas of 3am Software Foundry.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(1, "$NetBSD: arm32_tlb.c,v 1.2 2014/04/11 02:39:03 matt Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 
35 #include <uvm/uvm.h>
36 
37 #include <arm/locore.h>
38 
39 bool arm_has_tlbiasid_p;	// CPU supports TLBIASID system coprocessor op
40 
41 tlb_asid_t
42 tlb_get_asid(void)
43 {
44 	return armreg_contextidr_read() & 0xff;
45 }
46 
47 void
48 tlb_set_asid(tlb_asid_t asid)
49 {
50 	arm_dsb();
51 	if (asid == 0) {
52 		armreg_ttbcr_write(armreg_ttbcr_read() | TTBCR_S_PD0);
53 	}
54 	armreg_contextidr_write(asid);
55 	arm_isb();
56 }
57 
58 void
59 tlb_invalidate_all(void)
60 {
61 	const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
62 	arm_dsb();
63 	armreg_tlbiall_write(0);
64 	arm_isb();
65 	if (__predict_false(vivt_icache_p)) {
66 		if (arm_has_tlbiasid_p) {
67 			armreg_icialluis_write(0);
68 		} else {
69 			armreg_iciallu_write(0);
70 		}
71 	}
72 	arm_isb();
73 }
74 
75 void
76 tlb_invalidate_globals(void)
77 {
78 	tlb_invalidate_all();
79 }
80 
81 void
82 tlb_invalidate_asids(tlb_asid_t lo, tlb_asid_t hi)
83 {
84 	const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
85 	arm_dsb();
86 	if (arm_has_tlbiasid_p) {
87 		for (; lo <= hi; lo++) {
88 			armreg_tlbiasid_write(lo);
89 		}
90 		arm_isb();
91 		if (__predict_false(vivt_icache_p)) {
92 			armreg_icialluis_write(0);
93 		}
94 	} else {
95 		armreg_tlbiall_write(0);
96 		arm_isb();
97 		if (__predict_false(vivt_icache_p)) {
98 			armreg_iciallu_write(0);
99 		}
100 	}
101 	arm_isb();
102 }
103 
104 void
105 tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
106 {
107 	arm_dsb();
108 	va = trunc_page(va) | asid;
109 	for (vaddr_t eva = va + PAGE_SIZE; va < eva; va += L2_S_SIZE) {
110 		armreg_tlbimva_write(va);
111 		//armreg_tlbiall_write(asid);
112 	}
113 	arm_isb();
114 }
115 
116 bool
117 tlb_update_addr(vaddr_t va, tlb_asid_t asid, pt_entry_t pte, bool insert_p)
118 {
119 	tlb_invalidate_addr(va, asid);
120 	return true;
121 }
122 
123 #if !defined(MULTIPROCESSOR) && defined(CPU_CORTEXA5)
124 static u_int
125 tlb_cortex_a5_record_asids(u_long *mapp)
126 {
127 	u_int nasids = 0;
128 	for (size_t va_index = 0; va_index < 63; va_index++) {
129 		for (size_t way = 0; way < 2; way++) {
130 			armreg_tlbdataop_write(
131 			     __SHIFTIN(way, ARM_TLBDATAOP_WAY)
132 			     | __SHIFTIN(va_index, ARM_A5_TLBDATAOP_INDEX));
133 			arm_isb();
134 			const uint64_t d = ((uint64_t) armreg_tlbdata1_read())
135 			    | armreg_tlbdata0_read();
136 			if (!(d & ARM_TLBDATA_VALID)
137 			    || !(d & ARM_V5_TLBDATA_nG))
138 				continue;
139 
140 			const tlb_asid_t asid = __SHIFTOUT(d,
141 			    ARM_V5_TLBDATA_ASID);
142 			const u_long mask = 1L << (asid & 31);
143 			const size_t idx = asid >> 5;
144 			if (mapp[idx] & mask)
145 				continue;
146 
147 			mapp[idx] |= mask;
148 			nasids++;
149 		}
150 	}
151 	return nasids;
152 }
153 #endif
154 
155 #if !defined(MULTIPROCESSOR) && defined(CPU_CORTEXA7)
156 static u_int
157 tlb_cortex_a7_record_asids(u_long *mapp)
158 {
159 	u_int nasids = 0;
160 	for (size_t va_index = 0; va_index < 128; va_index++) {
161 		for (size_t way = 0; way < 2; way++) {
162 			armreg_tlbdataop_write(
163 			     __SHIFTIN(way, ARM_TLBDATAOP_WAY)
164 			     | __SHIFTIN(va_index, ARM_A7_TLBDATAOP_INDEX));
165 			arm_isb();
166 			const uint32_t d0 = armreg_tlbdata0_read();
167 			const uint32_t d1 = armreg_tlbdata1_read();
168 			if (!(d0 & ARM_TLBDATA_VALID)
169 			    || !(d1 & ARM_A7_TLBDATA1_nG))
170 				continue;
171 
172 			const uint64_t d01 = ((uint64_t) d1)|d0;
173 			const tlb_asid_t asid = __SHIFTOUT(d01,
174 			    ARM_A7_TLBDATA01_ASID);
175 			const u_long mask = 1L << (asid & 31);
176 			const size_t idx = asid >> 5;
177 			if (mapp[idx] & mask)
178 				continue;
179 
180 			mapp[idx] |= mask;
181 			nasids++;
182 		}
183 	}
184 	return nasids;
185 }
186 #endif
187 
188 u_int
189 tlb_record_asids(u_long *mapp)
190 {
191 #ifndef MULTIPROCESSOR
192 #ifdef CPU_CORTEXA5
193 	if (CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid))
194 		return tlb_cortex_a5_record_asids(mapp);
195 #endif
196 #ifdef CPU_CORTEXA7
197 	if (CPU_ID_CORTEX_A7_P(curcpu()->ci_arm_cpuid))
198 		return tlb_cortex_a7_record_asids(mapp);
199 #endif
200 #endif /* MULTIPROCESSOR */
201 #ifdef DIAGNOSTIC
202 	mapp[0] = 0xfffffffe;
203 	mapp[1] = 0xffffffff;
204 	mapp[2] = 0xffffffff;
205 	mapp[3] = 0xffffffff;
206 	mapp[4] = 0xffffffff;
207 	mapp[5] = 0xffffffff;
208 	mapp[6] = 0xffffffff;
209 	mapp[7] = 0xffffffff;
210 #endif
211 	return 255;
212 }
213 
214 void
215 tlb_walk(void *ctx, bool (*func)(void *, vaddr_t, tlb_asid_t, pt_entry_t))
216 {
217 	/* no way to view the TLB */
218 }
219