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