1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <arch/arm64/feature.h>
8 
9 #include <arch/arm64.h>
10 #include <bits.h>
11 #include <fbl/algorithm.h>
12 #include <inttypes.h>
13 
14 // saved feature bitmap
15 uint32_t arm64_features;
16 
17 static arm64_cache_info_t cache_info[SMP_MAX_CPUS];
18 
19 // cache size parameters cpus, default to a reasonable minimum
20 uint32_t arm64_zva_size = 32;
21 uint32_t arm64_icache_size = 32;
22 uint32_t arm64_dcache_size = 32;
23 
parse_ccsid(arm64_cache_desc_t * desc,uint64_t ccsid)24 static void parse_ccsid(arm64_cache_desc_t* desc, uint64_t ccsid) {
25     desc->write_through = BIT(ccsid, 31) > 0;
26     desc->write_back = BIT(ccsid, 30) > 0;
27     desc->read_alloc = BIT(ccsid, 29) > 0;
28     desc->write_alloc = BIT(ccsid, 28) > 0;
29     desc->num_sets = (uint32_t)BITS_SHIFT(ccsid, 27, 13) + 1;
30     desc->associativity = (uint32_t)BITS_SHIFT(ccsid, 12, 3) + 1;
31     desc->line_size = 1u << (BITS(ccsid, 2, 0) + 4);
32 }
33 
arm64_get_cache_info(arm64_cache_info_t * info)34 void arm64_get_cache_info(arm64_cache_info_t* info) {
35     uint64_t temp = 0;
36 
37     uint64_t sysreg = __arm_rsr64("clidr_el1");
38     info->inner_boundary = (uint8_t)BITS_SHIFT(sysreg, 32, 30);
39     info->lou_u = (uint8_t)BITS_SHIFT(sysreg, 29, 27);
40     info->loc = (uint8_t)BITS_SHIFT(sysreg, 26, 24);
41     info->lou_is = (uint8_t)BITS_SHIFT(sysreg, 23, 21);
42     for (int i = 0; i < 7; i++) {
43         uint8_t ctype = (sysreg >> (3 * i)) & 0x07;
44         if (ctype == 0) {
45             info->level_data_type[i].ctype = 0;
46             info->level_inst_type[i].ctype = 0;
47         } else if (ctype == 4) {                               // Unified
48             __arm_wsr64("csselr_el1", (int64_t)(i << 1)); // Select cache level
49             __isb(ARM_MB_SY);
50             temp = __arm_rsr64("ccsidr_el1");
51             info->level_data_type[i].ctype = 4;
52             parse_ccsid(&(info->level_data_type[i]), temp);
53         } else {
54             if (ctype & 0x02) {
55                 __arm_wsr64("csselr_el1", (int64_t)(i << 1));
56                 __isb(ARM_MB_SY);
57                 temp = __arm_rsr64("ccsidr_el1");
58                 info->level_data_type[i].ctype = 2;
59                 parse_ccsid(&(info->level_data_type[i]), temp);
60             }
61             if (ctype & 0x01) {
62                 __arm_wsr64("csselr_el1", (int64_t)(i << 1) | 0x01);
63                 __isb(ARM_MB_SY);
64                 temp = __arm_rsr64("ccsidr_el1");
65                 info->level_inst_type[i].ctype = 1;
66                 parse_ccsid(&(info->level_inst_type[i]), temp);
67             }
68         }
69     }
70 }
71 
arm64_dump_cache_info(uint32_t cpu)72 void arm64_dump_cache_info(uint32_t cpu) {
73 
74     arm64_cache_info_t* info = &(cache_info[cpu]);
75     printf("==== ARM64 CACHE INFO CORE %u ====\n", cpu);
76     printf("Inner Boundary = L%u\n", info->inner_boundary);
77     printf("Level of Unification Uniprocessor = L%u\n", info->lou_u);
78     printf("Level of Coherence = L%u\n", info->loc);
79     printf("Level of Unification Inner Shareable = L%u\n", info->lou_is);
80     for (int i = 0; i < 7; i++) {
81         printf("L%d Details:", i + 1);
82         if ((info->level_data_type[i].ctype == 0) && (info->level_inst_type[i].ctype == 0)) {
83             printf("\tNot Implemented\n");
84         } else {
85             if (info->level_data_type[i].ctype == 4) {
86                 printf("\tUnified Cache, sets=%u, associativity=%u, line size=%u bytes\n",
87                        info->level_data_type[i].num_sets,
88                        info->level_data_type[i].associativity,
89                        info->level_data_type[i].line_size);
90             } else {
91                 if (info->level_data_type[i].ctype & 0x02) {
92                     printf("\tData Cache, sets=%u, associativity=%u, line size=%u bytes\n",
93                            info->level_data_type[i].num_sets,
94                            info->level_data_type[i].associativity,
95                            info->level_data_type[i].line_size);
96                 }
97                 if (info->level_inst_type[i].ctype & 0x01) {
98                     if (info->level_data_type[i].ctype & 0x02) {
99                         printf("\t");
100                     }
101                     printf("\tInstruction Cache, sets=%u, associativity=%u, line size=%u bytes\n",
102                            info->level_inst_type[i].num_sets,
103                            info->level_inst_type[i].associativity,
104                            info->level_inst_type[i].line_size);
105                 }
106             }
107         }
108     }
109 }
110 
midr_to_core(uint32_t midr,char * str,size_t len)111 static void midr_to_core(uint32_t midr, char* str, size_t len) {
112     __UNUSED uint32_t implementer = BITS_SHIFT(midr, 31, 24);
113     __UNUSED uint32_t variant = BITS_SHIFT(midr, 23, 20);
114     __UNUSED uint32_t architecture = BITS_SHIFT(midr, 19, 16);
115     __UNUSED uint32_t partnum = BITS_SHIFT(midr, 15, 4);
116     __UNUSED uint32_t revision = BITS_SHIFT(midr, 3, 0);
117 
118     const char* partnum_str = "unknown";
119     if (implementer == 'A') {
120         // ARM cores
121         switch (partnum) {
122         case 0xd03:
123             partnum_str = "ARM Cortex-a53";
124             break;
125         case 0xd04:
126             partnum_str = "ARM Cortex-a35";
127             break;
128         case 0xd05:
129             partnum_str = "ARM Cortex-a55";
130             break;
131         case 0xd07:
132             partnum_str = "ARM Cortex-a57";
133             break;
134         case 0xd08:
135             partnum_str = "ARM Cortex-a72";
136             break;
137         case 0xd09:
138             partnum_str = "ARM Cortex-a73";
139             break;
140         case 0xd0a:
141             partnum_str = "ARM Cortex-a75";
142             break;
143         default:
144             goto unknown;
145         }
146     } else if (implementer == 'C') {
147         // Cavium
148         switch (partnum) {
149         case 0xa1:
150             partnum_str = "Cavium CN88XX";
151             break;
152         case 0xaf:
153             partnum_str = "Cavium CN99XX";
154             break;
155         default:
156             goto unknown;
157         }
158     } else {
159 unknown:
160         snprintf(str, len, "Unknown implementer %c partnum 0x%x r%up%u",
161                 (char)implementer, partnum, variant, revision);
162         return;
163     }
164 
165     snprintf(str, len, "%s r%up%u", partnum_str, variant, revision);
166 }
167 
print_cpu_info()168 static void print_cpu_info() {
169     uint32_t midr = (uint32_t)__arm_rsr64("midr_el1");
170     char cpu_name[128];
171     midr_to_core(midr, cpu_name, sizeof(cpu_name));
172 
173     uint64_t mpidr = __arm_rsr64("mpidr_el1");
174 
175     dprintf(INFO, "ARM cpu %u: midr %#x '%s' mpidr %#" PRIx64 " aff %u:%u:%u:%u\n",
176             arch_curr_cpu_num(), midr, cpu_name, mpidr,
177             (uint32_t)((mpidr & MPIDR_AFF3_MASK) >> MPIDR_AFF3_SHIFT),
178             (uint32_t)((mpidr & MPIDR_AFF2_MASK) >> MPIDR_AFF2_SHIFT),
179             (uint32_t)((mpidr & MPIDR_AFF1_MASK) >> MPIDR_AFF1_SHIFT),
180             (uint32_t)((mpidr & MPIDR_AFF0_MASK) >> MPIDR_AFF0_SHIFT));
181 }
182 
183 // call on every cpu to save features
arm64_feature_init()184 void arm64_feature_init() {
185     // set up some global constants based on the boot cpu
186     cpu_num_t cpu = arch_curr_cpu_num();
187     if (cpu == 0) {
188         // read the block size of DC ZVA
189         uint64_t dczid = __arm_rsr64("dczid_el0");
190         uint32_t arm64_zva_shift = 0;
191         if (BIT(dczid, 4) == 0) {
192             arm64_zva_shift = (uint32_t)(__arm_rsr64("dczid_el0") & 0xf) + 2;
193         }
194         ASSERT(arm64_zva_shift != 0); // for now, fail if DC ZVA is unavailable
195         arm64_zva_size = (1u << arm64_zva_shift);
196 
197         // read the dcache and icache line size
198         uint64_t ctr = __arm_rsr64("ctr_el0");
199         uint32_t arm64_dcache_shift = (uint32_t)BITS_SHIFT(ctr, 19, 16) + 2;
200         arm64_dcache_size = (1u << arm64_dcache_shift);
201         uint32_t arm64_icache_shift = (uint32_t)BITS(ctr, 3, 0) + 2;
202         arm64_icache_size = (1u << arm64_icache_shift);
203 
204         // parse the ISA feature bits
205         arm64_features |= ZX_HAS_CPU_FEATURES;
206         uint64_t isar0 = __arm_rsr64("id_aa64isar0_el1");
207         if (BITS_SHIFT(isar0, 7, 4) >= 1) {
208             arm64_features |= ZX_ARM64_FEATURE_ISA_AES;
209         }
210         if (BITS_SHIFT(isar0, 7, 4) >= 2) {
211             arm64_features |= ZX_ARM64_FEATURE_ISA_PMULL;
212         }
213         if (BITS_SHIFT(isar0, 11, 8) >= 1) {
214             arm64_features |= ZX_ARM64_FEATURE_ISA_SHA1;
215         }
216         if (BITS_SHIFT(isar0, 15, 12) >= 1) {
217             arm64_features |= ZX_ARM64_FEATURE_ISA_SHA2;
218         }
219         if (BITS_SHIFT(isar0, 19, 16) >= 1) {
220             arm64_features |= ZX_ARM64_FEATURE_ISA_CRC32;
221         }
222         if (BITS_SHIFT(isar0, 23, 20) >= 1) {
223             arm64_features |= ZX_ARM64_FEATURE_ISA_ATOMICS;
224         }
225         if (BITS_SHIFT(isar0, 31, 28) >= 1) {
226             arm64_features |= ZX_ARM64_FEATURE_ISA_RDM;
227         }
228         if (BITS_SHIFT(isar0, 35, 32) >= 1) {
229             arm64_features |= ZX_ARM64_FEATURE_ISA_SHA3;
230         }
231         if (BITS_SHIFT(isar0, 39, 36) >= 1) {
232             arm64_features |= ZX_ARM64_FEATURE_ISA_SM3;
233         }
234         if (BITS_SHIFT(isar0, 43, 40) >= 1) {
235             arm64_features |= ZX_ARM64_FEATURE_ISA_SM4;
236         }
237         if (BITS_SHIFT(isar0, 47, 44) >= 1) {
238             arm64_features |= ZX_ARM64_FEATURE_ISA_DP;
239         }
240 
241         uint64_t isar1 = __arm_rsr64("id_aa64isar1_el1");
242         if (BITS_SHIFT(isar1, 3, 0) >= 1) {
243             arm64_features |= ZX_ARM64_FEATURE_ISA_DPB;
244         }
245 
246         uint64_t pfr0 = __arm_rsr64("id_aa64pfr0_el1");
247         if (BITS_SHIFT(pfr0, 19, 16) < 0b1111) {
248             arm64_features |= ZX_ARM64_FEATURE_ISA_FP;
249         }
250         if (BITS_SHIFT(pfr0, 23, 20) < 0b1111) {
251             arm64_features |= ZX_ARM64_FEATURE_ISA_ASIMD;
252         }
253     }
254 
255     // read the cache info for each cpu
256     arm64_get_cache_info(&(cache_info[cpu]));
257 
258     // check to make sure implementation supports 16 bit asids
259     uint64_t mmfr0 = __arm_rsr64("id_aa64mmfr0_el1");
260     ASSERT((mmfr0 & ARM64_MMFR0_ASIDBITS_MASK) == ARM64_MMFR0_ASIDBITS_16);
261 }
262 
print_feature()263 static void print_feature() {
264     const struct {
265         uint32_t bit;
266         const char* name;
267     } features[] = {
268         {ZX_ARM64_FEATURE_ISA_FP, "fp"},
269         {ZX_ARM64_FEATURE_ISA_ASIMD, "asimd"},
270         {ZX_ARM64_FEATURE_ISA_AES, "aes"},
271         {ZX_ARM64_FEATURE_ISA_PMULL, "pmull"},
272         {ZX_ARM64_FEATURE_ISA_SHA1, "sha1"},
273         {ZX_ARM64_FEATURE_ISA_SHA2, "sha2"},
274         {ZX_ARM64_FEATURE_ISA_CRC32, "crc32"},
275         {ZX_ARM64_FEATURE_ISA_ATOMICS, "atomics"},
276         {ZX_ARM64_FEATURE_ISA_RDM, "rdm"},
277         {ZX_ARM64_FEATURE_ISA_SHA3, "sha3"},
278         {ZX_ARM64_FEATURE_ISA_SM3, "sm3"},
279         {ZX_ARM64_FEATURE_ISA_SM4, "sm4"},
280         {ZX_ARM64_FEATURE_ISA_DP, "dp"},
281         {ZX_ARM64_FEATURE_ISA_DPB, "dpb"},
282     };
283 
284     printf("ARM Features: ");
285     uint col = 0;
286     for (uint i = 0; i < fbl::count_of(features); ++i) {
287         if (arm64_feature_test(features[i].bit))
288             col += printf("%s ", features[i].name);
289         if (col >= 80) {
290             printf("\n");
291             col = 0;
292         }
293     }
294     if (col > 0)
295         printf("\n");
296 }
297 
298 // dump the feature set
299 // print additional information if full is passed
arm64_feature_debug(bool full)300 void arm64_feature_debug(bool full) {
301     print_cpu_info();
302 
303     if (full) {
304         print_feature();
305         dprintf(INFO, "ARM cache line sizes: icache %u dcache %u zva %u\n",
306                 arm64_icache_size, arm64_dcache_size, arm64_zva_size);
307         if (LK_DEBUGLEVEL > 0) {
308             arm64_dump_cache_info(arch_curr_cpu_num());
309         }
310     }
311 }
312