2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
5 #include <sys/kernel.h>
6 #include <sys/sysctl.h>
8 #include <machine/machine_routines.h>
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>
18 #include <kern/hv_support.h>
21 extern uint64_t wake_abstime
;
22 extern int lck_mtx_adaptive_spin_mode
;
25 SYSCTL_QUAD(_machdep
, OID_AUTO
, wake_abstime
,
26 CTLFLAG_RD
, &wake_abstime
,
27 "Absolute Time at the last wakeup");
30 sysctl_time_since_reset SYSCTL_HANDLER_ARGS
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
));
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");
43 sysctl_wake_conttime SYSCTL_HANDLER_ARGS
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
));
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");
57 cpu_signal_deferred_timer(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
62 int old_value
= (int)ml_cpu_signal_deferred_get_timer();
64 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
66 if (error
== 0 && changed
) {
67 ml_cpu_signal_deferred_adjust_timer((uint64_t)new_value
);
73 SYSCTL_PROC(_machdep
, OID_AUTO
, deferred_ipi_timeout
,
74 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
76 cpu_signal_deferred_timer
, "I", "Deferred IPI timeout (nanoseconds)");
78 #endif /* defined(HAS_IPI) */
81 * For source compatibility, here's some machdep.cpu mibs that
82 * use host_info() to simulate reasonable answers.
85 SYSCTL_NODE(_machdep
, OID_AUTO
, cpu
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
89 arm_host_info SYSCTL_HANDLER_ARGS
91 __unused
struct sysctl_oid
*unused_oidp
= oidp
;
93 host_basic_info_data_t hinfo
;
94 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
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
) {
102 if (sizeof(uint32_t) != arg2
) {
103 panic("size mismatch");
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
));
112 * machdep.cpu.cores_per_package
114 * x86: derived from CPUID data.
115 * ARM: how many physical cores we have in the AP; aka hw.physicalcpu_max
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
),
122 arm_host_info
, "I", "CPU cores per package");
125 * machdep.cpu.core_count
127 * x86: derived from CPUID data.
128 * ARM: # active physical cores in the AP; aka hw.physicalcpu
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
),
135 arm_host_info
, "I", "Number of enabled cores per package");
138 * machdep.cpu.logical_per_package
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
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
),
149 arm_host_info
, "I", "CPU logical cpus per package");
152 * machdep.cpu.thread_count
154 * x86: derived from CPUID data.
155 * ARM: # active logical cores in the AP; aka hw.logicalcpu
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
),
162 arm_host_info
, "I", "Number of enabled threads per package");
164 static SECURITY_READ_ONLY_LATE(char*) brand_string
= NULL
;
165 static SECURITY_READ_ONLY_LATE(size_t) brand_string_len
= 0;
168 * SecureDTLookupEntry() is only guaranteed to work before PE_init_iokit(),
169 * so we load the brand string (if available) in a startup handler.
173 sysctl_load_brand_string(void)
176 void const *value
= NULL
;
177 unsigned int size
= 0;
179 if (kSuccess
!= SecureDTLookupEntry(0, "/product", &node
)) {
183 if (kSuccess
!= SecureDTGetProperty(node
, "product-soc-name", (void const **) &value
, &size
)) {
191 brand_string
= zalloc_permanent(size
, ZALIGN_NONE
);
192 if (brand_string
== NULL
) {
196 memcpy(brand_string
, value
, size
);
197 brand_string_len
= size
;
199 STARTUP(SYSCTL
, STARTUP_RANK_MIDDLE
, sysctl_load_brand_string
);
202 * machdep.cpu.brand_string
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.
210 make_brand_string SYSCTL_HANDLER_ARGS
212 __unused
struct sysctl_oid
*unused_oidp
= oidp
;
213 __unused
void *unused_arg1
= arg1
;
214 __unused
int unused_arg2
= arg2
;
216 if (brand_string
!= NULL
) {
217 return SYSCTL_OUT(req
, brand_string
, brand_string_len
);
222 switch (cpuid_info()->arm_info
.arm_implementor
) {
230 impl
= "ARM architecture";
236 snprintf(buf
, sizeof(buf
), "%s processor", impl
);
237 return SYSCTL_OUT(req
, buf
, strlen(buf
) + 1);
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");
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");
251 virtual_address_size SYSCTL_HANDLER_ARGS
253 #pragma unused(arg1, arg2, oidp)
254 int return_value
= 64 - T0SZ_BOOT
;
255 return SYSCTL_OUT(req
, &return_value
, sizeof(return_value
));
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");
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");
272 * macro to generate a sysctl machdep.cpu.sysreg_* for a given system register
273 * using __builtin_arm_rsr64.
275 #define SYSCTL_PROC_MACHDEP_CPU_SYSREG(name) \
277 sysctl_sysreg_##name SYSCTL_HANDLER_ARGS \
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)); \
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");
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
);
305 #endif /* DEVELOPMENT || DEBUG */