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