/ duct-tape / xnu / osfmk / arm / commpage / commpage.c
commpage.c
  1  /*
  2   * Copyright (c) 2007 Apple Inc. All rights reserved.
  3   * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
  4   *
  5   * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  6   *
  7   * This file contains Original Code and/or Modifications of Original Code
  8   * as defined in and that are subject to the Apple Public Source License
  9   * Version 2.0 (the 'License'). You may not use this file except in
 10   * compliance with the License. The rights granted to you under the License
 11   * may not be used to create, or enable the creation or redistribution of,
 12   * unlawful or unlicensed copies of an Apple operating system, or to
 13   * circumvent, violate, or enable the circumvention or violation of, any
 14   * terms of an Apple operating system software license agreement.
 15   *
 16   * Please obtain a copy of the License at
 17   * http://www.opensource.apple.com/apsl/ and read it before using this file.
 18   *
 19   * The Original Code and all software distributed under the License are
 20   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 21   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 22   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 23   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 24   * Please see the License for the specific language governing rights and
 25   * limitations under the License.
 26   *
 27   * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 28   */
 29  /*
 30   * @OSF_COPYRIGHT@
 31   */
 32  /*
 33   * @APPLE_FREE_COPYRIGHT@
 34   */
 35  /*
 36   *	File:		arm/commpage/commpage.c
 37   *	Purpose:	Set up and export a RO/RW page
 38   */
 39  #include <libkern/section_keywords.h>
 40  #include <mach/mach_types.h>
 41  #include <mach/machine.h>
 42  #include <mach/vm_map.h>
 43  #include <machine/cpu_capabilities.h>
 44  #include <machine/commpage.h>
 45  #include <machine/config.h>
 46  #include <machine/pmap.h>
 47  #include <vm/vm_kern.h>
 48  #include <vm/vm_map.h>
 49  #include <vm/vm_protos.h>
 50  #include <ipc/ipc_port.h>
 51  #include <arm/cpuid.h>          /* for cpuid_info() & cache_info() */
 52  #include <arm/rtclock.h>
 53  #include <libkern/OSAtomic.h>
 54  #include <stdatomic.h>
 55  #include <kern/remote_time.h>
 56  #include <machine/machine_remote_time.h>
 57  #include <machine/machine_routines.h>
 58  
 59  #include <sys/kdebug.h>
 60  
 61  #if CONFIG_ATM
 62  #include <atm/atm_internal.h>
 63  #endif
 64  
 65  static int commpage_cpus( void );
 66  
 67  
 68  static void commpage_init_cpu_capabilities( void );
 69  
 70  SECURITY_READ_ONLY_LATE(vm_address_t)   commPagePtr = 0;
 71  SECURITY_READ_ONLY_LATE(vm_address_t)   sharedpage_rw_addr = 0;
 72  SECURITY_READ_ONLY_LATE(uint64_t)       _cpu_capabilities = 0;
 73  SECURITY_READ_ONLY_LATE(vm_address_t)   sharedpage_rw_text_addr = 0;
 74  
 75  extern user64_addr_t commpage_text64_location;
 76  extern user32_addr_t commpage_text32_location;
 77  
 78  /* For sysctl access from BSD side */
 79  extern int      gARMv81Atomics;
 80  extern int      gARMv8Crc32;
 81  extern int      gARMv82FHM;
 82  extern int      gARMv82SHA512;
 83  extern int      gARMv82SHA3;
 84  
 85  void
 86  commpage_populate(void)
 87  {
 88  	uint16_t        c2;
 89  	int cpufamily;
 90  
 91  	// Create the data and the text commpage
 92  	vm_map_address_t kernel_data_addr, kernel_text_addr, user_text_addr;
 93  	pmap_create_sharedpages(&kernel_data_addr, &kernel_text_addr, &user_text_addr);
 94  
 95  	sharedpage_rw_addr = kernel_data_addr;
 96  	sharedpage_rw_text_addr = kernel_text_addr;
 97  	commPagePtr = (vm_address_t) _COMM_PAGE_BASE_ADDRESS;
 98  
 99  #if __arm64__
100  	commpage_text64_location = user_text_addr;
101  	bcopy(_COMM_PAGE64_SIGNATURE_STRING, (void *)(_COMM_PAGE_SIGNATURE + _COMM_PAGE_RW_OFFSET),
102  	    MIN(_COMM_PAGE_SIGNATURELEN, strlen(_COMM_PAGE64_SIGNATURE_STRING)));
103  #else
104  	commpage_text32_location = user_text_addr;
105  	bcopy(_COMM_PAGE32_SIGNATURE_STRING, (void *)(_COMM_PAGE_SIGNATURE + _COMM_PAGE_RW_OFFSET),
106  	    MIN(_COMM_PAGE_SIGNATURELEN, strlen(_COMM_PAGE32_SIGNATURE_STRING)));
107  #endif
108  
109  	*((uint16_t*)(_COMM_PAGE_VERSION + _COMM_PAGE_RW_OFFSET)) = (uint16_t) _COMM_PAGE_THIS_VERSION;
110  
111  	commpage_init_cpu_capabilities();
112  	commpage_set_timestamp(0, 0, 0, 0, 0);
113  
114  	if (_cpu_capabilities & kCache32) {
115  		c2 = 32;
116  	} else if (_cpu_capabilities & kCache64) {
117  		c2 = 64;
118  	} else if (_cpu_capabilities & kCache128) {
119  		c2 = 128;
120  	} else {
121  		c2 = 0;
122  	}
123  
124  	*((uint16_t*)(_COMM_PAGE_CACHE_LINESIZE + _COMM_PAGE_RW_OFFSET)) = c2;
125  
126  	commpage_update_active_cpus();
127  	cpufamily = cpuid_get_cpufamily();
128  
129  	*((uint8_t*)(_COMM_PAGE_PHYSICAL_CPUS + _COMM_PAGE_RW_OFFSET)) = (uint8_t) machine_info.physical_cpu_max;
130  	*((uint8_t*)(_COMM_PAGE_LOGICAL_CPUS + _COMM_PAGE_RW_OFFSET)) = (uint8_t) machine_info.logical_cpu_max;
131  	*((uint64_t*)(_COMM_PAGE_MEMORY_SIZE + _COMM_PAGE_RW_OFFSET)) = machine_info.max_mem;
132  	*((uint32_t*)(_COMM_PAGE_CPUFAMILY + _COMM_PAGE_RW_OFFSET)) = (uint32_t)cpufamily;
133  	*((uint32_t*)(_COMM_PAGE_DEV_FIRM + _COMM_PAGE_RW_OFFSET)) = (uint32_t)PE_i_can_has_debugger(NULL);
134  	*((uint8_t*)(_COMM_PAGE_USER_TIMEBASE + _COMM_PAGE_RW_OFFSET)) = user_timebase_type();
135  	*((uint8_t*)(_COMM_PAGE_CONT_HWCLOCK + _COMM_PAGE_RW_OFFSET)) = (uint8_t)user_cont_hwclock_allowed();
136  	*((uint8_t*)(_COMM_PAGE_KERNEL_PAGE_SHIFT + _COMM_PAGE_RW_OFFSET)) = (uint8_t) page_shift;
137  
138  #if __arm64__
139  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_32 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) page_shift_user32;
140  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_64 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) SIXTEENK_PAGE_SHIFT;
141  #elif (__ARM_ARCH_7K__ >= 2)
142  	/* enforce 16KB alignment for watch targets with new ABI */
143  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_32 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) SIXTEENK_PAGE_SHIFT;
144  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_64 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) SIXTEENK_PAGE_SHIFT;
145  #else /* __arm64__ */
146  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_32 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) PAGE_SHIFT;
147  	*((uint8_t*)(_COMM_PAGE_USER_PAGE_SHIFT_64 + _COMM_PAGE_RW_OFFSET)) = (uint8_t) PAGE_SHIFT;
148  #endif /* __arm64__ */
149  
150  	commpage_update_timebase();
151  	commpage_update_mach_continuous_time(0);
152  
153  	clock_sec_t secs;
154  	clock_usec_t microsecs;
155  	clock_get_boottime_microtime(&secs, &microsecs);
156  	commpage_update_boottime(secs * USEC_PER_SEC + microsecs);
157  
158  	/*
159  	 * set commpage approximate time to zero for initialization.
160  	 * scheduler shall populate correct value before running user thread
161  	 */
162  	*((uint64_t *)(_COMM_PAGE_APPROX_TIME + _COMM_PAGE_RW_OFFSET)) = 0;
163  #ifdef CONFIG_MACH_APPROXIMATE_TIME
164  	*((uint8_t *)(_COMM_PAGE_APPROX_TIME_SUPPORTED + _COMM_PAGE_RW_OFFSET)) = 1;
165  #else
166  	*((uint8_t *)(_COMM_PAGE_APPROX_TIME_SUPPORTED + _COMM_PAGE_RW_OFFSET)) = 0;
167  #endif
168  
169  	commpage_update_kdebug_state();
170  
171  #if CONFIG_ATM
172  	commpage_update_atm_diagnostic_config(atm_get_diagnostic_config());
173  #endif
174  
175  
176  	*((uint64_t*)(_COMM_PAGE_REMOTETIME_PARAMS + _COMM_PAGE_RW_OFFSET)) = BT_RESET_SENTINEL_TS;
177  }
178  
179  #define COMMPAGE_TEXT_SEGMENT "__TEXT_EXEC"
180  #define COMMPAGE_TEXT_SECTION "__commpage_text"
181  
182  /* Get a pointer to the start of the ARM PFZ code section. This macro tell the
183   * linker that the storage for the variable here is at the start of the section */
184  extern char commpage_text_start[]
185  __SECTION_START_SYM(COMMPAGE_TEXT_SEGMENT, COMMPAGE_TEXT_SECTION);
186  
187  /* Get a pointer to the end of the ARM PFZ code section. This macro tell the
188   * linker that the storage for the variable here is at the end of the section */
189  extern char commpage_text_end[]
190  __SECTION_END_SYM(COMMPAGE_TEXT_SEGMENT, COMMPAGE_TEXT_SECTION);
191  
192  /* This is defined in the commpage text section as a symbol at the start of the preemptible
193   * functions */
194  extern char commpage_text_preemptible_functions;
195  
196  #if CONFIG_ARM_PFZ
197  static size_t size_of_pfz = 0;
198  #endif
199  
200  /* This is the opcode for brk #666 */
201  #define BRK_666_OPCODE 0xD4205340
202  
203  void
204  commpage_text_populate(void)
205  {
206  #if CONFIG_ARM_PFZ
207  	size_t size_of_commpage_text = commpage_text_end - commpage_text_start;
208  	if (size_of_commpage_text == 0) {
209  		panic("ARM comm page text section %s,%s missing", COMMPAGE_TEXT_SEGMENT, COMMPAGE_TEXT_SECTION);
210  	}
211  	assert(size_of_commpage_text <= PAGE_SIZE);
212  	assert(size_of_commpage_text > 0);
213  
214  	/* Get the size of the PFZ half of the comm page text section. */
215  	size_of_pfz = &commpage_text_preemptible_functions - commpage_text_start;
216  
217  	// Copy the code segment of comm page text section into the PFZ
218  	memcpy((void *) _COMM_PAGE64_TEXT_START_ADDRESS, (void *) commpage_text_start, size_of_commpage_text);
219  
220  	// Make sure to populate the rest of it with brk 666 so that undefined code
221  	// doesn't get  run
222  	memset((char *) _COMM_PAGE64_TEXT_START_ADDRESS + size_of_commpage_text, BRK_666_OPCODE,
223  	    PAGE_SIZE - size_of_commpage_text);
224  #endif
225  }
226  
227  uint32_t
228  commpage_is_in_pfz64(addr64_t addr64)
229  {
230  #if CONFIG_ARM_PFZ
231  	if ((addr64 >= commpage_text64_location) &&
232  	    (addr64 < (commpage_text64_location + size_of_pfz))) {
233  		return 1;
234  	} else {
235  		return 0;
236  	}
237  #else
238  #pragma unused (addr64)
239  	return 0;
240  #endif
241  }
242  
243  
244  void
245  commpage_set_timestamp(
246  	uint64_t        tbr,
247  	uint64_t        secs,
248  	uint64_t        frac,
249  	uint64_t        scale,
250  	uint64_t        tick_per_sec)
251  {
252  	new_commpage_timeofday_data_t *commpage_timeofday_datap;
253  
254  	if (commPagePtr == 0) {
255  		return;
256  	}
257  
258  	commpage_timeofday_datap =  (new_commpage_timeofday_data_t *)(_COMM_PAGE_NEWTIMEOFDAY_DATA + _COMM_PAGE_RW_OFFSET);
259  
260  	commpage_timeofday_datap->TimeStamp_tick = 0x0ULL;
261  
262  #if     (__ARM_ARCH__ >= 7)
263  	__asm__ volatile ("dmb ish");
264  #endif
265  	commpage_timeofday_datap->TimeStamp_sec = secs;
266  	commpage_timeofday_datap->TimeStamp_frac = frac;
267  	commpage_timeofday_datap->Ticks_scale = scale;
268  	commpage_timeofday_datap->Ticks_per_sec = tick_per_sec;
269  
270  #if     (__ARM_ARCH__ >= 7)
271  	__asm__ volatile ("dmb ish");
272  #endif
273  	commpage_timeofday_datap->TimeStamp_tick = tbr;
274  
275  }
276  
277  /*
278   * Update _COMM_PAGE_MEMORY_PRESSURE.  Called periodically from vm's compute_memory_pressure()
279   */
280  
281  void
282  commpage_set_memory_pressure(
283  	unsigned int    pressure )
284  {
285  	if (commPagePtr == 0) {
286  		return;
287  	}
288  	*((uint32_t *)(_COMM_PAGE_MEMORY_PRESSURE + _COMM_PAGE_RW_OFFSET)) = pressure;
289  }
290  
291  /*
292   * Determine number of CPUs on this system.
293   */
294  static int
295  commpage_cpus( void )
296  {
297  	int cpus;
298  
299  	cpus = machine_info.max_cpus;
300  
301  	if (cpus == 0) {
302  		panic("commpage cpus==0");
303  	}
304  	if (cpus > 0xFF) {
305  		cpus = 0xFF;
306  	}
307  
308  	return cpus;
309  }
310  
311  uint64_t
312  _get_cpu_capabilities(void)
313  {
314  	return _cpu_capabilities;
315  }
316  
317  vm_address_t
318  _get_commpage_priv_address(void)
319  {
320  	return sharedpage_rw_addr;
321  }
322  
323  vm_address_t
324  _get_commpage_text_priv_address(void)
325  {
326  	return sharedpage_rw_text_addr;
327  }
328  
329  /*
330   * Initialize _cpu_capabilities vector
331   */
332  static void
333  commpage_init_cpu_capabilities( void )
334  {
335  	uint64_t bits;
336  	int cpus;
337  	ml_cpu_info_t cpu_info;
338  
339  	bits = 0;
340  	ml_cpu_get_info(&cpu_info);
341  
342  	switch (cpu_info.cache_line_size) {
343  	case 128:
344  		bits |= kCache128;
345  		break;
346  	case 64:
347  		bits |= kCache64;
348  		break;
349  	case 32:
350  		bits |= kCache32;
351  		break;
352  	default:
353  		break;
354  	}
355  	cpus = commpage_cpus();
356  
357  	if (cpus == 1) {
358  		bits |= kUP;
359  	}
360  
361  	bits |= (cpus << kNumCPUsShift);
362  
363  	bits |= kFastThreadLocalStorage;        // TPIDRURO for TLS
364  
365  #if     __ARM_VFP__
366  	bits |= kHasVfp;
367  	arm_mvfp_info_t *mvfp_info = arm_mvfp_info();
368  	if (mvfp_info->neon) {
369  		bits |= kHasNeon;
370  	}
371  	if (mvfp_info->neon_hpfp) {
372  		bits |= kHasNeonHPFP;
373  	}
374  	if (mvfp_info->neon_fp16) {
375  		bits |= kHasNeonFP16;
376  	}
377  #endif
378  #if defined(__arm64__)
379  	bits |= kHasFMA;
380  #endif
381  #if     __ARM_ENABLE_WFE_
382  	bits |= kHasEvent;
383  #endif
384  #if __ARM_V8_CRYPTO_EXTENSIONS__
385  	bits |= kHasARMv8Crypto;
386  #endif
387  #ifdef __arm64__
388  	uint64_t isar0 = __builtin_arm_rsr64("ID_AA64ISAR0_EL1");
389  	if ((isar0 & ID_AA64ISAR0_EL1_ATOMIC_MASK) == ID_AA64ISAR0_EL1_ATOMIC_8_1) {
390  		bits |= kHasARMv81Atomics;
391  		gARMv81Atomics = 1;
392  	}
393  	if ((isar0 & ID_AA64ISAR0_EL1_CRC32_MASK) == ID_AA64ISAR0_EL1_CRC32_EN) {
394  		bits |= kHasARMv8Crc32;
395  		gARMv8Crc32 = 1;
396  	}
397  	if ((isar0 & ID_AA64ISAR0_EL1_FHM_MASK) >= ID_AA64ISAR0_EL1_FHM_8_2) {
398  		bits |= kHasARMv82FHM;
399  		gARMv82FHM = 1;
400  	}
401  
402  	if ((isar0 & ID_AA64ISAR0_EL1_SHA2_MASK) > ID_AA64ISAR0_EL1_SHA2_EN) {
403  		bits |= kHasARMv82SHA512;
404  		gARMv82SHA512 = 1;
405  	}
406  	if ((isar0 & ID_AA64ISAR0_EL1_SHA3_MASK) >= ID_AA64ISAR0_EL1_SHA3_EN) {
407  		bits |= kHasARMv82SHA3;
408  		gARMv82SHA3 = 1;
409  	}
410  
411  #endif
412  
413  
414  
415  
416  	_cpu_capabilities = bits;
417  
418  	*((uint32_t *)(_COMM_PAGE_CPU_CAPABILITIES + _COMM_PAGE_RW_OFFSET)) = (uint32_t)_cpu_capabilities;
419  	*((uint64_t *)(_COMM_PAGE_CPU_CAPABILITIES64 + _COMM_PAGE_RW_OFFSET)) = _cpu_capabilities;
420  }
421  
422  /*
423   * Updated every time a logical CPU goes offline/online
424   */
425  void
426  commpage_update_active_cpus(void)
427  {
428  	if (!commPagePtr) {
429  		return;
430  	}
431  	*((uint8_t *)(_COMM_PAGE_ACTIVE_CPUS + _COMM_PAGE_RW_OFFSET)) = (uint8_t)processor_avail_count;
432  
433  }
434  
435  /*
436   * Update the commpage bits for mach_absolute_time and mach_continuous_time (for userspace)
437   */
438  void
439  commpage_update_timebase(void)
440  {
441  	if (commPagePtr) {
442  		*((uint64_t*)(_COMM_PAGE_TIMEBASE_OFFSET + _COMM_PAGE_RW_OFFSET)) = rtclock_base_abstime;
443  	}
444  }
445  
446  /*
447   * Update the commpage with current kdebug state. This currently has bits for
448   * global trace state, and typefilter enablement. It is likely additional state
449   * will be tracked in the future.
450   *
451   * INVARIANT: This value will always be 0 if global tracing is disabled. This
452   * allows simple guard tests of "if (*_COMM_PAGE_KDEBUG_ENABLE) { ... }"
453   */
454  void
455  commpage_update_kdebug_state(void)
456  {
457  	if (commPagePtr) {
458  		*((volatile uint32_t*)(_COMM_PAGE_KDEBUG_ENABLE + _COMM_PAGE_RW_OFFSET)) = kdebug_commpage_state();
459  	}
460  }
461  
462  /* Ditto for atm_diagnostic_config */
463  void
464  commpage_update_atm_diagnostic_config(uint32_t diagnostic_config)
465  {
466  	if (commPagePtr) {
467  		*((volatile uint32_t*)(_COMM_PAGE_ATM_DIAGNOSTIC_CONFIG + _COMM_PAGE_RW_OFFSET)) = diagnostic_config;
468  	}
469  }
470  
471  /*
472   * Update the commpage data with the state of multiuser mode for
473   * this device. Allowing various services in userspace to avoid
474   * IPC in the (more common) non-multiuser environment.
475   */
476  void
477  commpage_update_multiuser_config(uint32_t multiuser_config)
478  {
479  	if (commPagePtr) {
480  		*((volatile uint32_t *)(_COMM_PAGE_MULTIUSER_CONFIG + _COMM_PAGE_RW_OFFSET)) = multiuser_config;
481  	}
482  }
483  
484  /*
485   * update the commpage data for
486   * last known value of mach_absolute_time()
487   */
488  
489  void
490  commpage_update_mach_approximate_time(uint64_t abstime)
491  {
492  #ifdef CONFIG_MACH_APPROXIMATE_TIME
493  	uintptr_t approx_time_base = (uintptr_t)(_COMM_PAGE_APPROX_TIME + _COMM_PAGE_RW_OFFSET);
494  	uint64_t saved_data;
495  
496  	if (commPagePtr) {
497  		saved_data = atomic_load_explicit((_Atomic uint64_t *)approx_time_base,
498  		    memory_order_relaxed);
499  		if (saved_data < abstime) {
500  			/* ignoring the success/fail return value assuming that
501  			 * if the value has been updated since we last read it,
502  			 * "someone" has a newer timestamp than us and ours is
503  			 * now invalid. */
504  			atomic_compare_exchange_strong_explicit((_Atomic uint64_t *)approx_time_base,
505  			    &saved_data, abstime, memory_order_relaxed, memory_order_relaxed);
506  		}
507  	}
508  #else
509  #pragma unused (abstime)
510  #endif
511  }
512  
513  /*
514   * update the commpage data's total system sleep time for
515   * userspace call to mach_continuous_time()
516   */
517  void
518  commpage_update_mach_continuous_time(uint64_t sleeptime)
519  {
520  	if (commPagePtr) {
521  #ifdef __arm64__
522  		*((uint64_t *)(_COMM_PAGE_CONT_TIMEBASE + _COMM_PAGE_RW_OFFSET)) = sleeptime;
523  #else
524  		uint64_t *c_time_base = (uint64_t *)(_COMM_PAGE_CONT_TIMEBASE + _COMM_PAGE_RW_OFFSET);
525  		uint64_t old;
526  		do {
527  			old = *c_time_base;
528  		} while (!OSCompareAndSwap64(old, sleeptime, c_time_base));
529  #endif /* __arm64__ */
530  	}
531  }
532  
533  void
534  commpage_update_mach_continuous_time_hw_offset(uint64_t offset)
535  {
536  	*((uint64_t *)(_COMM_PAGE_CONT_HW_TIMEBASE + _COMM_PAGE_RW_OFFSET)) = offset;
537  }
538  
539  /*
540   * update the commpage's value for the boot time
541   */
542  void
543  commpage_update_boottime(uint64_t value)
544  {
545  	if (commPagePtr) {
546  #ifdef __arm64__
547  		*((uint64_t *)(_COMM_PAGE_BOOTTIME_USEC + _COMM_PAGE_RW_OFFSET)) = value;
548  #else
549  		uint64_t *cp = (uint64_t *)(_COMM_PAGE_BOOTTIME_USEC + _COMM_PAGE_RW_OFFSET);
550  		uint64_t old_value;
551  		do {
552  			old_value = *cp;
553  		} while (!OSCompareAndSwap64(old_value, value, cp));
554  #endif /* __arm64__ */
555  	}
556  }
557  
558  /*
559   * set the commpage's remote time params for
560   * userspace call to mach_bridge_remote_time()
561   */
562  void
563  commpage_set_remotetime_params(double rate, uint64_t base_local_ts, uint64_t base_remote_ts)
564  {
565  	if (commPagePtr) {
566  #ifdef __arm64__
567  		struct bt_params *paramsp = (struct bt_params *)(_COMM_PAGE_REMOTETIME_PARAMS + _COMM_PAGE_RW_OFFSET);
568  		paramsp->base_local_ts = 0;
569  		__asm__ volatile ("dmb ish" ::: "memory");
570  		paramsp->rate = rate;
571  		paramsp->base_remote_ts = base_remote_ts;
572  		__asm__ volatile ("dmb ish" ::: "memory");
573  		paramsp->base_local_ts = base_local_ts;  //This will act as a generation count
574  #else
575  		(void)rate;
576  		(void)base_local_ts;
577  		(void)base_remote_ts;
578  #endif /* __arm64__ */
579  	}
580  }
581  
582  
583  /*
584   * After this counter has incremented, all running CPUs are guaranteed to
585   * have quiesced, i.e. executed serially dependent memory barriers.
586   * This is only tracked for CPUs running in userspace, therefore only useful
587   * outside the kernel.
588   *
589   * Note that you can't know which side of those barriers your read was from,
590   * so you have to observe 2 increments in order to ensure that you saw a
591   * serially dependent barrier chain across all running CPUs.
592   */
593  uint64_t
594  commpage_increment_cpu_quiescent_counter(void)
595  {
596  	if (!commPagePtr) {
597  		return 0;
598  	}
599  
600  	uint64_t old_gen;
601  
602  	_Atomic uint64_t *sched_gen = (_Atomic uint64_t *)(_COMM_PAGE_CPU_QUIESCENT_COUNTER +
603  	    _COMM_PAGE_RW_OFFSET);
604  	/*
605  	 * On 32bit architectures, double-wide atomic load or stores are a CAS,
606  	 * so the atomic increment is the most efficient way to increment the
607  	 * counter.
608  	 *
609  	 * On 64bit architectures however, because the update is synchronized by
610  	 * the cpu mask, relaxed loads and stores is more efficient.
611  	 */
612  #if __LP64__
613  	old_gen = os_atomic_load(sched_gen, relaxed);
614  	os_atomic_store(sched_gen, old_gen + 1, relaxed);
615  #else
616  	old_gen = atomic_fetch_add_explicit(sched_gen, 1, memory_order_relaxed);
617  #endif
618  	return old_gen;
619  }
620  
621  /*
622   * update the commpage with if dtrace user land probes are enabled
623   */
624  void
625  commpage_update_dof(boolean_t enabled)
626  {
627  #if CONFIG_DTRACE
628  	*((uint8_t*)(_COMM_PAGE_DTRACE_DOF_ENABLED + _COMM_PAGE_RW_OFFSET)) = (enabled ? 1 : 0);
629  #else
630  	(void)enabled;
631  #endif
632  }
633  
634  /*
635   * update the dyld global config flags
636   */
637  void
638  commpage_update_dyld_flags(uint64_t value)
639  {
640  	*((uint64_t*)(_COMM_PAGE_DYLD_FLAGS + _COMM_PAGE_RW_OFFSET)) = value;
641  
642  }