1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2017, Michael Ellerman, IBM Corp.
4  */
5 
6 #include <elf.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <link.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 
18 #include "utils.h"
19 
20 #ifndef AT_L1I_CACHESIZE
21 #define AT_L1I_CACHESIZE	40
22 #define AT_L1I_CACHEGEOMETRY	41
23 #define AT_L1D_CACHESIZE	42
24 #define AT_L1D_CACHEGEOMETRY	43
25 #define AT_L2_CACHESIZE		44
26 #define AT_L2_CACHEGEOMETRY	45
27 #define AT_L3_CACHESIZE		46
28 #define AT_L3_CACHEGEOMETRY	47
29 #endif
30 
print_size(const char * label,uint32_t val)31 static void print_size(const char *label, uint32_t val)
32 {
33 	printf("%s cache size: %#10x %10dB %10dK\n", label, val, val, val / 1024);
34 }
35 
print_geo(const char * label,uint32_t val)36 static void print_geo(const char *label, uint32_t val)
37 {
38 	uint16_t assoc;
39 
40 	printf("%s line size:  %#10x       ", label, val & 0xFFFF);
41 
42 	assoc = val >> 16;
43 	if (assoc)
44 		printf("%u-way", assoc);
45 	else
46 		printf("fully");
47 
48 	printf(" associative\n");
49 }
50 
test_cache_shape()51 static int test_cache_shape()
52 {
53 	static char buffer[4096];
54 	ElfW(auxv_t) *p;
55 	int found;
56 
57 	FAIL_IF(read_auxv(buffer, sizeof(buffer)));
58 
59 	found = 0;
60 
61 	p = find_auxv_entry(AT_L1I_CACHESIZE, buffer);
62 	if (p) {
63 		found++;
64 		print_size("L1I ", (uint32_t)p->a_un.a_val);
65 	}
66 
67 	p = find_auxv_entry(AT_L1I_CACHEGEOMETRY, buffer);
68 	if (p) {
69 		found++;
70 		print_geo("L1I ", (uint32_t)p->a_un.a_val);
71 	}
72 
73 	p = find_auxv_entry(AT_L1D_CACHESIZE, buffer);
74 	if (p) {
75 		found++;
76 		print_size("L1D ", (uint32_t)p->a_un.a_val);
77 	}
78 
79 	p = find_auxv_entry(AT_L1D_CACHEGEOMETRY, buffer);
80 	if (p) {
81 		found++;
82 		print_geo("L1D ", (uint32_t)p->a_un.a_val);
83 	}
84 
85 	p = find_auxv_entry(AT_L2_CACHESIZE, buffer);
86 	if (p) {
87 		found++;
88 		print_size("L2  ", (uint32_t)p->a_un.a_val);
89 	}
90 
91 	p = find_auxv_entry(AT_L2_CACHEGEOMETRY, buffer);
92 	if (p) {
93 		found++;
94 		print_geo("L2  ", (uint32_t)p->a_un.a_val);
95 	}
96 
97 	p = find_auxv_entry(AT_L3_CACHESIZE, buffer);
98 	if (p) {
99 		found++;
100 		print_size("L3  ", (uint32_t)p->a_un.a_val);
101 	}
102 
103 	p = find_auxv_entry(AT_L3_CACHEGEOMETRY, buffer);
104 	if (p) {
105 		found++;
106 		print_geo("L3  ", (uint32_t)p->a_un.a_val);
107 	}
108 
109 	/* If we found none we're probably on a system where they don't exist */
110 	SKIP_IF(found == 0);
111 
112 	/* But if we found any, we expect to find them all */
113 	FAIL_IF(found != 8);
114 
115 	return 0;
116 }
117 
main(void)118 int main(void)
119 {
120 	return test_harness(test_cache_shape, "cache_shape");
121 }
122