]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/arm64/sysctl.c
xnu-7195.60.75.tar.gz
[apple/xnu.git] / bsd / dev / arm64 / sysctl.c
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
10 #include <mach/host_info.h>
11 #include <mach/mach_host.h>
12 #include <arm/cpuid.h>
13 #include <kern/zalloc.h>
14 #include <libkern/libkern.h>
15 #include <pexpert/device_tree.h>
16
17 #if HYPERVISOR
18 #include <kern/hv_support.h>
19 #endif
20
21 extern uint64_t wake_abstime;
22 extern int lck_mtx_adaptive_spin_mode;
23
24 static
25 SYSCTL_QUAD(_machdep, OID_AUTO, wake_abstime,
26 CTLFLAG_RD, &wake_abstime,
27 "Absolute Time at the last wakeup");
28
29 static int
30 sysctl_time_since_reset SYSCTL_HANDLER_ARGS
31 {
32 #pragma unused(arg1, arg2, oidp)
33 uint64_t return_value = ml_get_time_since_reset();
34 return SYSCTL_OUT(req, &return_value, sizeof(return_value));
35 }
36
37 SYSCTL_PROC(_machdep, OID_AUTO, time_since_reset,
38 CTLFLAG_RD | CTLTYPE_QUAD | CTLFLAG_LOCKED,
39 0, 0, sysctl_time_since_reset, "I",
40 "Continuous time since last SOC boot/wake started");
41
42 static int
43 sysctl_wake_conttime SYSCTL_HANDLER_ARGS
44 {
45 #pragma unused(arg1, arg2, oidp)
46 uint64_t return_value = ml_get_conttime_wake_time();
47 return SYSCTL_OUT(req, &return_value, sizeof(return_value));
48 }
49
50 SYSCTL_PROC(_machdep, OID_AUTO, wake_conttime,
51 CTLFLAG_RD | CTLTYPE_QUAD | CTLFLAG_LOCKED,
52 0, 0, sysctl_wake_conttime, "I",
53 "Continuous Time at the last wakeup");
54
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) */
79
80 /*
81 * For source compatibility, here's some machdep.cpu mibs that
82 * use host_info() to simulate reasonable answers.
83 */
84
85 SYSCTL_NODE(_machdep, OID_AUTO, cpu, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
86 "CPU info");
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;
95 #define BSD_HOST 1
96 kern_return_t kret = host_info((host_t)BSD_HOST,
97 HOST_BASIC_INFO, (host_info_t)&hinfo, &count);
98 if (KERN_SUCCESS != kret) {
99 return EINVAL;
100 }
101
102 if (sizeof(uint32_t) != arg2) {
103 panic("size mismatch");
104 }
105
106 uintptr_t woffset = (uintptr_t)arg1 / sizeof(uint32_t);
107 uint32_t datum = *(uint32_t *)(((uint32_t *)&hinfo) + woffset);
108 return SYSCTL_OUT(req, &datum, sizeof(datum));
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,
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");
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,
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");
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,
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");
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,
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");
163
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
201 /*
202 * machdep.cpu.brand_string
203 *
204 * x86: derived from CPUID data.
205 * ARM: Grab the product string from the device tree, if it exists.
206 * Otherwise, cons something up from the CPUID register.
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
216 if (brand_string != NULL) {
217 return SYSCTL_OUT(req, brand_string, brand_string_len);
218 }
219
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 }
233
234
235 char buf[80];
236 snprintf(buf, sizeof(buf), "%s processor", impl);
237 return SYSCTL_OUT(req, buf, strlen(buf) + 1);
238 }
239
240 SYSCTL_PROC(_machdep_cpu, OID_AUTO, brand_string,
241 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
242 0, 0, make_brand_string, "A", "CPU brand string");
243
244
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
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
264
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");
270
271 /*
272 * macro to generate a sysctl machdep.cpu.sysreg_* for a given system register
273 * using __builtin_arm_rsr64.
274 */
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);
304
305 #endif /* DEVELOPMENT || DEBUG */
306