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 (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-17 WangXiaoyao cache API unit test
*/
#ifndef __TEST_CACHE_RV64_H
#define __TEST_CACHE_RV64_H
#ifdef ARCH_RISCV64
#ifndef RT_USING_RISCV_NEW_COMMON
#include "riscv_mmu.h"
#endif
#include <utest.h>
#include <cache.h>
#include <page.h>
#include <mmu.h>
#include <ioremap.h>
/**
* ==============================================================
* TEST FEATURE
* API under cache.h
* rt_hw_sync_cache_local
*
* rt_hw_cpu_dcache_clean
* rt_hw_cpu_dcache_invalidate
* rt_hw_cpu_dcache_clean_invalidate
* rt_hw_cpu_dcache_clean_all
* rt_hw_cpu_dcache_invalidate_all // meaningless
* rt_hw_cpu_dcache_clean_invalidate_all
* rt_hw_cpu_icache_invalidate
* rt_hw_cpu_icache_invalidate_all
* ==============================================================
*/
/* Ensure the ISA is valid for target ARCHITECTURE */
static void _illegal_instr(void)
{
rt_hw_sync_cache_local(_illegal_instr, 64);
rt_hw_cpu_dcache_clean(_illegal_instr, 64);
rt_hw_cpu_dcache_invalidate(_illegal_instr, 64);
// rt_hw_cpu_dcache_clean_invalidate(_illegal_instr, 64); // C908 ONLY
rt_hw_cpu_dcache_clean_all();
rt_hw_cpu_dcache_invalidate_all(); // !CAREFUL must be inline
// rt_hw_cpu_dcache_clean_invalidate_all(); // C908 ONLY
rt_hw_cpu_icache_invalidate(_illegal_instr, 64);
rt_hw_cpu_icache_invalidate_all();
uassert_true(1);
LOG_I("All ok!");
}
static int _get1(void)
{
return 1;
}
static int _get2(void)
{
return 2;
}
/* hot patching codes and test if the value can be seen by icache */
static void _test_cache_sync(void)
{
uassert_true(1 == _get1());
rt_memcpy(_get1, _get2, _get2 - _get1);
uassert_true(1 == _get1());
rt_hw_sync_cache_local(_get1, _get2 - _get1);
uassert_true(2 == _get1());
LOG_I("%s ok", __func__);
}
/* test clean operation should do and only effect the range specified by writing to a page */
static void _test_dcache_clean(void)
{
const size_t padding = 1024 * 3;
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
/* after ioremap, we can access system memory to verify outcome */
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
rt_memset(page, 0xab, buf_sz);
rt_hw_cpu_sync();
int _outdate_flag = 0;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] != 0xab)
{
_outdate_flag = 1;
break;
}
}
page[padding - 1] = 0xac;
page[padding + ARCH_PAGE_SIZE] = 0xac;
rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE);
/* free some space in dcache to avoid padding data being written back */
rt_hw_cpu_dcache_invalidate(page + padding, ARCH_PAGE_SIZE);
uassert_true(remap_nocache[padding - 1] != 0xac);
uassert_true(remap_nocache[padding + ARCH_PAGE_SIZE] != 0xac);
int _test_ok = 1;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] != 0xab)
{
_test_ok = 0;
break;
}
}
uassert_true(_test_ok);
if (!_outdate_flag)
LOG_W("Cannot guarantee clean works");
else
LOG_I("%s ok", __func__);
rt_pages_free(page, 0);
rt_iounmap(remap_nocache);
}
/* test clean op should do and only effect the range */
static void _test_dcache_invalidate(void)
{
const size_t padding = 1024 * 3;
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
/* prepare */
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
rt_memset(page, 0x0, buf_sz);
rt_hw_cpu_sync();
int _outdate_flag = 0;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
remap_nocache[i] = 0xab;
rt_hw_cpu_dcache_invalidate((void *)&remap_nocache[i], 1);
}
rt_hw_cpu_dcache_clean_all();
int _test_ok = 1;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] == 0xab)
{
_test_ok = 0;
break;
}
}
uassert_true(_test_ok);
LOG_I("%s ok", __func__);
rt_pages_free(page, 0);
rt_iounmap(remap_nocache);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(_illegal_instr);
#ifdef BOARD_allwinnerd1s
/* thead ISA extension */
UTEST_UNIT_RUN(_test_cache_sync);
/* part of it is hard to test on simulation machine */
UTEST_UNIT_RUN(_test_dcache_clean);
UTEST_UNIT_RUN(_test_dcache_invalidate);
#endif
}
UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10);
#endif /* ARCH_RISCV64 */
#endif /* __TEST_CACHE_RV64_H */
|