1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
* Copyright 2014, General Dynamics C4 Systems
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(GD_GPL)
*/
#include <api/types.h>
#include <arch/machine.h>
#include <arch/machine/hardware.h>
#include <arch/machine/l2c_310.h>
#define LINE_START(a) ROUND_DOWN(a, L1_CACHE_LINE_SIZE_BITS)
#define LINE_INDEX(a) (LINE_START(a)>>L1_CACHE_LINE_SIZE_BITS)
#define L1_CACHE_LINE_SIZE BIT(L1_CACHE_LINE_SIZE_BITS)
static void
cleanCacheRange_PoC(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
cleanByVA(line, pstart + (line - start));
}
}
void
cleanInvalidateCacheRange_RAM(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end, id)" */
/* First clean the L1 range */
cleanCacheRange_PoC(start, end, pstart);
/* ensure operation completes and visible in L2 */
dsb();
/* Now clean and invalidate the L2 range */
plat_cleanInvalidateL2Range(pstart, pstart + (end - start));
/* Finally clean and invalidate the L1 range. The extra clean is only strictly neccessary
* in a multiprocessor environment to prevent a write being lost if another core is
* attempting a store at the same time. As the range should already be clean asking
* it to clean again should not affect performance */
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
cleanInvalByVA(line, pstart + (line - start));
}
/* ensure clean and invalidate complete */
dsb();
}
void
cleanCacheRange_RAM(vptr_t start, vptr_t end, paddr_t pstart)
{
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end
\<and> \<acute>pstart <= \<acute>pstart + (\<acute>end - \<acute>start), id)" */
/* clean l1 to l2 */
cleanCacheRange_PoC(start, end, pstart);
/* ensure cache operation completes before cleaning l2 */
dsb();
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end
\<and> \<acute>pstart <= \<acute>pstart + (\<acute>end - \<acute>start), id)" */
/* now clean l2 to RAM */
plat_cleanL2Range(pstart, pstart + (end - start));
}
void
cleanCacheRange_PoU(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end
\<and> \<acute>pstart <= \<acute>pstart + (\<acute>end - \<acute>start), id)" */
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
cleanByVA_PoU(line, pstart + (line - start));
}
}
void
invalidateCacheRange_RAM(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
/* If the start and end are not aligned to a cache line boundary
* then we need to clean the line first to prevent invalidating
* bytes we didn't mean to. Calling the functions in this way is
* not the most efficient method, but we assume the user will
* rarely be this silly */
if (start != LINE_START(start)) {
cleanCacheRange_RAM(start, start, pstart);
}
if (end + 1 != LINE_START(end + 1)) {
line = LINE_START(end);
cleanCacheRange_RAM(line, line, pstart + (line - start));
}
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end
\<and> \<acute>pstart <= \<acute>pstart + (\<acute>end - \<acute>start), id)" */
/* Invalidate L2 range. Invalidating the L2 before the L1 is the order
* given in the l2c_310 manual, as an L1 line might be allocated from the L2
* before the L2 can be invalidated. */
plat_invalidateL2Range(pstart, pstart + (end - start));
/** GHOSTUPD: "((gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
\<or> \<acute>end - \<acute>start <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state)
\<and> \<acute>start <= \<acute>end
\<and> \<acute>pstart <= \<acute>pstart + (\<acute>end - \<acute>start), id)" */
/* Now invalidate L1 range */
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
invalidateByVA(line, pstart + (line - start));
}
/* Ensure invalidate completes */
dsb();
}
void
invalidateCacheRange_I(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
invalidateByVA_I(line, pstart + (line - start));
}
}
void
branchFlushRange(vptr_t start, vptr_t end, paddr_t pstart)
{
vptr_t line;
word_t index;
for (index = LINE_INDEX(start); index < LINE_INDEX(end) + 1; index++) {
line = index << L1_CACHE_LINE_SIZE_BITS;
branchFlush(line, pstart + (line - start));
}
}
void
cleanCaches_PoU(void)
{
dsb();
clean_D_PoU();
dsb();
invalidate_I_PoU();
dsb();
}
void
cleanInvalidateL1Caches(void)
{
dsb();
cleanInvalidate_D_PoC();
dsb();
invalidate_I_PoU();
dsb();
}
void
arch_clean_invalidate_caches(void)
{
cleanCaches_PoU();
plat_cleanInvalidateCache();
cleanInvalidateL1Caches();
isb();
}