]>
Commit | Line | Data |
---|---|---|
43866e37 | 1 | /* |
0a7de745 | 2 | * Copyright (c) 2003-2019 Apple Inc. All rights reserved. |
43866e37 | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
43866e37 A |
27 | */ |
28 | ||
55e303ae A |
29 | /* |
30 | * Here's what to do if you want to add a new routine to the comm page: | |
31 | * | |
0c530ab8 | 32 | * 1. Add a definition for it's address in osfmk/i386/cpu_capabilities.h, |
55e303ae A |
33 | * being careful to reserve room for future expansion. |
34 | * | |
35 | * 2. Write one or more versions of the routine, each with it's own | |
36 | * commpage_descriptor. The tricky part is getting the "special", | |
37 | * "musthave", and "canthave" fields right, so that exactly one | |
38 | * version of the routine is selected for every machine. | |
0c530ab8 | 39 | * The source files should be in osfmk/i386/commpage/. |
55e303ae A |
40 | * |
41 | * 3. Add a ptr to your new commpage_descriptor(s) in the "routines" | |
0c530ab8 A |
42 | * array in osfmk/i386/commpage/commpage_asm.s. There are two |
43 | * arrays, one for the 32-bit and one for the 64-bit commpage. | |
55e303ae A |
44 | * |
45 | * 4. Write the code in Libc to use the new routine. | |
46 | */ | |
47 | ||
48 | #include <mach/mach_types.h> | |
49 | #include <mach/machine.h> | |
91447636 | 50 | #include <mach/vm_map.h> |
b0d623f7 | 51 | #include <mach/mach_vm.h> |
7e4a7d39 A |
52 | #include <mach/machine.h> |
53 | #include <i386/cpuid.h> | |
2d21ac55 | 54 | #include <i386/tsc.h> |
6d2010ae | 55 | #include <i386/rtclock_protos.h> |
2d21ac55 | 56 | #include <i386/cpu_data.h> |
b0d623f7 A |
57 | #include <i386/machine_routines.h> |
58 | #include <i386/misc_protos.h> | |
7e4a7d39 | 59 | #include <i386/cpuid.h> |
43866e37 A |
60 | #include <machine/cpu_capabilities.h> |
61 | #include <machine/commpage.h> | |
55e303ae A |
62 | #include <machine/pmap.h> |
63 | #include <vm/vm_kern.h> | |
91447636 | 64 | #include <vm/vm_map.h> |
5ba3f43e | 65 | #include <stdatomic.h> |
b0d623f7 | 66 | |
91447636 A |
67 | #include <ipc/ipc_port.h> |
68 | ||
0c530ab8 | 69 | #include <kern/page_decrypt.h> |
6d2010ae | 70 | #include <kern/processor.h> |
4452a7af | 71 | |
a1c7dba1 A |
72 | #include <sys/kdebug.h> |
73 | ||
3e170ce0 A |
74 | #if CONFIG_ATM |
75 | #include <atm/atm_internal.h> | |
76 | #endif | |
77 | ||
0c530ab8 | 78 | /* the lists of commpage routines are in commpage_asm.s */ |
0a7de745 A |
79 | extern commpage_descriptor* commpage_32_routines[]; |
80 | extern commpage_descriptor* commpage_64_routines[]; | |
4452a7af | 81 | |
0a7de745 A |
82 | extern vm_map_t commpage32_map; // the shared submap, set up in vm init |
83 | extern vm_map_t commpage64_map; // the shared submap, set up in vm init | |
84 | extern vm_map_t commpage_text32_map; // the shared submap, set up in vm init | |
85 | extern vm_map_t commpage_text64_map; // the shared submap, set up in vm init | |
316670eb | 86 | |
4452a7af | 87 | |
0a7de745 A |
88 | char *commPagePtr32 = NULL; // virtual addr in kernel map of 32-bit commpage |
89 | char *commPagePtr64 = NULL; // ...and of 64-bit commpage | |
90 | char *commPageTextPtr32 = NULL; // virtual addr in kernel map of 32-bit commpage | |
91 | char *commPageTextPtr64 = NULL; // ...and of 64-bit commpage | |
6601e61a | 92 | |
bd504ef0 | 93 | uint64_t _cpu_capabilities = 0; // define the capability vector |
0c530ab8 | 94 | |
b0d623f7 A |
95 | typedef uint32_t commpage_address_t; |
96 | ||
0a7de745 | 97 | static commpage_address_t next; // next available address in comm page |
0c530ab8 | 98 | |
0a7de745 A |
99 | static char *commPagePtr; // virtual addr in kernel map of commpage we are working on |
100 | static commpage_address_t commPageBaseOffset; // subtract from 32-bit runtime address to get offset in virtual commpage in kernel map | |
55e303ae | 101 | |
0a7de745 A |
102 | static commpage_time_data *time_data32 = NULL; |
103 | static commpage_time_data *time_data64 = NULL; | |
5ba3f43e A |
104 | static new_commpage_timeofday_data_t *gtod_time_data32 = NULL; |
105 | static new_commpage_timeofday_data_t *gtod_time_data64 = NULL; | |
106 | ||
2d21ac55 | 107 | |
0a7de745 | 108 | decl_simple_lock_data(static, commpage_active_cpus_lock); |
6d2010ae | 109 | |
55e303ae | 110 | /* Allocate the commpage and add to the shared submap created by vm: |
0a7de745 | 111 | * 1. allocate a page in the kernel map (RW) |
55e303ae A |
112 | * 2. wire it down |
113 | * 3. make a memory entry out of it | |
114 | * 4. map that entry into the shared comm region map (R-only) | |
115 | */ | |
116 | ||
117 | static void* | |
0a7de745 A |
118 | commpage_allocate( |
119 | vm_map_t submap, // commpage32_map or commpage_map64 | |
120 | size_t area_used, // _COMM_PAGE32_AREA_USED or _COMM_PAGE64_AREA_USED | |
121 | vm_prot_t uperm) | |
55e303ae | 122 | { |
0a7de745 A |
123 | vm_offset_t kernel_addr = 0; // address of commpage in kernel map |
124 | vm_offset_t zero = 0; | |
125 | vm_size_t size = area_used; // size actually populated | |
126 | vm_map_entry_t entry; | |
127 | ipc_port_t handle; | |
128 | kern_return_t kr; | |
d9a64523 | 129 | vm_map_kernel_flags_t vmk_flags; |
0c530ab8 | 130 | |
0a7de745 | 131 | if (submap == NULL) { |
0c530ab8 | 132 | panic("commpage submap is null"); |
0a7de745 | 133 | } |
0c530ab8 | 134 | |
d9a64523 | 135 | kr = vm_map_kernel(kernel_map, |
0a7de745 A |
136 | &kernel_addr, |
137 | area_used, | |
138 | 0, | |
139 | VM_FLAGS_ANYWHERE, | |
140 | VM_MAP_KERNEL_FLAGS_NONE, | |
141 | VM_KERN_MEMORY_OSFMK, | |
142 | NULL, | |
143 | 0, | |
144 | FALSE, | |
145 | VM_PROT_ALL, | |
146 | VM_PROT_ALL, | |
147 | VM_INHERIT_NONE); | |
148 | if (kr != KERN_SUCCESS) { | |
316670eb | 149 | panic("cannot allocate commpage %d", kr); |
0a7de745 | 150 | } |
0c530ab8 | 151 | |
5ba3f43e | 152 | if ((kr = vm_map_wire_kernel(kernel_map, |
0a7de745 A |
153 | kernel_addr, |
154 | kernel_addr + area_used, | |
155 | VM_PROT_DEFAULT, VM_KERN_MEMORY_OSFMK, | |
156 | FALSE))) { | |
316670eb | 157 | panic("cannot wire commpage: %d", kr); |
0a7de745 | 158 | } |
0c530ab8 | 159 | |
0a7de745 | 160 | /* |
0c530ab8 A |
161 | * Now that the object is created and wired into the kernel map, mark it so that no delay |
162 | * copy-on-write will ever be performed on it as a result of mapping it into user-space. | |
163 | * If such a delayed copy ever occurred, we could remove the kernel's wired mapping - and | |
164 | * that would be a real disaster. | |
165 | * | |
166 | * JMM - What we really need is a way to create it like this in the first place. | |
167 | */ | |
0a7de745 | 168 | if (!(kr = vm_map_lookup_entry( kernel_map, vm_map_trunc_page(kernel_addr, VM_MAP_PAGE_MASK(kernel_map)), &entry) || entry->is_sub_map)) { |
316670eb | 169 | panic("cannot find commpage entry %d", kr); |
0a7de745 | 170 | } |
3e170ce0 | 171 | VME_OBJECT(entry)->copy_strategy = MEMORY_OBJECT_COPY_NONE; |
0c530ab8 | 172 | |
0a7de745 A |
173 | if ((kr = mach_make_memory_entry( kernel_map, // target map |
174 | &size, // size | |
175 | kernel_addr, // offset (address in kernel map) | |
176 | uperm, // protections as specified | |
177 | &handle, // this is the object handle we get | |
178 | NULL ))) { // parent_entry (what is this?) | |
316670eb | 179 | panic("cannot make entry for commpage %d", kr); |
0a7de745 | 180 | } |
0c530ab8 | 181 | |
d9a64523 A |
182 | vmk_flags = VM_MAP_KERNEL_FLAGS_NONE; |
183 | if (uperm == (VM_PROT_READ | VM_PROT_EXECUTE)) { | |
184 | /* | |
185 | * Mark this unsigned executable mapping as "jit" to avoid | |
186 | * code-signing violations when attempting to execute unsigned | |
187 | * code. | |
188 | */ | |
189 | vmk_flags.vmkf_map_jit = TRUE; | |
190 | } | |
191 | ||
192 | kr = vm_map_64_kernel( | |
0a7de745 A |
193 | submap, // target map (shared submap) |
194 | &zero, // address (map into 1st page in submap) | |
195 | area_used, // size | |
196 | 0, // mask | |
197 | VM_FLAGS_FIXED, // flags (it must be 1st page in submap) | |
d9a64523 A |
198 | vmk_flags, |
199 | VM_KERN_MEMORY_NONE, | |
0a7de745 A |
200 | handle, // port is the memory entry we just made |
201 | 0, // offset (map 1st page in memory entry) | |
202 | FALSE, // copy | |
203 | uperm, // cur_protection (R-only in user map) | |
204 | uperm, // max_protection | |
205 | VM_INHERIT_SHARE); // inheritance | |
206 | if (kr != KERN_SUCCESS) { | |
316670eb | 207 | panic("cannot map commpage %d", kr); |
0a7de745 | 208 | } |
0c530ab8 A |
209 | |
210 | ipc_port_release(handle); | |
316670eb A |
211 | /* Make the kernel mapping non-executable. This cannot be done |
212 | * at the time of map entry creation as mach_make_memory_entry | |
213 | * cannot handle disjoint permissions at this time. | |
214 | */ | |
215 | kr = vm_protect(kernel_map, kernel_addr, area_used, FALSE, VM_PROT_READ | VM_PROT_WRITE); | |
0a7de745 | 216 | assert(kr == KERN_SUCCESS); |
0c530ab8 | 217 | |
b0d623f7 | 218 | return (void*)(intptr_t)kernel_addr; // return address in kernel map |
55e303ae A |
219 | } |
220 | ||
221 | /* Get address (in kernel map) of a commpage field. */ | |
222 | ||
91447636 | 223 | static void* |
55e303ae | 224 | commpage_addr_of( |
0a7de745 | 225 | commpage_address_t addr_at_runtime ) |
55e303ae | 226 | { |
0a7de745 A |
227 | return (void*) ((uintptr_t)commPagePtr + (addr_at_runtime - commPageBaseOffset)); |
228 | } | |
229 | ||
230 | /* | |
231 | * Calculate address of data within 32- and 64-bit commpages (not to be used with commpage | |
232 | * text). | |
233 | */ | |
234 | static void* | |
235 | commpage_specific_addr_of(char *commPageBase, commpage_address_t addr_at_runtime) | |
236 | { | |
237 | /* | |
238 | * Note that the base address (_COMM_PAGE32_BASE_ADDRESS) is the same for | |
239 | * 32- and 64-bit commpages | |
240 | */ | |
241 | return (void*) ((uintptr_t)commPageBase + (addr_at_runtime - _COMM_PAGE32_BASE_ADDRESS)); | |
55e303ae A |
242 | } |
243 | ||
244 | /* Determine number of CPUs on this system. We cannot rely on | |
245 | * machine_info.max_cpus this early in the boot. | |
246 | */ | |
247 | static int | |
248 | commpage_cpus( void ) | |
249 | { | |
250 | int cpus; | |
251 | ||
252 | cpus = ml_get_max_cpus(); // NB: this call can block | |
253 | ||
0a7de745 | 254 | if (cpus == 0) { |
55e303ae | 255 | panic("commpage cpus==0"); |
0a7de745 A |
256 | } |
257 | if (cpus > 0xFF) { | |
55e303ae | 258 | cpus = 0xFF; |
0a7de745 | 259 | } |
55e303ae A |
260 | |
261 | return cpus; | |
262 | } | |
43866e37 | 263 | |
55e303ae | 264 | /* Initialize kernel version of _cpu_capabilities vector (used by KEXTs.) */ |
43866e37 | 265 | |
55e303ae A |
266 | static void |
267 | commpage_init_cpu_capabilities( void ) | |
268 | { | |
bd504ef0 | 269 | uint64_t bits; |
55e303ae A |
270 | int cpus; |
271 | ml_cpu_info_t cpu_info; | |
43866e37 | 272 | |
55e303ae A |
273 | bits = 0; |
274 | ml_cpu_get_info(&cpu_info); | |
0a7de745 | 275 | |
55e303ae | 276 | switch (cpu_info.vector_unit) { |
0a7de745 A |
277 | case 9: |
278 | bits |= kHasAVX1_0; | |
279 | /* fall thru */ | |
280 | case 8: | |
281 | bits |= kHasSSE4_2; | |
282 | /* fall thru */ | |
283 | case 7: | |
284 | bits |= kHasSSE4_1; | |
285 | /* fall thru */ | |
286 | case 6: | |
287 | bits |= kHasSupplementalSSE3; | |
288 | /* fall thru */ | |
289 | case 5: | |
290 | bits |= kHasSSE3; | |
291 | /* fall thru */ | |
292 | case 4: | |
293 | bits |= kHasSSE2; | |
294 | /* fall thru */ | |
295 | case 3: | |
296 | bits |= kHasSSE; | |
297 | /* fall thru */ | |
298 | case 2: | |
299 | bits |= kHasMMX; | |
300 | default: | |
301 | break; | |
55e303ae A |
302 | } |
303 | switch (cpu_info.cache_line_size) { | |
0a7de745 A |
304 | case 128: |
305 | bits |= kCache128; | |
306 | break; | |
307 | case 64: | |
308 | bits |= kCache64; | |
309 | break; | |
310 | case 32: | |
311 | bits |= kCache32; | |
312 | break; | |
313 | default: | |
314 | break; | |
315 | } | |
316 | cpus = commpage_cpus(); // how many CPUs do we have | |
55e303ae | 317 | |
55e303ae A |
318 | bits |= (cpus << kNumCPUsShift); |
319 | ||
0a7de745 | 320 | bits |= kFastThreadLocalStorage; // we use %gs for TLS |
91447636 | 321 | |
bd504ef0 A |
322 | #define setif(_bits, _bit, _condition) \ |
323 | if (_condition) _bits |= _bit | |
324 | ||
0a7de745 A |
325 | setif(bits, kUP, cpus == 1); |
326 | setif(bits, k64Bit, cpu_mode_is64bit()); | |
327 | setif(bits, kSlow, tscFreq <= SLOW_TSC_THRESHOLD); | |
328 | ||
329 | setif(bits, kHasAES, cpuid_features() & | |
330 | CPUID_FEATURE_AES); | |
331 | setif(bits, kHasF16C, cpuid_features() & | |
332 | CPUID_FEATURE_F16C); | |
333 | setif(bits, kHasRDRAND, cpuid_features() & | |
334 | CPUID_FEATURE_RDRAND); | |
335 | setif(bits, kHasFMA, cpuid_features() & | |
336 | CPUID_FEATURE_FMA); | |
337 | ||
338 | setif(bits, kHasBMI1, cpuid_leaf7_features() & | |
339 | CPUID_LEAF7_FEATURE_BMI1); | |
340 | setif(bits, kHasBMI2, cpuid_leaf7_features() & | |
341 | CPUID_LEAF7_FEATURE_BMI2); | |
342 | /* Do not advertise RTM and HLE if the TSX FORCE ABORT WA is required */ | |
343 | if (cpuid_wa_required(CPU_INTEL_TSXFA) & CWA_OFF) { | |
344 | setif(bits, kHasRTM, cpuid_leaf7_features() & | |
345 | CPUID_LEAF7_FEATURE_RTM); | |
346 | setif(bits, kHasHLE, cpuid_leaf7_features() & | |
347 | CPUID_LEAF7_FEATURE_HLE); | |
348 | } | |
349 | setif(bits, kHasAVX2_0, cpuid_leaf7_features() & | |
350 | CPUID_LEAF7_FEATURE_AVX2); | |
351 | setif(bits, kHasRDSEED, cpuid_leaf7_features() & | |
352 | CPUID_LEAF7_FEATURE_RDSEED); | |
353 | setif(bits, kHasADX, cpuid_leaf7_features() & | |
354 | CPUID_LEAF7_FEATURE_ADX); | |
355 | ||
356 | #if 0 /* The kernel doesn't support MPX or SGX */ | |
357 | setif(bits, kHasMPX, cpuid_leaf7_features() & | |
358 | CPUID_LEAF7_FEATURE_MPX); | |
359 | setif(bits, kHasSGX, cpuid_leaf7_features() & | |
360 | CPUID_LEAF7_FEATURE_SGX); | |
5ba3f43e A |
361 | #endif |
362 | ||
5ba3f43e | 363 | if (ml_fpu_avx512_enabled()) { |
0a7de745 A |
364 | setif(bits, kHasAVX512F, cpuid_leaf7_features() & |
365 | CPUID_LEAF7_FEATURE_AVX512F); | |
366 | setif(bits, kHasAVX512CD, cpuid_leaf7_features() & | |
367 | CPUID_LEAF7_FEATURE_AVX512CD); | |
368 | setif(bits, kHasAVX512DQ, cpuid_leaf7_features() & | |
369 | CPUID_LEAF7_FEATURE_AVX512DQ); | |
370 | setif(bits, kHasAVX512BW, cpuid_leaf7_features() & | |
371 | CPUID_LEAF7_FEATURE_AVX512BW); | |
372 | setif(bits, kHasAVX512VL, cpuid_leaf7_features() & | |
373 | CPUID_LEAF7_FEATURE_AVX512VL); | |
5ba3f43e | 374 | setif(bits, kHasAVX512IFMA, cpuid_leaf7_features() & |
0a7de745 | 375 | CPUID_LEAF7_FEATURE_AVX512IFMA); |
5ba3f43e | 376 | setif(bits, kHasAVX512VBMI, cpuid_leaf7_features() & |
0a7de745 | 377 | CPUID_LEAF7_FEATURE_AVX512VBMI); |
cb323159 A |
378 | setif(bits, kHasVAES, cpuid_leaf7_features() & |
379 | CPUID_LEAF7_FEATURE_VAES); | |
380 | setif(bits, kHasVPCLMULQDQ, cpuid_leaf7_features() & | |
381 | CPUID_LEAF7_FEATURE_VPCLMULQDQ); | |
382 | setif(bits, kHasAVX512VNNI, cpuid_leaf7_features() & | |
383 | CPUID_LEAF7_FEATURE_AVX512VNNI); | |
384 | setif(bits, kHasAVX512BITALG, cpuid_leaf7_features() & | |
385 | CPUID_LEAF7_FEATURE_AVX512BITALG); | |
386 | setif(bits, kHasAVX512VPOPCNTDQ, cpuid_leaf7_features() & | |
387 | CPUID_LEAF7_FEATURE_AVX512VPCDQ); | |
5ba3f43e A |
388 | } |
389 | ||
bd504ef0 A |
390 | uint64_t misc_enable = rdmsr64(MSR_IA32_MISC_ENABLE); |
391 | setif(bits, kHasENFSTRG, (misc_enable & 1ULL) && | |
0a7de745 A |
392 | (cpuid_leaf7_features() & |
393 | CPUID_LEAF7_FEATURE_ERMS)); | |
394 | ||
395 | _cpu_capabilities = bits; // set kernel version for use by drivers etc | |
55e303ae A |
396 | } |
397 | ||
fe8ab488 A |
398 | /* initialize the approx_time_supported flag and set the approx time to 0. |
399 | * Called during initial commpage population. | |
400 | */ | |
401 | static void | |
402 | commpage_mach_approximate_time_init(void) | |
403 | { | |
39037602 | 404 | char *cp = commPagePtr32; |
fe8ab488 A |
405 | uint8_t supported; |
406 | ||
407 | #ifdef CONFIG_MACH_APPROXIMATE_TIME | |
408 | supported = 1; | |
409 | #else | |
410 | supported = 0; | |
411 | #endif | |
0a7de745 | 412 | if (cp) { |
39037602 | 413 | cp += (_COMM_PAGE_APPROX_TIME_SUPPORTED - _COMM_PAGE32_BASE_ADDRESS); |
fe8ab488 A |
414 | *(boolean_t *)cp = supported; |
415 | } | |
0a7de745 | 416 | |
39037602 | 417 | cp = commPagePtr64; |
0a7de745 | 418 | if (cp) { |
39037602 | 419 | cp += (_COMM_PAGE_APPROX_TIME_SUPPORTED - _COMM_PAGE32_START_ADDRESS); |
fe8ab488 A |
420 | *(boolean_t *)cp = supported; |
421 | } | |
422 | commpage_update_mach_approximate_time(0); | |
423 | } | |
424 | ||
39037602 A |
425 | static void |
426 | commpage_mach_continuous_time_init(void) | |
427 | { | |
428 | commpage_update_mach_continuous_time(0); | |
429 | } | |
430 | ||
431 | static void | |
432 | commpage_boottime_init(void) | |
433 | { | |
434 | clock_sec_t secs; | |
435 | clock_usec_t microsecs; | |
436 | clock_get_boottime_microtime(&secs, µsecs); | |
437 | commpage_update_boottime(secs * USEC_PER_SEC + microsecs); | |
438 | } | |
fe8ab488 | 439 | |
bd504ef0 | 440 | uint64_t |
2d21ac55 | 441 | _get_cpu_capabilities(void) |
0c530ab8 A |
442 | { |
443 | return _cpu_capabilities; | |
444 | } | |
445 | ||
55e303ae A |
446 | /* Copy data into commpage. */ |
447 | ||
448 | static void | |
449 | commpage_stuff( | |
0a7de745 A |
450 | commpage_address_t address, |
451 | const void *source, | |
452 | int length ) | |
453 | { | |
454 | void *dest = commpage_addr_of(address); | |
455 | ||
456 | if (address < next) { | |
457 | panic("commpage overlap at address 0x%p, 0x%x < 0x%x", dest, address, next); | |
458 | } | |
459 | ||
460 | bcopy(source, dest, length); | |
461 | ||
462 | next = address + length; | |
463 | } | |
464 | ||
465 | /* | |
466 | * Updates both the 32-bit and 64-bit commpages with the new data. | |
467 | */ | |
468 | static void | |
469 | commpage_update(commpage_address_t address, const void *source, int length) | |
470 | { | |
471 | void *dest = commpage_specific_addr_of(commPagePtr32, address); | |
472 | bcopy(source, dest, length); | |
473 | ||
474 | dest = commpage_specific_addr_of(commPagePtr64, address); | |
475 | bcopy(source, dest, length); | |
476 | } | |
477 | ||
478 | void | |
479 | commpage_post_ucode_update(void) | |
480 | { | |
481 | commpage_init_cpu_capabilities(); | |
482 | commpage_update(_COMM_PAGE_CPU_CAPABILITIES64, &_cpu_capabilities, sizeof(_cpu_capabilities)); | |
483 | commpage_update(_COMM_PAGE_CPU_CAPABILITIES, &_cpu_capabilities, sizeof(uint32_t)); | |
55e303ae A |
484 | } |
485 | ||
486 | /* Copy a routine into comm page if it matches running machine. | |
487 | */ | |
488 | static void | |
489 | commpage_stuff_routine( | |
0a7de745 | 490 | commpage_descriptor *rd ) |
55e303ae | 491 | { |
0a7de745 | 492 | commpage_stuff(rd->commpage_address, rd->code_address, rd->code_length); |
55e303ae A |
493 | } |
494 | ||
cb323159 | 495 | |
0c530ab8 | 496 | /* Fill in the 32- or 64-bit commpage. Called once for each. |
55e303ae A |
497 | */ |
498 | ||
0c530ab8 | 499 | static void |
0a7de745 A |
500 | commpage_populate_one( |
501 | vm_map_t submap, // commpage32_map or compage64_map | |
502 | char ** kernAddressPtr, // &commPagePtr32 or &commPagePtr64 | |
503 | size_t area_used, // _COMM_PAGE32_AREA_USED or _COMM_PAGE64_AREA_USED | |
504 | commpage_address_t base_offset, // will become commPageBaseOffset | |
505 | commpage_time_data** time_data, // &time_data32 or &time_data64 | |
5ba3f43e | 506 | new_commpage_timeofday_data_t** gtod_time_data, // >od_time_data32 or >od_time_data64 |
0a7de745 A |
507 | const char* signature, // "commpage 32-bit" or "commpage 64-bit" |
508 | vm_prot_t uperm) | |
55e303ae | 509 | { |
0a7de745 A |
510 | uint8_t c1; |
511 | uint16_t c2; | |
512 | int c4; | |
513 | uint64_t c8; | |
514 | uint32_t cfamily; | |
55e303ae | 515 | short version = _COMM_PAGE_THIS_VERSION; |
55e303ae | 516 | |
b0d623f7 | 517 | next = 0; |
316670eb | 518 | commPagePtr = (char *)commpage_allocate( submap, (vm_size_t) area_used, uperm ); |
0a7de745 | 519 | *kernAddressPtr = commPagePtr; // save address either in commPagePtr32 or 64 |
0c530ab8 | 520 | commPageBaseOffset = base_offset; |
b0d623f7 | 521 | |
2d21ac55 | 522 | *time_data = commpage_addr_of( _COMM_PAGE_TIME_DATA_START ); |
5ba3f43e | 523 | *gtod_time_data = commpage_addr_of( _COMM_PAGE_NEWTIMEOFDAY_DATA ); |
55e303ae A |
524 | |
525 | /* Stuff in the constants. We move things into the comm page in strictly | |
0a7de745 A |
526 | * ascending order, so we can check for overlap and panic if so. |
527 | * Note: the 32-bit cpu_capabilities vector is retained in addition to | |
528 | * the expanded 64-bit vector. | |
529 | */ | |
530 | commpage_stuff(_COMM_PAGE_SIGNATURE, signature, (int)MIN(_COMM_PAGE_SIGNATURELEN, strlen(signature))); | |
531 | commpage_stuff(_COMM_PAGE_CPU_CAPABILITIES64, &_cpu_capabilities, sizeof(_cpu_capabilities)); | |
532 | commpage_stuff(_COMM_PAGE_VERSION, &version, sizeof(short)); | |
533 | commpage_stuff(_COMM_PAGE_CPU_CAPABILITIES, &_cpu_capabilities, sizeof(uint32_t)); | |
0c530ab8 | 534 | |
6d2010ae | 535 | c2 = 32; // default |
0a7de745 | 536 | if (_cpu_capabilities & kCache64) { |
91447636 | 537 | c2 = 64; |
0a7de745 | 538 | } else if (_cpu_capabilities & kCache128) { |
91447636 | 539 | c2 = 128; |
0a7de745 A |
540 | } |
541 | commpage_stuff(_COMM_PAGE_CACHE_LINESIZE, &c2, 2); | |
bd504ef0 | 542 | |
b0d623f7 | 543 | c4 = MP_SPIN_TRIES; |
0a7de745 | 544 | commpage_stuff(_COMM_PAGE_SPIN_COUNT, &c4, 4); |
91447636 | 545 | |
6d2010ae A |
546 | /* machine_info valid after ml_get_max_cpus() */ |
547 | c1 = machine_info.physical_cpu_max; | |
0a7de745 | 548 | commpage_stuff(_COMM_PAGE_PHYSICAL_CPUS, &c1, 1); |
6d2010ae | 549 | c1 = machine_info.logical_cpu_max; |
0a7de745 | 550 | commpage_stuff(_COMM_PAGE_LOGICAL_CPUS, &c1, 1); |
6d2010ae A |
551 | |
552 | c8 = ml_cpu_cache_size(0); | |
553 | commpage_stuff(_COMM_PAGE_MEMORY_SIZE, &c8, 8); | |
554 | ||
555 | cfamily = cpuid_info()->cpuid_cpufamily; | |
556 | commpage_stuff(_COMM_PAGE_CPUFAMILY, &cfamily, 4); | |
6601e61a | 557 | |
0a7de745 | 558 | if (next > _COMM_PAGE_END) { |
b0d623f7 | 559 | panic("commpage overflow: next = 0x%08x, commPagePtr = 0x%p", next, commPagePtr); |
0a7de745 | 560 | } |
43866e37 | 561 | } |
91447636 | 562 | |
0c530ab8 A |
563 | |
564 | /* Fill in commpages: called once, during kernel initialization, from the | |
565 | * startup thread before user-mode code is running. | |
566 | * | |
567 | * See the top of this file for a list of what you have to do to add | |
568 | * a new routine to the commpage. | |
0a7de745 | 569 | */ |
91447636 A |
570 | |
571 | void | |
0c530ab8 | 572 | commpage_populate( void ) |
91447636 | 573 | { |
0c530ab8 | 574 | commpage_init_cpu_capabilities(); |
0a7de745 A |
575 | |
576 | commpage_populate_one( commpage32_map, | |
577 | &commPagePtr32, | |
578 | _COMM_PAGE32_AREA_USED, | |
579 | _COMM_PAGE32_BASE_ADDRESS, | |
580 | &time_data32, | |
581 | >od_time_data32, | |
cb323159 | 582 | _COMM_PAGE32_SIGNATURE_STRING, |
0a7de745 | 583 | VM_PROT_READ); |
b0d623f7 | 584 | #ifndef __LP64__ |
0a7de745 A |
585 | pmap_commpage32_init((vm_offset_t) commPagePtr32, _COMM_PAGE32_BASE_ADDRESS, |
586 | _COMM_PAGE32_AREA_USED / INTEL_PGBYTES); | |
587 | #endif | |
588 | time_data64 = time_data32; /* if no 64-bit commpage, point to 32-bit */ | |
5ba3f43e | 589 | gtod_time_data64 = gtod_time_data32; |
0c530ab8 A |
590 | |
591 | if (_cpu_capabilities & k64Bit) { | |
0a7de745 A |
592 | commpage_populate_one( commpage64_map, |
593 | &commPagePtr64, | |
594 | _COMM_PAGE64_AREA_USED, | |
595 | _COMM_PAGE32_START_ADDRESS, /* commpage address are relative to 32-bit commpage placement */ | |
596 | &time_data64, | |
597 | >od_time_data64, | |
cb323159 | 598 | _COMM_PAGE64_SIGNATURE_STRING, |
0a7de745 | 599 | VM_PROT_READ); |
b0d623f7 | 600 | #ifndef __LP64__ |
0a7de745 A |
601 | pmap_commpage64_init((vm_offset_t) commPagePtr64, _COMM_PAGE64_BASE_ADDRESS, |
602 | _COMM_PAGE64_AREA_USED / INTEL_PGBYTES); | |
b0d623f7 | 603 | #endif |
0c530ab8 | 604 | } |
6601e61a | 605 | |
6d2010ae A |
606 | simple_lock_init(&commpage_active_cpus_lock, 0); |
607 | ||
608 | commpage_update_active_cpus(); | |
a1c7dba1 | 609 | commpage_mach_approximate_time_init(); |
39037602 A |
610 | commpage_mach_continuous_time_init(); |
611 | commpage_boottime_init(); | |
0c530ab8 | 612 | rtc_nanotime_init_commpage(); |
39037602 | 613 | commpage_update_kdebug_state(); |
3e170ce0 A |
614 | #if CONFIG_ATM |
615 | commpage_update_atm_diagnostic_config(atm_get_diagnostic_config()); | |
616 | #endif | |
91447636 | 617 | } |
2d21ac55 | 618 | |
0a7de745 | 619 | /* Fill in the common routines during kernel initialization. |
316670eb A |
620 | * This is called before user-mode code is running. |
621 | */ | |
0a7de745 A |
622 | void |
623 | commpage_text_populate( void ) | |
624 | { | |
316670eb | 625 | commpage_descriptor **rd; |
0a7de745 | 626 | |
bd504ef0 | 627 | next = 0; |
316670eb A |
628 | commPagePtr = (char *) commpage_allocate(commpage_text32_map, (vm_size_t) _COMM_PAGE_TEXT_AREA_USED, VM_PROT_READ | VM_PROT_EXECUTE); |
629 | commPageTextPtr32 = commPagePtr; | |
0a7de745 | 630 | |
316670eb | 631 | char *cptr = commPagePtr; |
0a7de745 A |
632 | int i = 0; |
633 | for (; i < _COMM_PAGE_TEXT_AREA_USED; i++) { | |
634 | cptr[i] = 0xCC; | |
316670eb | 635 | } |
0a7de745 | 636 | |
316670eb A |
637 | commPageBaseOffset = _COMM_PAGE_TEXT_START; |
638 | for (rd = commpage_32_routines; *rd != NULL; rd++) { | |
639 | commpage_stuff_routine(*rd); | |
640 | } | |
316670eb A |
641 | |
642 | #ifndef __LP64__ | |
0a7de745 A |
643 | pmap_commpage32_init((vm_offset_t) commPageTextPtr32, _COMM_PAGE_TEXT_START, |
644 | _COMM_PAGE_TEXT_AREA_USED / INTEL_PGBYTES); | |
645 | #endif | |
316670eb A |
646 | |
647 | if (_cpu_capabilities & k64Bit) { | |
bd504ef0 | 648 | next = 0; |
316670eb A |
649 | commPagePtr = (char *) commpage_allocate(commpage_text64_map, (vm_size_t) _COMM_PAGE_TEXT_AREA_USED, VM_PROT_READ | VM_PROT_EXECUTE); |
650 | commPageTextPtr64 = commPagePtr; | |
651 | ||
0a7de745 A |
652 | cptr = commPagePtr; |
653 | for (i = 0; i < _COMM_PAGE_TEXT_AREA_USED; i++) { | |
654 | cptr[i] = 0xCC; | |
316670eb A |
655 | } |
656 | ||
0a7de745 | 657 | for (rd = commpage_64_routines; *rd != NULL; rd++) { |
316670eb A |
658 | commpage_stuff_routine(*rd); |
659 | } | |
660 | ||
661 | #ifndef __LP64__ | |
0a7de745 A |
662 | pmap_commpage64_init((vm_offset_t) commPageTextPtr64, _COMM_PAGE_TEXT_START, |
663 | _COMM_PAGE_TEXT_AREA_USED / INTEL_PGBYTES); | |
664 | #endif | |
316670eb A |
665 | } |
666 | ||
0a7de745 A |
667 | if (next > _COMM_PAGE_TEXT_END) { |
668 | panic("commpage text overflow: next=0x%08x, commPagePtr=%p", next, commPagePtr); | |
669 | } | |
316670eb | 670 | } |
2d21ac55 | 671 | |
bd504ef0 | 672 | /* Update commpage nanotime information. |
2d21ac55 A |
673 | * |
674 | * This routine must be serialized by some external means, ie a lock. | |
675 | */ | |
676 | ||
677 | void | |
678 | commpage_set_nanotime( | |
0a7de745 A |
679 | uint64_t tsc_base, |
680 | uint64_t ns_base, | |
681 | uint32_t scale, | |
682 | uint32_t shift ) | |
2d21ac55 | 683 | { |
0a7de745 A |
684 | commpage_time_data *p32 = time_data32; |
685 | commpage_time_data *p64 = time_data64; | |
686 | static uint32_t generation = 0; | |
687 | uint32_t next_gen; | |
688 | ||
689 | if (p32 == NULL) { /* have commpages been allocated yet? */ | |
2d21ac55 | 690 | return; |
0a7de745 A |
691 | } |
692 | ||
693 | if (generation != p32->nt_generation) { | |
694 | panic("nanotime trouble 1"); /* possibly not serialized */ | |
695 | } | |
696 | if (ns_base < p32->nt_ns_base) { | |
2d21ac55 | 697 | panic("nanotime trouble 2"); |
0a7de745 A |
698 | } |
699 | if ((shift != 0) && ((_cpu_capabilities & kSlow) == 0)) { | |
2d21ac55 | 700 | panic("nanotime trouble 3"); |
0a7de745 A |
701 | } |
702 | ||
2d21ac55 | 703 | next_gen = ++generation; |
0a7de745 | 704 | if (next_gen == 0) { |
2d21ac55 | 705 | next_gen = ++generation; |
0a7de745 A |
706 | } |
707 | ||
708 | p32->nt_generation = 0; /* mark invalid, so commpage won't try to use it */ | |
2d21ac55 | 709 | p64->nt_generation = 0; |
0a7de745 | 710 | |
2d21ac55 A |
711 | p32->nt_tsc_base = tsc_base; |
712 | p64->nt_tsc_base = tsc_base; | |
0a7de745 | 713 | |
2d21ac55 A |
714 | p32->nt_ns_base = ns_base; |
715 | p64->nt_ns_base = ns_base; | |
0a7de745 | 716 | |
2d21ac55 A |
717 | p32->nt_scale = scale; |
718 | p64->nt_scale = scale; | |
0a7de745 | 719 | |
2d21ac55 A |
720 | p32->nt_shift = shift; |
721 | p64->nt_shift = shift; | |
0a7de745 A |
722 | |
723 | p32->nt_generation = next_gen; /* mark data as valid */ | |
2d21ac55 A |
724 | p64->nt_generation = next_gen; |
725 | } | |
726 | ||
2d21ac55 | 727 | /* Update commpage gettimeofday() information. As with nanotime(), we interleave |
0a7de745 | 728 | * updates to the 32- and 64-bit commpage, in order to keep time more nearly in sync |
2d21ac55 A |
729 | * between the two environments. |
730 | * | |
731 | * This routine must be serializeed by some external means, ie a lock. | |
732 | */ | |
5ba3f43e A |
733 | |
734 | void | |
735 | commpage_set_timestamp( | |
0a7de745 A |
736 | uint64_t abstime, |
737 | uint64_t sec, | |
738 | uint64_t frac, | |
739 | uint64_t scale, | |
740 | uint64_t tick_per_sec) | |
2d21ac55 | 741 | { |
0a7de745 A |
742 | new_commpage_timeofday_data_t *p32 = gtod_time_data32; |
743 | new_commpage_timeofday_data_t *p64 = gtod_time_data64; | |
744 | ||
5ba3f43e A |
745 | p32->TimeStamp_tick = 0x0ULL; |
746 | p64->TimeStamp_tick = 0x0ULL; | |
747 | ||
748 | p32->TimeStamp_sec = sec; | |
749 | p64->TimeStamp_sec = sec; | |
750 | ||
751 | p32->TimeStamp_frac = frac; | |
752 | p64->TimeStamp_frac = frac; | |
b0d623f7 | 753 | |
5ba3f43e A |
754 | p32->Ticks_scale = scale; |
755 | p64->Ticks_scale = scale; | |
756 | ||
757 | p32->Ticks_per_sec = tick_per_sec; | |
758 | p64->Ticks_per_sec = tick_per_sec; | |
759 | ||
760 | p32->TimeStamp_tick = abstime; | |
761 | p64->TimeStamp_tick = abstime; | |
762 | } | |
b0d623f7 A |
763 | |
764 | /* Update _COMM_PAGE_MEMORY_PRESSURE. Called periodically from vm's compute_memory_pressure() */ | |
765 | ||
766 | void | |
767 | commpage_set_memory_pressure( | |
0a7de745 | 768 | unsigned int pressure ) |
b0d623f7 | 769 | { |
0a7de745 | 770 | char *cp; |
b0d623f7 | 771 | uint32_t *ip; |
0a7de745 | 772 | |
b0d623f7 | 773 | cp = commPagePtr32; |
0a7de745 | 774 | if (cp) { |
b0d623f7 | 775 | cp += (_COMM_PAGE_MEMORY_PRESSURE - _COMM_PAGE32_BASE_ADDRESS); |
bd504ef0 | 776 | ip = (uint32_t*) (void *) cp; |
b0d623f7 A |
777 | *ip = (uint32_t) pressure; |
778 | } | |
0a7de745 | 779 | |
b0d623f7 | 780 | cp = commPagePtr64; |
0a7de745 | 781 | if (cp) { |
b0d623f7 | 782 | cp += (_COMM_PAGE_MEMORY_PRESSURE - _COMM_PAGE32_START_ADDRESS); |
bd504ef0 | 783 | ip = (uint32_t*) (void *) cp; |
b0d623f7 A |
784 | *ip = (uint32_t) pressure; |
785 | } | |
b0d623f7 A |
786 | } |
787 | ||
788 | ||
789 | /* Update _COMM_PAGE_SPIN_COUNT. We might want to reduce when running on a battery, etc. */ | |
790 | ||
791 | void | |
792 | commpage_set_spin_count( | |
0a7de745 | 793 | unsigned int count ) |
b0d623f7 | 794 | { |
0a7de745 | 795 | char *cp; |
b0d623f7 | 796 | uint32_t *ip; |
0a7de745 A |
797 | |
798 | if (count == 0) { /* we test for 0 after decrement, not before */ | |
799 | count = 1; | |
800 | } | |
801 | ||
b0d623f7 | 802 | cp = commPagePtr32; |
0a7de745 | 803 | if (cp) { |
b0d623f7 | 804 | cp += (_COMM_PAGE_SPIN_COUNT - _COMM_PAGE32_BASE_ADDRESS); |
bd504ef0 | 805 | ip = (uint32_t*) (void *) cp; |
b0d623f7 A |
806 | *ip = (uint32_t) count; |
807 | } | |
0a7de745 | 808 | |
b0d623f7 | 809 | cp = commPagePtr64; |
0a7de745 | 810 | if (cp) { |
b0d623f7 | 811 | cp += (_COMM_PAGE_SPIN_COUNT - _COMM_PAGE32_START_ADDRESS); |
bd504ef0 | 812 | ip = (uint32_t*) (void *) cp; |
b0d623f7 A |
813 | *ip = (uint32_t) count; |
814 | } | |
b0d623f7 A |
815 | } |
816 | ||
6d2010ae A |
817 | /* Updated every time a logical CPU goes offline/online */ |
818 | void | |
819 | commpage_update_active_cpus(void) | |
820 | { | |
0a7de745 | 821 | char *cp; |
6d2010ae | 822 | volatile uint8_t *ip; |
0a7de745 | 823 | |
6d2010ae | 824 | /* At least 32-bit commpage must be initialized */ |
0a7de745 | 825 | if (!commPagePtr32) { |
6d2010ae | 826 | return; |
0a7de745 | 827 | } |
6d2010ae | 828 | |
0a7de745 | 829 | simple_lock(&commpage_active_cpus_lock, LCK_GRP_NULL); |
6d2010ae A |
830 | |
831 | cp = commPagePtr32; | |
832 | cp += (_COMM_PAGE_ACTIVE_CPUS - _COMM_PAGE32_BASE_ADDRESS); | |
833 | ip = (volatile uint8_t*) cp; | |
0a7de745 A |
834 | *ip = (uint8_t) processor_avail_count_user; |
835 | ||
6d2010ae | 836 | cp = commPagePtr64; |
0a7de745 | 837 | if (cp) { |
6d2010ae A |
838 | cp += (_COMM_PAGE_ACTIVE_CPUS - _COMM_PAGE32_START_ADDRESS); |
839 | ip = (volatile uint8_t*) cp; | |
0a7de745 | 840 | *ip = (uint8_t) processor_avail_count_user; |
6d2010ae A |
841 | } |
842 | ||
843 | simple_unlock(&commpage_active_cpus_lock); | |
844 | } | |
845 | ||
a1c7dba1 | 846 | /* |
39037602 A |
847 | * Update the commpage with current kdebug state. This currently has bits for |
848 | * global trace state, and typefilter enablement. It is likely additional state | |
849 | * will be tracked in the future. | |
850 | * | |
851 | * INVARIANT: This value will always be 0 if global tracing is disabled. This | |
852 | * allows simple guard tests of "if (*_COMM_PAGE_KDEBUG_ENABLE) { ... }" | |
a1c7dba1 A |
853 | */ |
854 | void | |
39037602 | 855 | commpage_update_kdebug_state(void) |
a1c7dba1 A |
856 | { |
857 | volatile uint32_t *saved_data_ptr; | |
858 | char *cp; | |
859 | ||
860 | cp = commPagePtr32; | |
861 | if (cp) { | |
862 | cp += (_COMM_PAGE_KDEBUG_ENABLE - _COMM_PAGE32_BASE_ADDRESS); | |
863 | saved_data_ptr = (volatile uint32_t *)cp; | |
39037602 | 864 | *saved_data_ptr = kdebug_commpage_state(); |
a1c7dba1 A |
865 | } |
866 | ||
867 | cp = commPagePtr64; | |
39037602 | 868 | if (cp) { |
a1c7dba1 A |
869 | cp += (_COMM_PAGE_KDEBUG_ENABLE - _COMM_PAGE32_START_ADDRESS); |
870 | saved_data_ptr = (volatile uint32_t *)cp; | |
39037602 | 871 | *saved_data_ptr = kdebug_commpage_state(); |
a1c7dba1 A |
872 | } |
873 | } | |
874 | ||
3e170ce0 A |
875 | /* Ditto for atm_diagnostic_config */ |
876 | void | |
877 | commpage_update_atm_diagnostic_config(uint32_t diagnostic_config) | |
878 | { | |
879 | volatile uint32_t *saved_data_ptr; | |
880 | char *cp; | |
881 | ||
882 | cp = commPagePtr32; | |
883 | if (cp) { | |
884 | cp += (_COMM_PAGE_ATM_DIAGNOSTIC_CONFIG - _COMM_PAGE32_BASE_ADDRESS); | |
885 | saved_data_ptr = (volatile uint32_t *)cp; | |
886 | *saved_data_ptr = diagnostic_config; | |
887 | } | |
888 | ||
889 | cp = commPagePtr64; | |
0a7de745 | 890 | if (cp) { |
3e170ce0 A |
891 | cp += (_COMM_PAGE_ATM_DIAGNOSTIC_CONFIG - _COMM_PAGE32_START_ADDRESS); |
892 | saved_data_ptr = (volatile uint32_t *)cp; | |
893 | *saved_data_ptr = diagnostic_config; | |
894 | } | |
895 | } | |
a1c7dba1 | 896 | |
cb323159 A |
897 | /* |
898 | * update the commpage with if dtrace user land probes are enabled | |
899 | */ | |
900 | void | |
901 | commpage_update_dof(boolean_t enabled) | |
902 | { | |
903 | #if CONFIG_DTRACE | |
904 | char *cp; | |
905 | ||
906 | cp = commPagePtr32; | |
907 | if (cp) { | |
908 | cp += (_COMM_PAGE_DTRACE_DOF_ENABLED - _COMM_PAGE32_BASE_ADDRESS); | |
909 | *cp = (enabled ? 1 : 0); | |
910 | } | |
911 | ||
912 | cp = commPagePtr64; | |
913 | if (cp) { | |
914 | cp += (_COMM_PAGE_DTRACE_DOF_ENABLED - _COMM_PAGE32_START_ADDRESS); | |
915 | *cp = (enabled ? 1 : 0); | |
916 | } | |
917 | #else | |
918 | (void)enabled; | |
919 | #endif | |
920 | } | |
921 | ||
922 | ||
923 | /* | |
924 | * update the dyld global config flags | |
925 | */ | |
926 | void | |
927 | commpage_update_dyld_flags(uint64_t value) | |
928 | { | |
929 | char *cp; | |
930 | ||
931 | cp = commPagePtr32; | |
932 | if (cp) { | |
933 | cp += (_COMM_PAGE_DYLD_SYSTEM_FLAGS - _COMM_PAGE32_BASE_ADDRESS); | |
934 | *(uint64_t *)cp = value; | |
935 | } | |
936 | ||
937 | cp = commPagePtr64; | |
938 | if (cp) { | |
939 | cp += (_COMM_PAGE_DYLD_SYSTEM_FLAGS - _COMM_PAGE32_BASE_ADDRESS); | |
940 | *(uint64_t *)cp = value; | |
941 | } | |
942 | } | |
943 | ||
944 | ||
fe8ab488 A |
945 | /* |
946 | * update the commpage data for last known value of mach_absolute_time() | |
947 | */ | |
948 | ||
949 | void | |
950 | commpage_update_mach_approximate_time(uint64_t abstime) | |
951 | { | |
952 | #ifdef CONFIG_MACH_APPROXIMATE_TIME | |
953 | uint64_t saved_data; | |
a1c7dba1 | 954 | char *cp; |
0a7de745 | 955 | |
a1c7dba1 | 956 | cp = commPagePtr32; |
0a7de745 | 957 | if (cp) { |
a1c7dba1 | 958 | cp += (_COMM_PAGE_APPROX_TIME - _COMM_PAGE32_BASE_ADDRESS); |
5ba3f43e | 959 | saved_data = atomic_load_explicit((_Atomic uint64_t *)(uintptr_t)cp, memory_order_relaxed); |
fe8ab488 A |
960 | if (saved_data < abstime) { |
961 | /* ignoring the success/fail return value assuming that | |
962 | * if the value has been updated since we last read it, | |
963 | * "someone" has a newer timestamp than us and ours is | |
964 | * now invalid. */ | |
0a7de745 A |
965 | atomic_compare_exchange_strong_explicit((_Atomic uint64_t *)(uintptr_t)cp, |
966 | &saved_data, abstime, memory_order_relaxed, memory_order_relaxed); | |
fe8ab488 A |
967 | } |
968 | } | |
a1c7dba1 | 969 | cp = commPagePtr64; |
0a7de745 | 970 | if (cp) { |
a1c7dba1 | 971 | cp += (_COMM_PAGE_APPROX_TIME - _COMM_PAGE32_START_ADDRESS); |
5ba3f43e | 972 | saved_data = atomic_load_explicit((_Atomic uint64_t *)(uintptr_t)cp, memory_order_relaxed); |
fe8ab488 A |
973 | if (saved_data < abstime) { |
974 | /* ignoring the success/fail return value assuming that | |
975 | * if the value has been updated since we last read it, | |
976 | * "someone" has a newer timestamp than us and ours is | |
977 | * now invalid. */ | |
0a7de745 A |
978 | atomic_compare_exchange_strong_explicit((_Atomic uint64_t *)(uintptr_t)cp, |
979 | &saved_data, abstime, memory_order_relaxed, memory_order_relaxed); | |
fe8ab488 A |
980 | } |
981 | } | |
982 | #else | |
983 | #pragma unused (abstime) | |
984 | #endif | |
985 | } | |
986 | ||
39037602 A |
987 | void |
988 | commpage_update_mach_continuous_time(uint64_t sleeptime) | |
989 | { | |
990 | char *cp; | |
991 | cp = commPagePtr32; | |
992 | if (cp) { | |
993 | cp += (_COMM_PAGE_CONT_TIMEBASE - _COMM_PAGE32_START_ADDRESS); | |
994 | *(uint64_t *)cp = sleeptime; | |
995 | } | |
0a7de745 | 996 | |
39037602 A |
997 | cp = commPagePtr64; |
998 | if (cp) { | |
999 | cp += (_COMM_PAGE_CONT_TIMEBASE - _COMM_PAGE32_START_ADDRESS); | |
1000 | *(uint64_t *)cp = sleeptime; | |
1001 | } | |
1002 | } | |
1003 | ||
1004 | void | |
1005 | commpage_update_boottime(uint64_t boottime) | |
1006 | { | |
1007 | char *cp; | |
1008 | cp = commPagePtr32; | |
1009 | if (cp) { | |
1010 | cp += (_COMM_PAGE_BOOTTIME_USEC - _COMM_PAGE32_START_ADDRESS); | |
1011 | *(uint64_t *)cp = boottime; | |
1012 | } | |
1013 | ||
1014 | cp = commPagePtr64; | |
1015 | if (cp) { | |
1016 | cp += (_COMM_PAGE_BOOTTIME_USEC - _COMM_PAGE32_START_ADDRESS); | |
1017 | *(uint64_t *)cp = boottime; | |
1018 | } | |
1019 | } | |
1020 | ||
fe8ab488 | 1021 | |
316670eb A |
1022 | extern user32_addr_t commpage_text32_location; |
1023 | extern user64_addr_t commpage_text64_location; | |
b0d623f7 A |
1024 | |
1025 | /* Check to see if a given address is in the Preemption Free Zone (PFZ) */ | |
1026 | ||
1027 | uint32_t | |
1028 | commpage_is_in_pfz32(uint32_t addr32) | |
1029 | { | |
0a7de745 A |
1030 | if ((addr32 >= (commpage_text32_location + _COMM_TEXT_PFZ_START_OFFSET)) |
1031 | && (addr32 < (commpage_text32_location + _COMM_TEXT_PFZ_END_OFFSET))) { | |
b0d623f7 | 1032 | return 1; |
0a7de745 | 1033 | } else { |
b0d623f7 | 1034 | return 0; |
0a7de745 | 1035 | } |
b0d623f7 A |
1036 | } |
1037 | ||
1038 | uint32_t | |
1039 | commpage_is_in_pfz64(addr64_t addr64) | |
1040 | { | |
0a7de745 A |
1041 | if ((addr64 >= (commpage_text64_location + _COMM_TEXT_PFZ_START_OFFSET)) |
1042 | && (addr64 < (commpage_text64_location + _COMM_TEXT_PFZ_END_OFFSET))) { | |
b0d623f7 | 1043 | return 1; |
0a7de745 | 1044 | } else { |
b0d623f7 | 1045 | return 0; |
0a7de745 | 1046 | } |
b0d623f7 | 1047 | } |