FreeNOS
ARMCacheV7.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Partly based on cache_v7.c from the Android project:
20 *
21 * https://android.googlesource.com/device/ti/bootloader/uboot/+/c0eec2d5698a6722a195f4545064dccfb4010c16/arch/arm/cpu/armv7/cache_v7.c
22 */
23
24#include "ARMCore.h"
25#include "ARMCacheV7.h"
26
27#define CCSIDR_LINE_SIZE_OFFSET 0
28#define CCSIDR_LINE_SIZE_MASK 0x7
29#define CCSIDR_ASSOCIATIVITY_OFFSET 3
30#define CCSIDR_ASSOCIATIVITY_MASK (0x3FF << 3)
31#define CCSIDR_NUM_SETS_OFFSET 13
32#define CCSIDR_NUM_SETS_MASK (0x7FFF << 13)
33
35{
36 switch (type)
37 {
38 case Instruction:
39 return cleanInvalidate(type);
40
41 case Data:
42 return dataFlush(false);
43
44 case Unified:
47 break;
48 }
49 return Success;
50}
51
53{
54 switch (type)
55 {
56 case Instruction:
57 //
58 // Invalidate all instruction caches to PoU.
59 // Also flushes branch target cache.
60 //
61 mcr(p15, 0, 0, c7, c5, 0);
62
63 // Invalidate entire branch predictor array
65 dsb();
66 isb();
67 break;
68
69 case Data:
70 dataFlush(true);
71 dsb();
72 break;
73
74 case Unified:
77 break;
78 }
79 return Success;
80}
81
83{
84 const u32 lineSize = getCacheLineSize();
85 const u32 pageAddr = addr & PAGEMASK;
86
87 for (Address i = 0; i < PAGESIZE; i += lineSize)
88 {
89 switch (type)
90 {
91 case Instruction:
92 mcr(p15, 0, 1, c7, c5, pageAddr + i);
93 break;
94
95 case Data:
96 mcr(p15, 0, 1, c7, c14, pageAddr + i);
97 break;
98
99 case Unified:
100 return ARMCacheV7::IOError;
101 }
102 }
103
104 isb();
105 dsb();
106
107 return Success;
108}
109
111{
112 const u32 lineSize = getCacheLineSize();
113 const u32 pageAddr = addr & PAGEMASK;
114
115 for (Address i = 0; i < PAGESIZE; i += lineSize)
116 {
117 switch (type)
118 {
119 case Instruction:
120 mcr(p15, 0, 1, c7, c5, pageAddr + i);
121 break;
122
123 case Data:
124 mcr(p15, 0, 1, c7, c10, pageAddr + i);
125 break;
126
127 case Unified:
128 return ARMCacheV7::IOError;
129 }
130 }
131
132 dsb();
133 isb();
134
135 return Success;
136}
137
139{
140 const u32 lineSize = getCacheLineSize();
141 const u32 pageAddr = addr & PAGEMASK;
142
143 for (Address i = 0; i < PAGESIZE; i += lineSize)
144 {
145 switch (type)
146 {
147 case Instruction:
148 return ARMCacheV7::IOError;
149
150 case Data:
151 mcr(p15, 0, 1, c7, c6, pageAddr + i);
152 break;
153
154 case Unified:
155 return ARMCacheV7::IOError;
156 }
157 }
158
159 dsb();
160 return Success;
161}
162
164{
165 u32 levelId;
166 asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (levelId));
167 return levelId;
168}
169
171{
172 u32 ccsidr, line_len;
173
174 // Read current CP15 Cache Size ID Register
175 asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
176
177 line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
179
180 // Converting from words to bytes
181 line_len += 2;
182
183 // converting from log2(linelen) to linelen
184 line_len = 1 << line_len;
185 return line_len;
186}
187
189{
190 u32 sel = level << 1 | type;
191 u32 ids;
192
193 // Cache Size Selection Register
194 asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (sel));
195
196 // Current Cache Size ID Register
197 asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ids));
198 return ids;
199}
200
201static inline s32 log_2_n_round_up(u32 n)
202{
203 s32 log2n = -1;
204 u32 temp = n;
205
206 while (temp) {
207 log2n++;
208 temp >>= 1;
209 }
210
211 if (n & (n - 1))
212 return log2n + 1; // not power of 2 - round up
213 else
214 return log2n; // power of 2
215}
216
217
219{
220 u32 ccsidr = readCacheSize(level, 0);
221 int way, set, setway;
222 u32 log2_line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
224
225 // Converting from words to bytes
226 log2_line_len += 2;
227
228 u32 num_ways = ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >>
230 u32 num_sets = ((ccsidr & CCSIDR_NUM_SETS_MASK) >>
232 //
233 // According to ARMv7 ARM number of sets and number of ways need
234 // not be a power of 2
235 //
236 u32 log2_num_ways = ::log_2_n_round_up(num_ways);
237 u32 way_shift = (32 - log2_num_ways);
238
239 // Invoke the Clean & Invalidate cache line by set/way on the CP15.
240 for (way = num_ways - 1; way >= 0 ; way--)
241 {
242 for (set = num_sets - 1; set >= 0; set--)
243 {
244 setway = (level << 1) | (set << log2_line_len) |
245 (way << way_shift);
246 //
247 // Clean & Invalidate data/unified
248 // cache line by set/way
249 //
250 if (clean)
251 {
252 asm volatile (" mcr p15, 0, %0, c7, c14, 2"
253 : : "r" (setway));
254 }
255 else
256 {
257 asm volatile (" mcr p15, 0, %0, c7, c6, 2"
258 : : "r" (setway));
259 }
260 }
261 }
262 // Data Synchronisation Barrier to ensure operations are complete
263 dsb();
264 return Success;
265}
266
268{
269 u32 levelId = getCacheLevelId();
270 u32 cacheType, startBit = 0;
271
272 for (u32 level = 0; level < 7; level++)
273 {
274 cacheType = (levelId >> startBit) & 7;
275 if (cacheType == CacheLevelData ||
276 cacheType == CacheLevelInstruction ||
277 cacheType == CacheLevelUnified)
278 {
279 flushLevel(level, clean);
280 }
281 startBit += 3;
282 }
283 return Success;
284}
285
#define isb()
Instruction Synchronisation Barrier (ARMv7 and above)
#define dsb(type)
Data Memory Barrier.
#define CCSIDR_LINE_SIZE_MASK
#define CCSIDR_NUM_SETS_OFFSET
#define CCSIDR_ASSOCIATIVITY_OFFSET
#define CCSIDR_NUM_SETS_MASK
#define CCSIDR_LINE_SIZE_OFFSET
static s32 log_2_n_round_up(u32 n)
#define CCSIDR_ASSOCIATIVITY_MASK
u8 type
Definition IntelACPI.h:0
Result flushLevel(u32 level, bool clean)
Clean and Invalidate by cache level.
virtual Result invalidateAddress(Type type, Address addr)
Invalidate one memory page.
Result dataFlush(bool clean)
Flush the entire data cache.
virtual Result cleanAddress(Type type, Address addr)
Clean one memory page.
@ CacheLevelInstruction
Definition ARMCacheV7.h:51
@ CacheLevelUnified
Definition ARMCacheV7.h:54
u32 getCacheLevelId() const
Get cache level identifier.
virtual Result cleanInvalidateAddress(Type type, Address addr)
Clean and invalidate one memory page.
virtual Result invalidate(Type type)
Invalidate the entire cache.
u32 readCacheSize(u32 level, u32 type) const
Get cache size.
virtual Result cleanInvalidate(Type type)
Clean and invalidate entire cache.
u32 getCacheLineSize() const
Get cache line size in bytes.
Result
Result codes.
Definition Cache.h:43
@ IOError
Definition Cache.h:46
@ Success
Definition Cache.h:44
Type
Cache types.
Definition Cache.h:54
@ Unified
Definition Cache.h:57
@ Data
Definition Cache.h:56
@ Instruction
Definition Cache.h:55
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
void flushBranchPrediction()
Flush branch prediction.
Definition ARMCore.h:210
#define PAGEMASK
Mask to find the page.
#define mcr(coproc, opcode1, opcode2, reg, subReg, value)
Move to CoProcessor from ARM (MCR).
Definition ARMCore.h:63
signed int s32
Signed 32-bit number.
Definition Types.h:80
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
unsigned long Address
A memory address.
Definition Types.h:131