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 
201 static 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 
Cache::Type
Type
Cache types.
Definition: Cache.h:53
isb
void isb()
Instruction Synchronisation Barrier (ARMv7 and above)
Definition: ARMCore.h:218
ARMCacheV7::readCacheSize
u32 readCacheSize(u32 level, u32 type) const
Get cache size.
Definition: ARMCacheV7.cpp:188
Cache::IOError
@ IOError
Definition: Cache.h:46
mcr
#define mcr(coproc, opcode1, opcode2, reg, subReg, value)
Move to CoProcessor from ARM (MCR).
Definition: ARMCore.h:63
dsb
void dsb()
Data Synchronisation Barrier.
Definition: ARMCore.h:198
ARMCacheV7::dataFlush
Result dataFlush(bool clean)
Flush the entire data cache.
Definition: ARMCacheV7.cpp:267
ARMCacheV7::CacheLevelUnified
@ CacheLevelUnified
Definition: ARMCacheV7.h:54
PAGEMASK
#define PAGEMASK
Mask to find the page.
Definition: ARMConstant.h:121
ARMCacheV7::getCacheLevelId
u32 getCacheLevelId() const
Get cache level identifier.
Definition: ARMCacheV7.cpp:163
CCSIDR_ASSOCIATIVITY_MASK
#define CCSIDR_ASSOCIATIVITY_MASK
Definition: ARMCacheV7.cpp:30
PAGESIZE
#define PAGESIZE
ARM uses 4K pages.
Definition: ARMConstant.h:97
CCSIDR_LINE_SIZE_OFFSET
#define CCSIDR_LINE_SIZE_OFFSET
Definition: ARMCacheV7.cpp:27
Cache::Data
@ Data
Definition: Cache.h:56
ARMCore.h
Address
unsigned long Address
A memory address.
Definition: Types.h:131
ARMCacheV7::invalidate
virtual Result invalidate(Type type)
Invalidate the entire cache.
Definition: ARMCacheV7.cpp:34
Cache::Success
@ Success
Definition: Cache.h:44
ARMCacheV7::cleanAddress
virtual Result cleanAddress(Type type, Address addr)
Clean one memory page.
Definition: ARMCacheV7.cpp:110
ARMCacheV7::flushLevel
Result flushLevel(u32 level, bool clean)
Clean and Invalidate by cache level.
Definition: ARMCacheV7.cpp:218
ARMCacheV7.h
CCSIDR_NUM_SETS_MASK
#define CCSIDR_NUM_SETS_MASK
Definition: ARMCacheV7.cpp:32
log_2_n_round_up
static s32 log_2_n_round_up(u32 n)
Definition: ARMCacheV7.cpp:201
u32
unsigned int u32
Unsigned 32-bit number.
Definition: Types.h:53
s32
signed int s32
Signed 32-bit number.
Definition: Types.h:80
ARMCacheV7::getCacheLineSize
u32 getCacheLineSize() const
Get cache line size in bytes.
Definition: ARMCacheV7.cpp:170
CCSIDR_NUM_SETS_OFFSET
#define CCSIDR_NUM_SETS_OFFSET
Definition: ARMCacheV7.cpp:31
ARMCacheV7::CacheLevelInstruction
@ CacheLevelInstruction
Definition: ARMCacheV7.h:51
Cache::Result
Result
Result codes.
Definition: Cache.h:42
ARMCacheV7::cleanInvalidateAddress
virtual Result cleanInvalidateAddress(Type type, Address addr)
Clean and invalidate one memory page.
Definition: ARMCacheV7.cpp:82
CCSIDR_LINE_SIZE_MASK
#define CCSIDR_LINE_SIZE_MASK
Definition: ARMCacheV7.cpp:28
Cache::Unified
@ Unified
Definition: Cache.h:57
type
u8 type
Definition: IntelACPI.h:63
ARMCacheV7::CacheLevelData
@ CacheLevelData
Definition: ARMCacheV7.h:52
ARMCacheV7::invalidateAddress
virtual Result invalidateAddress(Type type, Address addr)
Invalidate one memory page.
Definition: ARMCacheV7.cpp:138
ARMCacheV7::cleanInvalidate
virtual Result cleanInvalidate(Type type)
Clean and invalidate entire cache.
Definition: ARMCacheV7.cpp:52
CCSIDR_ASSOCIATIVITY_OFFSET
#define CCSIDR_ASSOCIATIVITY_OFFSET
Definition: ARMCacheV7.cpp:29
flushBranchPrediction
void flushBranchPrediction()
Flush branch prediction.
Definition: ARMCore.h:210
Cache::Instruction
@ Instruction
Definition: Cache.h:55