1 | /* |
2 | * cacheinfo.c - helpers to query the host about its caches |
3 | * |
4 | * Copyright (C) 2017, Emilio G. Cota <cota@braap.org> |
5 | * License: GNU GPL, version 2 or later. |
6 | * See the COPYING file in the top-level directory. |
7 | */ |
8 | |
9 | #include "qemu/osdep.h" |
10 | #include "qemu/host-utils.h" |
11 | #include "qemu/atomic.h" |
12 | |
13 | int qemu_icache_linesize = 0; |
14 | int qemu_icache_linesize_log; |
15 | int qemu_dcache_linesize = 0; |
16 | int qemu_dcache_linesize_log; |
17 | |
18 | /* |
19 | * Operating system specific detection mechanisms. |
20 | */ |
21 | |
22 | #if defined(_WIN32) |
23 | |
24 | static void sys_cache_info(int *isize, int *dsize) |
25 | { |
26 | SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf; |
27 | DWORD size = 0; |
28 | BOOL success; |
29 | size_t i, n; |
30 | |
31 | /* Check for the required buffer size first. Note that if the zero |
32 | size we use for the probe results in success, then there is no |
33 | data available; fail in that case. */ |
34 | success = GetLogicalProcessorInformation(0, &size); |
35 | if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
36 | return; |
37 | } |
38 | |
39 | n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); |
40 | size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); |
41 | buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n); |
42 | if (!GetLogicalProcessorInformation(buf, &size)) { |
43 | goto fail; |
44 | } |
45 | |
46 | for (i = 0; i < n; i++) { |
47 | if (buf[i].Relationship == RelationCache |
48 | && buf[i].Cache.Level == 1) { |
49 | switch (buf[i].Cache.Type) { |
50 | case CacheUnified: |
51 | *isize = *dsize = buf[i].Cache.LineSize; |
52 | break; |
53 | case CacheInstruction: |
54 | *isize = buf[i].Cache.LineSize; |
55 | break; |
56 | case CacheData: |
57 | *dsize = buf[i].Cache.LineSize; |
58 | break; |
59 | default: |
60 | break; |
61 | } |
62 | } |
63 | } |
64 | fail: |
65 | g_free(buf); |
66 | } |
67 | |
68 | #elif defined(__APPLE__) \ |
69 | || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
70 | # include <sys/sysctl.h> |
71 | # if defined(__APPLE__) |
72 | # define SYSCTL_CACHELINE_NAME "hw.cachelinesize" |
73 | # else |
74 | # define SYSCTL_CACHELINE_NAME "machdep.cacheline_size" |
75 | # endif |
76 | |
77 | static void sys_cache_info(int *isize, int *dsize) |
78 | { |
79 | /* There's only a single sysctl for both I/D cache line sizes. */ |
80 | long size; |
81 | size_t len = sizeof(size); |
82 | if (!sysctlbyname(SYSCTL_CACHELINE_NAME, &size, &len, NULL, 0)) { |
83 | *isize = *dsize = size; |
84 | } |
85 | } |
86 | |
87 | #else |
88 | /* POSIX */ |
89 | |
90 | static void sys_cache_info(int *isize, int *dsize) |
91 | { |
92 | # ifdef _SC_LEVEL1_ICACHE_LINESIZE |
93 | *isize = sysconf(_SC_LEVEL1_ICACHE_LINESIZE); |
94 | # endif |
95 | # ifdef _SC_LEVEL1_DCACHE_LINESIZE |
96 | *dsize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
97 | # endif |
98 | } |
99 | #endif /* sys_cache_info */ |
100 | |
101 | /* |
102 | * Architecture (+ OS) specific detection mechanisms. |
103 | */ |
104 | |
105 | #if defined(__aarch64__) |
106 | |
107 | static void arch_cache_info(int *isize, int *dsize) |
108 | { |
109 | if (*isize == 0 || *dsize == 0) { |
110 | uint64_t ctr; |
111 | |
112 | /* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1, |
113 | but (at least under Linux) these are marked protected by the |
114 | kernel. However, CTR_EL0 contains the minimum linesize in the |
115 | entire hierarchy, and is used by userspace cache flushing. */ |
116 | asm volatile("mrs\t%0, ctr_el0" : "=r" (ctr)); |
117 | if (*isize == 0) { |
118 | *isize = 4 << (ctr & 0xf); |
119 | } |
120 | if (*dsize == 0) { |
121 | *dsize = 4 << ((ctr >> 16) & 0xf); |
122 | } |
123 | } |
124 | } |
125 | |
126 | #elif defined(_ARCH_PPC) && defined(__linux__) |
127 | # include "elf.h" |
128 | |
129 | static void arch_cache_info(int *isize, int *dsize) |
130 | { |
131 | if (*isize == 0) { |
132 | *isize = qemu_getauxval(AT_ICACHEBSIZE); |
133 | } |
134 | if (*dsize == 0) { |
135 | *dsize = qemu_getauxval(AT_DCACHEBSIZE); |
136 | } |
137 | } |
138 | |
139 | #else |
140 | static void arch_cache_info(int *isize, int *dsize) { } |
141 | #endif /* arch_cache_info */ |
142 | |
143 | /* |
144 | * ... and if all else fails ... |
145 | */ |
146 | |
147 | static void fallback_cache_info(int *isize, int *dsize) |
148 | { |
149 | /* If we can only find one of the two, assume they're the same. */ |
150 | if (*isize) { |
151 | if (*dsize) { |
152 | /* Success! */ |
153 | } else { |
154 | *dsize = *isize; |
155 | } |
156 | } else if (*dsize) { |
157 | *isize = *dsize; |
158 | } else { |
159 | #if defined(_ARCH_PPC) |
160 | /* For PPC, we're going to use the icache size computed for |
161 | flush_icache_range. Which means that we must use the |
162 | architecture minimum. */ |
163 | *isize = *dsize = 16; |
164 | #else |
165 | /* Otherwise, 64 bytes is not uncommon. */ |
166 | *isize = *dsize = 64; |
167 | #endif |
168 | } |
169 | } |
170 | |
171 | static void __attribute__((constructor)) init_cache_info(void) |
172 | { |
173 | int isize = 0, dsize = 0; |
174 | |
175 | sys_cache_info(&isize, &dsize); |
176 | arch_cache_info(&isize, &dsize); |
177 | fallback_cache_info(&isize, &dsize); |
178 | |
179 | assert((isize & (isize - 1)) == 0); |
180 | assert((dsize & (dsize - 1)) == 0); |
181 | |
182 | qemu_icache_linesize = isize; |
183 | qemu_icache_linesize_log = ctz32(isize); |
184 | qemu_dcache_linesize = dsize; |
185 | qemu_dcache_linesize_log = ctz32(dsize); |
186 | |
187 | atomic64_init(); |
188 | } |
189 | |