1 /*
2  * Copyright (c) 2023, Google Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 /* Tests the cache line lengths for the d-caches and compares against CACHE_LINE.
25  * This also prints some info about the cache types and line lengths.
26  * Since this uses ARM64 system registers, it is skipped for other arches.
27  */
28 
29 #include <arch/ops.h>
30 #include <inttypes.h>
31 #include <lib/unittest/unittest.h>
32 #include <lk/init.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 
36 /* Architecturally there can be no more than 7 cache levels */
37 #define MAX_CACHE_LEVELS 7
38 
39 /* Cache-type bits in CLIDR_EL1 */
40 #define CTYPE_NO_CACHE 0x0
41 #define CTYPE_I_CACHE 0x1
42 #define CTYPE_D_CACHE 0x2
43 #define CTYPE_ID_CACHE 0x3
44 #define CTYPE_UNIFIED_CACHE 0x4
45 
46 #ifndef ARCH_ARM64
TEST(cachetest,DISABLED_line_length)47 TEST(cachetest, DISABLED_line_length) {}
48 #else
49 /* This tests that CACHE_LINE is configured appriately for the system, while
50  * also displaying some basic info on the caches.
51  */
TEST(cachetest,line_length)52 TEST(cachetest, line_length) {
53     uint64_t cache_types = ARM64_READ_SYSREG(CLIDR_EL1);
54     uint32_t max_dline = 0;
55 
56     for (int level = 0; level < MAX_CACHE_LEVELS; level++) {
57         /* Determine the cache type for the level */
58         const uint8_t ctype = cache_types & 0x7;
59         cache_types >>= 3;
60 
61         /* Ignore if 'no-cache' at this level */
62         if (ctype != CTYPE_NO_CACHE) {
63             uint32_t dline_size = 0, iline_size = 0;
64 
65             /* Read data or unified cache line size */
66             if ((ctype & CTYPE_D_CACHE) || ctype == CTYPE_UNIFIED_CACHE) {
67                 ARM64_WRITE_SYSREG(CSSELR_EL1, (uint64_t)(level << 1u));
68                 dline_size = 1u << ((ARM64_READ_SYSREG(CCSIDR_EL1) & 0x7) + 4);
69 
70                 if (dline_size > max_dline)
71                     max_dline = dline_size;
72             }
73 
74             /* Read instruction cache line size */
75             if (ctype & CTYPE_I_CACHE) {
76                 ARM64_WRITE_SYSREG(CSSELR_EL1,
77                                    (uint64_t)((level << 1u) | 0x1u));
78                 iline_size = 1u << ((ARM64_READ_SYSREG(CCSIDR_EL1) & 0x7) + 4);
79             }
80 
81             /* Print summary of the line size(s) */
82             switch (ctype) {
83             case CTYPE_I_CACHE:
84                 trusty_unittest_printf(
85                         "[   DATA   ] level %d line:           icache=%" PRIu32
86                         "\n",
87                         level + 1, iline_size);
88                 break;
89             case CTYPE_D_CACHE:
90                 trusty_unittest_printf(
91                         "[   DATA   ] level %d line: dcache=%" PRIu32 "\n",
92                         level + 1, dline_size);
93                 break;
94             case CTYPE_ID_CACHE:
95                 trusty_unittest_printf(
96                         "[   DATA   ] level %d line: dcache=%" PRIu32
97                         " icache=%" PRIu32 "\n",
98                         level + 1, dline_size, iline_size);
99                 break;
100             case CTYPE_UNIFIED_CACHE:
101                 trusty_unittest_printf(
102                         "[   DATA   ] level %d line:      unified=%" PRIu32
103                         "\n",
104                         level + 1, dline_size);
105                 break;
106             }
107 
108         } else {
109             /* Stop at first no-cache entry */
110             break;
111         }
112     }
113 
114     EXPECT_GE(CACHE_LINE, max_dline,
115               "cpu%u: max d-cache line exceeds CACHE_LINE (%" PRIu32 " > %u)\n",
116               arch_curr_cpu_num(), max_dline, CACHE_LINE);
117 }
118 #endif
119 
120 PORT_TEST(cachetest, "com.android.kernel.cachetest");
121