]>
Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | /* |
2 | * Copyright (c) 2003-2007 Apple Inc. All rights reserved. | |
3 | */ | |
4 | #include <sys/param.h> | |
5 | #include <sys/kernel.h> | |
6 | #include <sys/sysctl.h> | |
7 | ||
8 | #include <machine/machine_routines.h> | |
9 | ||
d9a64523 A |
10 | #include <mach/host_info.h> |
11 | #include <mach/mach_host.h> | |
12 | #include <arm/cpuid.h> | |
2a1bd2d3 | 13 | #include <kern/zalloc.h> |
d9a64523 | 14 | #include <libkern/libkern.h> |
2a1bd2d3 | 15 | #include <pexpert/device_tree.h> |
d9a64523 | 16 | |
f427ee49 A |
17 | #if HYPERVISOR |
18 | #include <kern/hv_support.h> | |
19 | #endif | |
20 | ||
0a7de745 A |
21 | extern uint64_t wake_abstime; |
22 | extern int lck_mtx_adaptive_spin_mode; | |
5ba3f43e A |
23 | |
24 | static | |
25 | SYSCTL_QUAD(_machdep, OID_AUTO, wake_abstime, | |
0a7de745 A |
26 | CTLFLAG_RD, &wake_abstime, |
27 | "Absolute Time at the last wakeup"); | |
5ba3f43e A |
28 | |
29 | static int | |
30 | sysctl_time_since_reset SYSCTL_HANDLER_ARGS | |
31 | { | |
32 | #pragma unused(arg1, arg2, oidp) | |
cb323159 A |
33 | uint64_t return_value = ml_get_time_since_reset(); |
34 | return SYSCTL_OUT(req, &return_value, sizeof(return_value)); | |
5ba3f43e A |
35 | } |
36 | ||
37 | SYSCTL_PROC(_machdep, OID_AUTO, time_since_reset, | |
0a7de745 A |
38 | CTLFLAG_RD | CTLTYPE_QUAD | CTLFLAG_LOCKED, |
39 | 0, 0, sysctl_time_since_reset, "I", | |
40 | "Continuous time since last SOC boot/wake started"); | |
5ba3f43e A |
41 | |
42 | static int | |
43 | sysctl_wake_conttime SYSCTL_HANDLER_ARGS | |
44 | { | |
45 | #pragma unused(arg1, arg2, oidp) | |
cb323159 A |
46 | uint64_t return_value = ml_get_conttime_wake_time(); |
47 | return SYSCTL_OUT(req, &return_value, sizeof(return_value)); | |
5ba3f43e A |
48 | } |
49 | ||
50 | SYSCTL_PROC(_machdep, OID_AUTO, wake_conttime, | |
0a7de745 A |
51 | CTLFLAG_RD | CTLTYPE_QUAD | CTLFLAG_LOCKED, |
52 | 0, 0, sysctl_wake_conttime, "I", | |
53 | "Continuous Time at the last wakeup"); | |
5ba3f43e | 54 | |
c6bf4f31 A |
55 | #if defined(HAS_IPI) |
56 | static int | |
57 | cpu_signal_deferred_timer(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req) | |
58 | { | |
59 | int new_value = 0; | |
60 | int changed = 0; | |
61 | ||
62 | int old_value = (int)ml_cpu_signal_deferred_get_timer(); | |
63 | ||
64 | int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed); | |
65 | ||
66 | if (error == 0 && changed) { | |
67 | ml_cpu_signal_deferred_adjust_timer((uint64_t)new_value); | |
68 | } | |
69 | ||
70 | return error; | |
71 | } | |
72 | ||
73 | SYSCTL_PROC(_machdep, OID_AUTO, deferred_ipi_timeout, | |
74 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, | |
75 | 0, 0, | |
76 | cpu_signal_deferred_timer, "I", "Deferred IPI timeout (nanoseconds)"); | |
77 | ||
78 | #endif /* defined(HAS_IPI) */ | |
5ba3f43e | 79 | |
d9a64523 A |
80 | /* |
81 | * For source compatibility, here's some machdep.cpu mibs that | |
82 | * use host_info() to simulate reasonable answers. | |
83 | */ | |
84 | ||
0a7de745 A |
85 | SYSCTL_NODE(_machdep, OID_AUTO, cpu, CTLFLAG_RW | CTLFLAG_LOCKED, 0, |
86 | "CPU info"); | |
d9a64523 A |
87 | |
88 | static int | |
89 | arm_host_info SYSCTL_HANDLER_ARGS | |
90 | { | |
91 | __unused struct sysctl_oid *unused_oidp = oidp; | |
92 | ||
93 | host_basic_info_data_t hinfo; | |
94 | mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; | |
0a7de745 | 95 | #define BSD_HOST 1 |
d9a64523 | 96 | kern_return_t kret = host_info((host_t)BSD_HOST, |
0a7de745 A |
97 | HOST_BASIC_INFO, (host_info_t)&hinfo, &count); |
98 | if (KERN_SUCCESS != kret) { | |
99 | return EINVAL; | |
100 | } | |
d9a64523 | 101 | |
0a7de745 | 102 | if (sizeof(uint32_t) != arg2) { |
d9a64523 | 103 | panic("size mismatch"); |
0a7de745 | 104 | } |
d9a64523 | 105 | |
0a7de745 | 106 | uintptr_t woffset = (uintptr_t)arg1 / sizeof(uint32_t); |
d9a64523 | 107 | uint32_t datum = *(uint32_t *)(((uint32_t *)&hinfo) + woffset); |
0a7de745 | 108 | return SYSCTL_OUT(req, &datum, sizeof(datum)); |
d9a64523 A |
109 | } |
110 | ||
111 | /* | |
112 | * machdep.cpu.cores_per_package | |
113 | * | |
114 | * x86: derived from CPUID data. | |
115 | * ARM: how many physical cores we have in the AP; aka hw.physicalcpu_max | |
116 | */ | |
117 | static | |
118 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, cores_per_package, | |
0a7de745 A |
119 | CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, |
120 | (void *)offsetof(host_basic_info_data_t, physical_cpu_max), | |
121 | sizeof(integer_t), | |
122 | arm_host_info, "I", "CPU cores per package"); | |
d9a64523 A |
123 | |
124 | /* | |
125 | * machdep.cpu.core_count | |
126 | * | |
127 | * x86: derived from CPUID data. | |
128 | * ARM: # active physical cores in the AP; aka hw.physicalcpu | |
129 | */ | |
130 | static | |
131 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, core_count, | |
0a7de745 A |
132 | CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, |
133 | (void *)offsetof(host_basic_info_data_t, physical_cpu), | |
134 | sizeof(integer_t), | |
135 | arm_host_info, "I", "Number of enabled cores per package"); | |
d9a64523 A |
136 | |
137 | /* | |
138 | * machdep.cpu.logical_per_package | |
139 | * | |
140 | * x86: derived from CPUID data. Returns ENOENT if HTT bit not set, but | |
141 | * most x64 CPUs have that, so assume it's available. | |
142 | * ARM: total # logical cores in the AP; aka hw.logicalcpu_max | |
143 | */ | |
144 | static | |
145 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, logical_per_package, | |
0a7de745 A |
146 | CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, |
147 | (void *)offsetof(host_basic_info_data_t, logical_cpu_max), | |
148 | sizeof(integer_t), | |
149 | arm_host_info, "I", "CPU logical cpus per package"); | |
d9a64523 A |
150 | |
151 | /* | |
152 | * machdep.cpu.thread_count | |
153 | * | |
154 | * x86: derived from CPUID data. | |
155 | * ARM: # active logical cores in the AP; aka hw.logicalcpu | |
156 | */ | |
157 | static | |
158 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, thread_count, | |
0a7de745 A |
159 | CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, |
160 | (void *)offsetof(host_basic_info_data_t, logical_cpu), | |
161 | sizeof(integer_t), | |
162 | arm_host_info, "I", "Number of enabled threads per package"); | |
d9a64523 | 163 | |
2a1bd2d3 A |
164 | static SECURITY_READ_ONLY_LATE(char*) brand_string = NULL; |
165 | static SECURITY_READ_ONLY_LATE(size_t) brand_string_len = 0; | |
166 | ||
167 | /* | |
168 | * SecureDTLookupEntry() is only guaranteed to work before PE_init_iokit(), | |
169 | * so we load the brand string (if available) in a startup handler. | |
170 | */ | |
171 | __startup_func | |
172 | static void | |
173 | sysctl_load_brand_string(void) | |
174 | { | |
175 | DTEntry node; | |
176 | void const *value = NULL; | |
177 | unsigned int size = 0; | |
178 | ||
179 | if (kSuccess != SecureDTLookupEntry(0, "/product", &node)) { | |
180 | return; | |
181 | } | |
182 | ||
183 | if (kSuccess != SecureDTGetProperty(node, "product-soc-name", (void const **) &value, &size)) { | |
184 | return; | |
185 | } | |
186 | ||
187 | if (size == 0) { | |
188 | return; | |
189 | } | |
190 | ||
191 | brand_string = zalloc_permanent(size, ZALIGN_NONE); | |
192 | if (brand_string == NULL) { | |
193 | return; | |
194 | } | |
195 | ||
196 | memcpy(brand_string, value, size); | |
197 | brand_string_len = size; | |
198 | } | |
199 | STARTUP(SYSCTL, STARTUP_RANK_MIDDLE, sysctl_load_brand_string); | |
200 | ||
d9a64523 A |
201 | /* |
202 | * machdep.cpu.brand_string | |
203 | * | |
204 | * x86: derived from CPUID data. | |
2a1bd2d3 A |
205 | * ARM: Grab the product string from the device tree, if it exists. |
206 | * Otherwise, cons something up from the CPUID register. | |
d9a64523 A |
207 | * the value is already exported via the commpage. So keep it simple. |
208 | */ | |
209 | static int | |
210 | make_brand_string SYSCTL_HANDLER_ARGS | |
211 | { | |
212 | __unused struct sysctl_oid *unused_oidp = oidp; | |
213 | __unused void *unused_arg1 = arg1; | |
214 | __unused int unused_arg2 = arg2; | |
215 | ||
2a1bd2d3 A |
216 | if (brand_string != NULL) { |
217 | return SYSCTL_OUT(req, brand_string, brand_string_len); | |
218 | } | |
219 | ||
d9a64523 A |
220 | const char *impl; |
221 | ||
222 | switch (cpuid_info()->arm_info.arm_implementor) { | |
223 | case CPU_VID_APPLE: | |
224 | impl = "Apple"; | |
225 | break; | |
226 | case CPU_VID_ARM: | |
227 | impl = "ARM"; | |
228 | break; | |
229 | default: | |
230 | impl = "ARM architecture"; | |
231 | break; | |
232 | } | |
f427ee49 A |
233 | |
234 | ||
d9a64523 | 235 | char buf[80]; |
0a7de745 A |
236 | snprintf(buf, sizeof(buf), "%s processor", impl); |
237 | return SYSCTL_OUT(req, buf, strlen(buf) + 1); | |
d9a64523 A |
238 | } |
239 | ||
240 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, brand_string, | |
0a7de745 A |
241 | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED, |
242 | 0, 0, make_brand_string, "A", "CPU brand string"); | |
243 | ||
f427ee49 | 244 | |
0a7de745 A |
245 | static |
246 | SYSCTL_INT(_machdep, OID_AUTO, lck_mtx_adaptive_spin_mode, | |
247 | CTLFLAG_RW, &lck_mtx_adaptive_spin_mode, 0, | |
248 | "Enable adaptive spin behavior for kernel mutexes"); | |
249 | ||
f427ee49 A |
250 | static int |
251 | virtual_address_size SYSCTL_HANDLER_ARGS | |
252 | { | |
253 | #pragma unused(arg1, arg2, oidp) | |
254 | int return_value = 64 - T0SZ_BOOT; | |
255 | return SYSCTL_OUT(req, &return_value, sizeof(return_value)); | |
256 | } | |
257 | ||
258 | static | |
259 | SYSCTL_PROC(_machdep, OID_AUTO, virtual_address_size, | |
260 | CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, | |
261 | 0, 0, virtual_address_size, "I", | |
262 | "Number of addressable bits in userspace virtual addresses"); | |
263 | ||
cb323159 | 264 | |
0a7de745 A |
265 | #if DEVELOPMENT || DEBUG |
266 | extern uint64_t TLockTimeOut; | |
267 | SYSCTL_QUAD(_machdep, OID_AUTO, tlto, | |
268 | CTLFLAG_RW | CTLFLAG_LOCKED, &TLockTimeOut, | |
269 | "Ticket spinlock timeout (MATUs): use with care"); | |
cb323159 | 270 | |
cb323159 | 271 | /* |
f427ee49 A |
272 | * macro to generate a sysctl machdep.cpu.sysreg_* for a given system register |
273 | * using __builtin_arm_rsr64. | |
cb323159 | 274 | */ |
f427ee49 A |
275 | #define SYSCTL_PROC_MACHDEP_CPU_SYSREG(name) \ |
276 | static int \ | |
277 | sysctl_sysreg_##name SYSCTL_HANDLER_ARGS \ | |
278 | { \ | |
279 | _Pragma("unused(arg1, arg2, oidp)") \ | |
280 | uint64_t return_value = __builtin_arm_rsr64(#name); \ | |
281 | return SYSCTL_OUT(req, &return_value, sizeof(return_value)); \ | |
282 | } \ | |
283 | SYSCTL_PROC(_machdep_cpu, OID_AUTO, sysreg_##name, \ | |
284 | CTLFLAG_RD | CTLTYPE_QUAD | CTLFLAG_LOCKED, \ | |
285 | 0, 0, sysctl_sysreg_##name, "Q", \ | |
286 | #name " register on the current CPU"); | |
287 | ||
288 | ||
289 | // CPU system registers | |
290 | // ARM64: AArch64 Vector Base Address Register | |
291 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(VBAR_EL1); | |
292 | // ARM64: AArch64 Memory Attribute Indirection Register | |
293 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(MAIR_EL1); | |
294 | // ARM64: AArch64 Translation table base register 1 | |
295 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(TTBR1_EL1); | |
296 | // ARM64: AArch64 System Control Register | |
297 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(SCTLR_EL1); | |
298 | // ARM64: AArch64 Translation Control Register | |
299 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(TCR_EL1); | |
300 | // ARM64: AArch64 Memory Model Feature Register 0 | |
301 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(ID_AA64MMFR0_EL1); | |
302 | // ARM64: AArch64 Instruction Set Attribute Register 1 | |
303 | SYSCTL_PROC_MACHDEP_CPU_SYSREG(ID_AA64ISAR1_EL1); | |
cb323159 | 304 | |
2a1bd2d3 | 305 | #endif /* DEVELOPMENT || DEBUG */ |
cb323159 | 306 |