/* * Copyright (c) 2023, Google Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Tests the cache line lengths for the d-caches and compares against CACHE_LINE. * This also prints some info about the cache types and line lengths. * Since this uses ARM64 system registers, it is skipped for other arches. */ #include #include #include #include #include #include /* Architecturally there can be no more than 7 cache levels */ #define MAX_CACHE_LEVELS 7 /* Cache-type bits in CLIDR_EL1 */ #define CTYPE_NO_CACHE 0x0 #define CTYPE_I_CACHE 0x1 #define CTYPE_D_CACHE 0x2 #define CTYPE_ID_CACHE 0x3 #define CTYPE_UNIFIED_CACHE 0x4 #ifndef ARCH_ARM64 TEST(cachetest, DISABLED_line_length) {} #else /* This tests that CACHE_LINE is configured appriately for the system, while * also displaying some basic info on the caches. */ TEST(cachetest, line_length) { uint64_t cache_types = ARM64_READ_SYSREG(CLIDR_EL1); uint32_t max_dline = 0; for (int level = 0; level < MAX_CACHE_LEVELS; level++) { /* Determine the cache type for the level */ const uint8_t ctype = cache_types & 0x7; cache_types >>= 3; /* Ignore if 'no-cache' at this level */ if (ctype != CTYPE_NO_CACHE) { uint32_t dline_size = 0, iline_size = 0; /* Read data or unified cache line size */ if ((ctype & CTYPE_D_CACHE) || ctype == CTYPE_UNIFIED_CACHE) { ARM64_WRITE_SYSREG(CSSELR_EL1, (uint64_t)(level << 1u)); dline_size = 1u << ((ARM64_READ_SYSREG(CCSIDR_EL1) & 0x7) + 4); if (dline_size > max_dline) max_dline = dline_size; } /* Read instruction cache line size */ if (ctype & CTYPE_I_CACHE) { ARM64_WRITE_SYSREG(CSSELR_EL1, (uint64_t)((level << 1u) | 0x1u)); iline_size = 1u << ((ARM64_READ_SYSREG(CCSIDR_EL1) & 0x7) + 4); } /* Print summary of the line size(s) */ switch (ctype) { case CTYPE_I_CACHE: trusty_unittest_printf( "[ DATA ] level %d line: icache=%" PRIu32 "\n", level + 1, iline_size); break; case CTYPE_D_CACHE: trusty_unittest_printf( "[ DATA ] level %d line: dcache=%" PRIu32 "\n", level + 1, dline_size); break; case CTYPE_ID_CACHE: trusty_unittest_printf( "[ DATA ] level %d line: dcache=%" PRIu32 " icache=%" PRIu32 "\n", level + 1, dline_size, iline_size); break; case CTYPE_UNIFIED_CACHE: trusty_unittest_printf( "[ DATA ] level %d line: unified=%" PRIu32 "\n", level + 1, dline_size); break; } } else { /* Stop at first no-cache entry */ break; } } EXPECT_GE(CACHE_LINE, max_dline, "cpu%u: max d-cache line exceeds CACHE_LINE (%" PRIu32 " > %u)\n", arch_curr_cpu_num(), max_dline, CACHE_LINE); } #endif PORT_TEST(cachetest, "com.android.kernel.cachetest");