xref: /xnu-8792.61.2/osfmk/arm/locks_arm.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System Copyright (c) 1991,1990,1989,1988,1987 Carnegie
33  * Mellon University All Rights Reserved.
34  *
35  * Permission to use, copy, modify and distribute this software and its
36  * documentation is hereby granted, provided that both the copyright notice
37  * and this permission notice appear in all copies of the software,
38  * derivative works or modified versions, and any portions thereof, and that
39  * both notices appear in supporting documentation.
40  *
41  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
42  * CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
43  * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
44  *
45  * Carnegie Mellon requests users of this software to return to
46  *
47  * Software Distribution Coordinator  or  [email protected]
48  * School of Computer Science Carnegie Mellon University Pittsburgh PA
49  * 15213-3890
50  *
51  * any improvements or extensions that they make and grant Carnegie Mellon the
52  * rights to redistribute these changes.
53  */
54 /*
55  *	File:	kern/lock.c
56  *	Author:	Avadis Tevanian, Jr., Michael Wayne Young
57  *	Date:	1985
58  *
59  *	Locking primitives implementation
60  */
61 
62 #define LOCK_PRIVATE 1
63 
64 #include <mach_ldebug.h>
65 
66 #include <mach/machine/sdt.h>
67 
68 #include <kern/locks_internal.h>
69 #include <kern/zalloc.h>
70 #include <kern/lock_stat.h>
71 #include <kern/locks.h>
72 #include <kern/misc_protos.h>
73 #include <kern/thread.h>
74 #include <kern/processor.h>
75 #include <kern/sched_hygiene.h>
76 #include <kern/sched_prim.h>
77 #include <kern/debug.h>
78 #include <kern/kcdata.h>
79 #include <kern/percpu.h>
80 #include <kern/hvg_hypercall.h>
81 #include <string.h>
82 #include <arm/cpu_internal.h>
83 #include <os/hash.h>
84 #include <arm/cpu_data.h>
85 
86 #include <arm/cpu_data_internal.h>
87 #include <arm64/proc_reg.h>
88 #include <arm/smp.h>
89 #include <machine/atomic.h>
90 #include <machine/machine_cpu.h>
91 
92 #include <pexpert/pexpert.h>
93 
94 #include <sys/kdebug.h>
95 
96 #define ANY_LOCK_DEBUG  (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
97 
98 // Panic in tests that check lock usage correctness
99 // These are undesirable when in a panic or a debugger is runnning.
100 #define LOCK_CORRECTNESS_PANIC() (kernel_debugger_entry_count == 0)
101 
102 /* Forwards */
103 
104 extern unsigned int not_in_kdp;
105 
106 MACHINE_TIMEOUT(lock_panic_timeout, "lock-panic",
107     0xc00000 /* 12.5 m ticks ~= 524ms with 24MHz OSC */, MACHINE_TIMEOUT_UNIT_TIMEBASE, NULL);
108 
109 #define NOINLINE                __attribute__((noinline))
110 
111 #define interrupts_disabled(mask) (mask & DAIF_IRQF)
112 
113 KALLOC_TYPE_DEFINE(KT_LCK_SPIN, lck_spin_t, KT_PRIV_ACCT);
114 
115 #pragma GCC visibility push(hidden)
116 /*
117  * atomic exchange API is a low level abstraction of the operations
118  * to atomically read, modify, and write a pointer.  This abstraction works
119  * for both Intel and ARMv8.1 compare and exchange atomic instructions as
120  * well as the ARM exclusive instructions.
121  *
122  * atomic_exchange_begin() - begin exchange and retrieve current value
123  * atomic_exchange_complete() - conclude an exchange
124  * atomic_exchange_abort() - cancel an exchange started with atomic_exchange_begin()
125  */
126 uint32_t
load_exclusive32(uint32_t * target,enum memory_order ord)127 load_exclusive32(uint32_t *target, enum memory_order ord)
128 {
129 	uint32_t        value;
130 
131 	if (_os_atomic_mo_has_acquire(ord)) {
132 		value = __builtin_arm_ldaex(target);    // ldaxr
133 	} else {
134 		value = __builtin_arm_ldrex(target);    // ldxr
135 	}
136 
137 	return value;
138 }
139 
140 boolean_t
store_exclusive32(uint32_t * target,uint32_t value,enum memory_order ord)141 store_exclusive32(uint32_t *target, uint32_t value, enum memory_order ord)
142 {
143 	boolean_t err;
144 
145 	if (_os_atomic_mo_has_release(ord)) {
146 		err = __builtin_arm_stlex(value, target);       // stlxr
147 	} else {
148 		err = __builtin_arm_strex(value, target);       // stxr
149 	}
150 
151 	return !err;
152 }
153 
154 uint32_t
atomic_exchange_begin32(uint32_t * target,uint32_t * previous,enum memory_order ord)155 atomic_exchange_begin32(uint32_t *target, uint32_t *previous, enum memory_order ord)
156 {
157 	uint32_t        val;
158 
159 #if !OS_ATOMIC_USE_LLSC
160 	ord = memory_order_relaxed;
161 #endif
162 	val = load_exclusive32(target, ord);
163 	*previous = val;
164 	return val;
165 }
166 
167 boolean_t
atomic_exchange_complete32(uint32_t * target,uint32_t previous,uint32_t newval,enum memory_order ord)168 atomic_exchange_complete32(uint32_t *target, uint32_t previous, uint32_t newval, enum memory_order ord)
169 {
170 #if !OS_ATOMIC_USE_LLSC
171 	return __c11_atomic_compare_exchange_strong((_Atomic uint32_t *)target, &previous, newval, ord, memory_order_relaxed);
172 #else
173 	(void)previous;         // Previous not needed, monitor is held
174 	return store_exclusive32(target, newval, ord);
175 #endif
176 }
177 
178 void
atomic_exchange_abort(void)179 atomic_exchange_abort(void)
180 {
181 	os_atomic_clear_exclusive();
182 }
183 
184 boolean_t
atomic_test_and_set32(uint32_t * target,uint32_t test_mask,uint32_t set_mask,enum memory_order ord,boolean_t wait)185 atomic_test_and_set32(uint32_t *target, uint32_t test_mask, uint32_t set_mask, enum memory_order ord, boolean_t wait)
186 {
187 	uint32_t                value, prev;
188 
189 	for (;;) {
190 		value = atomic_exchange_begin32(target, &prev, ord);
191 		if (value & test_mask) {
192 			if (wait) {
193 				wait_for_event();       // Wait with monitor held
194 			} else {
195 				atomic_exchange_abort();        // Clear exclusive monitor
196 			}
197 			return FALSE;
198 		}
199 		value |= set_mask;
200 		if (atomic_exchange_complete32(target, prev, value, ord)) {
201 			return TRUE;
202 		}
203 	}
204 }
205 
206 #pragma GCC visibility pop
207 #pragma mark preemption
208 
209 #if SCHED_HYGIENE_DEBUG
210 
211 uint64_t _Atomic PERCPU_DATA_HACK_78750602(preemption_disable_max_mt);
212 
213 MACHINE_TIMEOUT_WRITEABLE(sched_preemption_disable_threshold_mt, "sched-preemption", 0, MACHINE_TIMEOUT_UNIT_TIMEBASE, kprintf_spam_mt_pred);
214 
215 TUNABLE_DT_WRITEABLE(sched_hygiene_mode_t, sched_preemption_disable_debug_mode,
216     "machine-timeouts",
217     "sched-preemption-disable-mode", /* DT property names have to be 31 chars max */
218     "sched_preemption_disable_debug_mode",
219     SCHED_HYGIENE_MODE_OFF,
220     TUNABLE_DT_CHECK_CHOSEN);
221 
222 static uint32_t const sched_preemption_disable_debug_dbgid = MACHDBG_CODE(DBG_MACH_SCHED, MACH_PREEMPTION_EXPIRED) | DBG_FUNC_NONE;
223 
224 NOINLINE void
_prepare_preemption_disable_measurement(thread_t thread)225 _prepare_preemption_disable_measurement(thread_t thread)
226 {
227 	if (thread->machine.inthandler_timestamp == 0) {
228 		/*
229 		 * Only prepare a measurement if not currently in an interrupt
230 		 * handler.
231 		 *
232 		 * We are only interested in the net duration of disabled
233 		 * preemption, that is: The time in which preemption was
234 		 * disabled, minus the intervals in which any (likely
235 		 * unrelated) interrupts were handled.
236 		 * ml_adjust_preemption_disable_time() will remove those
237 		 * intervals, however we also do not even start measuring
238 		 * preemption disablement if we are already within handling of
239 		 * an interrupt when preemption was disabled (the resulting
240 		 * net time would be 0).
241 		 *
242 		 * Interrupt handling duration is handled separately, and any
243 		 * long intervals of preemption disablement are counted
244 		 * towards that.
245 		 */
246 
247 		bool istate = ml_set_interrupts_enabled_with_debug(false, false); // don't take int masked timestamp
248 		thread->machine.preemption_disable_abandon = false;
249 		thread->machine.preemption_disable_mt = ml_get_sched_hygiene_timebase();
250 		thread->machine.preemption_disable_adjust = 0;
251 #if MONOTONIC
252 		if (sched_hygiene_debug_pmc) {
253 			mt_cur_cpu_cycles_instrs_speculative(&thread->machine.preemption_disable_cycles, &thread->machine.preemption_disable_instr);
254 		}
255 #endif
256 		ml_set_interrupts_enabled_with_debug(istate, false);
257 	}
258 }
259 
260 NOINLINE void
_collect_preemption_disable_measurement(thread_t thread)261 _collect_preemption_disable_measurement(thread_t thread)
262 {
263 	bool istate = ml_set_interrupts_enabled_with_debug(false, false); // don't take int masked timestamp
264 	/*
265 	 * Collect start time and current time with interrupts disabled.
266 	 * Otherwise an interrupt coming in after grabbing the timestamp
267 	 * could spuriously inflate the measurement, because it will
268 	 * adjust preemption_disable_mt only after we already grabbed
269 	 * it.
270 	 *
271 	 * (Even worse if we collected the current time first: Then a
272 	 * subsequent interrupt could adjust preemption_disable_mt to
273 	 * make the duration go negative after subtracting the already
274 	 * grabbed time. With interrupts disabled we don't care much about
275 	 * the order.)
276 	 */
277 
278 	uint64_t const mt = thread->machine.preemption_disable_mt;
279 	uint64_t const adjust = thread->machine.preemption_disable_adjust;
280 	uint64_t const now = ml_get_sched_hygiene_timebase();
281 	thread->machine.preemption_disable_mt = 0;
282 	thread->machine.preemption_disable_adjust = 0;
283 
284 	/*
285 	 * Don't need to reset (or even save) preemption_disable_abandon
286 	 * here: abandon_preemption_disable_measurement is a no-op anyway
287 	 * if preemption_disable_mt == 0 (which we just set), and it
288 	 * will stay that way until the next call to
289 	 * _collect_preemption_disable_measurement.
290 	 */
291 
292 	os_compiler_barrier(acq_rel);
293 
294 	ml_set_interrupts_enabled_with_debug(istate, false);
295 
296 	/*
297 	 * Fine to get with interrupts enabled:
298 	 * Above we set preemption_disable_mt to 0, which turns
299 	 * abandon_preemption_disable_measurement() into a no-op
300 	 * until the next collection starts.
301 	 */
302 	if (thread->machine.preemption_disable_abandon) {
303 		return;
304 	}
305 
306 	int64_t const gross_duration = now - mt;
307 	int64_t const net_duration = gross_duration - adjust;
308 
309 	uint64_t _Atomic * const max_duration = PERCPU_GET(preemption_disable_max_mt);
310 
311 	if (__improbable(net_duration > *max_duration)) {
312 		os_atomic_store(max_duration, net_duration, relaxed);
313 	}
314 
315 	uint64_t const threshold = os_atomic_load(&sched_preemption_disable_threshold_mt, relaxed);
316 	if (__improbable(threshold > 0 && net_duration >= threshold)) {
317 		uint64_t average_freq = 0;
318 		uint64_t average_cpi_whole = 0;
319 		uint64_t average_cpi_fractional = 0;
320 
321 #if MONOTONIC
322 		if (sched_hygiene_debug_pmc) {
323 			uint64_t current_cycles = 0, current_instrs = 0;
324 
325 			/*
326 			 * We're getting these values a bit late, but getting them
327 			 * is a bit expensive, so we take the slight hit in
328 			 * accuracy for the reported values (which aren't very
329 			 * stable anyway).
330 			 */
331 			istate = ml_set_interrupts_enabled_with_debug(false, false);
332 			mt_cur_cpu_cycles_instrs_speculative(&current_cycles, &current_instrs);
333 			ml_set_interrupts_enabled_with_debug(istate, false);
334 
335 			uint64_t duration_ns;
336 			absolutetime_to_nanoseconds(gross_duration, &duration_ns);
337 
338 			average_freq = (current_cycles - thread->machine.preemption_disable_cycles) / (duration_ns / 1000);
339 			average_cpi_whole = (current_cycles - thread->machine.preemption_disable_cycles) / (current_instrs - thread->machine.preemption_disable_instr);
340 			average_cpi_fractional =
341 			    (((current_cycles - thread->machine.preemption_disable_cycles) * 100) / (current_instrs - thread->machine.preemption_disable_instr)) % 100;
342 		}
343 #endif
344 
345 		if (sched_preemption_disable_debug_mode == SCHED_HYGIENE_MODE_PANIC) {
346 			panic("preemption disable timeout exceeded: %llu >= %llu mt ticks (start: %llu, now: %llu, gross: %llu, inttime: %llu), "
347 			    "freq = %llu MHz, CPI = %llu.%llu",
348 			    net_duration, threshold, mt, now, gross_duration, adjust,
349 			    average_freq, average_cpi_whole, average_cpi_fractional);
350 		}
351 
352 		DTRACE_SCHED4(mach_preemption_expired, uint64_t, net_duration, uint64_t, gross_duration,
353 		    uint64_t, average_cpi_whole, uint64_t, average_cpi_fractional);
354 		if (__improbable(kdebug_debugid_enabled(sched_preemption_disable_debug_dbgid))) {
355 			KDBG(sched_preemption_disable_debug_dbgid, net_duration, gross_duration, average_cpi_whole, average_cpi_fractional);
356 		}
357 	}
358 }
359 
360 #if SCHED_HYGIENE_DEBUG
361 
362 /*
363  * Abandon a potential preemption disable measurement. Useful for
364  * example for the idle thread, which would just spuriously
365  * trigger the threshold while actually idling, which we don't
366  * care about.
367  */
368 void
abandon_preemption_disable_measurement(void)369 abandon_preemption_disable_measurement(void)
370 {
371 	thread_t t = current_thread();
372 	bool istate = ml_set_interrupts_enabled_with_debug(false, false); // don't take int masked timestamp
373 
374 	if (t->machine.preemption_disable_mt != 0) {
375 		t->machine.preemption_disable_abandon = true;
376 	}
377 	ml_set_interrupts_enabled_with_debug(istate, false);
378 }
379 
380 #endif
381 
382 
383 /*
384  * Skip predicate for sched_preemption_disable, which would trigger
385  * spuriously when kprintf spam is enabled.
386  */
387 bool
kprintf_spam_mt_pred(struct machine_timeout_spec const __unused * spec)388 kprintf_spam_mt_pred(struct machine_timeout_spec const __unused *spec)
389 {
390 	bool const kprintf_spam_enabled = !(disable_kprintf_output || disable_serial_output);
391 	return kprintf_spam_enabled;
392 }
393 
394 #endif /* SCHED_HYGIENE_DEBUG */
395 
396 /*
397  * To help _disable_preemption() inline everywhere with LTO,
398  * we keep these nice non inlineable functions as the panic()
399  * codegen setup is quite large and for weird reasons causes a frame.
400  */
401 __abortlike
402 static void
_disable_preemption_overflow(void)403 _disable_preemption_overflow(void)
404 {
405 	panic("Preemption count overflow");
406 }
407 
408 void
_disable_preemption(void)409 _disable_preemption(void)
410 {
411 	thread_t     thread = current_thread();
412 	unsigned int count  = thread->machine.preemption_count;
413 
414 	if (__improbable(++count == 0)) {
415 		_disable_preemption_overflow();
416 	}
417 
418 	os_atomic_store(&thread->machine.preemption_count, count, compiler_acq_rel);
419 
420 #if SCHED_HYGIENE_DEBUG
421 	/*
422 	 * Note that this is not the only place preemption gets disabled,
423 	 * it also gets modified on ISR and PPL entry/exit. Both of those
424 	 * events will be treated specially however, and
425 	 * increment/decrement being paired around their entry/exit means
426 	 * that collection here is not desynced otherwise.
427 	 */
428 
429 	if (count == 1 && sched_preemption_disable_debug_mode) {
430 		_prepare_preemption_disable_measurement(thread);
431 	}
432 #endif /* SCHED_HYGIENE_DEBUG */
433 }
434 
435 /*
436  * This variant of _disable_preemption() allows disabling preemption
437  * without taking measurements (and later potentially triggering
438  * actions on those).
439  *
440  * We do this through a separate variant because we do not want to
441  * disturb inlinability of _disable_preemption(). However, in order to
442  * also avoid code duplication, instead of repeating common code we
443  * simply call _disable_preemption() and explicitly abandon any taken
444  * measurement.
445  */
446 void
_disable_preemption_without_measurements(void)447 _disable_preemption_without_measurements(void)
448 {
449 	_disable_preemption();
450 
451 #if SCHED_HYGIENE_DEBUG
452 	abandon_preemption_disable_measurement();
453 #endif /* SCHED_HYGIENE_DEBUG */
454 }
455 
456 /*
457  * This function checks whether an AST_URGENT has been pended.
458  *
459  * It is called once the preemption has been reenabled, which means the thread
460  * may have been preempted right before this was called, and when this function
461  * actually performs the check, we've changed CPU.
462  *
463  * This race is however benign: the point of AST_URGENT is to trigger a context
464  * switch, so if one happened, there's nothing left to check for, and AST_URGENT
465  * was cleared in the process.
466  *
467  * It follows that this check cannot have false negatives, which allows us
468  * to avoid fiddling with interrupt state for the vast majority of cases
469  * when the check will actually be negative.
470  */
471 static NOINLINE void
kernel_preempt_check(thread_t thread)472 kernel_preempt_check(thread_t thread)
473 {
474 	uint64_t state;
475 
476 	/* If interrupts are masked, we can't take an AST here */
477 	state = __builtin_arm_rsr64("DAIF");
478 	if (state & DAIF_IRQF) {
479 		return;
480 	}
481 
482 	/* disable interrupts (IRQ FIQ ASYNCF) */
483 	__builtin_arm_wsr64("DAIFSet", DAIFSC_STANDARD_DISABLE);
484 
485 	/*
486 	 * Reload cpu_pending_ast: a context switch would cause it to change.
487 	 * Now that interrupts are disabled, this will debounce false positives.
488 	 */
489 	if (thread->machine.CpuDatap->cpu_pending_ast & AST_URGENT) {
490 		ast_taken_kernel();
491 	}
492 
493 	/* restore the original interrupt mask */
494 	__builtin_arm_wsr64("DAIF", state);
495 }
496 
497 /*
498  * To help _enable_preemption() inline everywhere with LTO,
499  * we keep these nice non inlineable functions as the panic()
500  * codegen setup is quite large and for weird reasons causes a frame.
501  */
502 __abortlike
503 static void
_enable_preemption_underflow(void)504 _enable_preemption_underflow(void)
505 {
506 	panic("Preemption count underflow");
507 }
508 
509 void
_enable_preemption(void)510 _enable_preemption(void)
511 {
512 	thread_t     thread = current_thread();
513 	unsigned int count  = thread->machine.preemption_count;
514 
515 	if (__improbable(count == 0)) {
516 		_enable_preemption_underflow();
517 	}
518 	count -= 1;
519 
520 #if SCHED_HYGIENE_DEBUG
521 	if (count == 0 && thread->machine.preemption_disable_mt != 0) {
522 		_collect_preemption_disable_measurement(thread);
523 	}
524 #endif /* SCHED_HYGIENE_DEBUG */
525 
526 	os_atomic_store(&thread->machine.preemption_count, count, compiler_acq_rel);
527 	if (count == 0) {
528 		/*
529 		 * This check is racy and could load from another CPU's pending_ast mask,
530 		 * but as described above, this can't have false negatives.
531 		 */
532 		if (__improbable(thread->machine.CpuDatap->cpu_pending_ast & AST_URGENT)) {
533 			kernel_preempt_check(thread);
534 		}
535 	}
536 
537 	os_compiler_barrier();
538 }
539 
540 int
get_preemption_level(void)541 get_preemption_level(void)
542 {
543 	return current_thread()->machine.preemption_count;
544 }
545 
546 #if CONFIG_PV_TICKET
547 __startup_func
548 void
lck_init_pv(void)549 lck_init_pv(void)
550 {
551 	uint32_t pvtck = 1;
552 	PE_parse_boot_argn("pvticket", &pvtck, sizeof(pvtck));
553 	if (pvtck == 0) {
554 		return;
555 	}
556 	has_lock_pv = hvg_is_hcall_available(HVG_HCALL_VCPU_WFK) &&
557 	    hvg_is_hcall_available(HVG_HCALL_VCPU_KICK);
558 }
559 STARTUP(LOCKS, STARTUP_RANK_FIRST, lck_init_pv);
560 #endif
561 
562 
563 #pragma mark lck_spin_t
564 #if LCK_SPIN_IS_TICKET_LOCK
565 
566 lck_spin_t *
lck_spin_alloc_init(lck_grp_t * grp,lck_attr_t * attr)567 lck_spin_alloc_init(lck_grp_t *grp, lck_attr_t *attr)
568 {
569 	lck_spin_t *lck;
570 
571 	lck = zalloc(KT_LCK_SPIN);
572 	lck_spin_init(lck, grp, attr);
573 	return lck;
574 }
575 
576 void
lck_spin_free(lck_spin_t * lck,lck_grp_t * grp)577 lck_spin_free(lck_spin_t *lck, lck_grp_t *grp)
578 {
579 	lck_spin_destroy(lck, grp);
580 	zfree(KT_LCK_SPIN, lck);
581 }
582 
583 void
lck_spin_init(lck_spin_t * lck,lck_grp_t * grp,__unused lck_attr_t * attr)584 lck_spin_init(lck_spin_t *lck, lck_grp_t *grp, __unused lck_attr_t *attr)
585 {
586 	lck_ticket_init(lck, grp);
587 }
588 
589 /*
590  * arm_usimple_lock is a lck_spin_t without a group or attributes
591  */
592 MARK_AS_HIBERNATE_TEXT void inline
arm_usimple_lock_init(simple_lock_t lck,__unused unsigned short initial_value)593 arm_usimple_lock_init(simple_lock_t lck, __unused unsigned short initial_value)
594 {
595 	lck_ticket_init((lck_ticket_t *)lck, LCK_GRP_NULL);
596 }
597 
598 void
lck_spin_assert(lck_spin_t * lock,unsigned int type)599 lck_spin_assert(lck_spin_t *lock, unsigned int type)
600 {
601 	if (type == LCK_ASSERT_OWNED) {
602 		lck_ticket_assert_owned(lock);
603 	} else if (type == LCK_ASSERT_NOTOWNED) {
604 		lck_ticket_assert_not_owned(lock);
605 	} else {
606 		panic("lck_spin_assert(): invalid arg (%u)", type);
607 	}
608 }
609 
610 void
lck_spin_lock(lck_spin_t * lock)611 lck_spin_lock(lck_spin_t *lock)
612 {
613 	lck_ticket_lock(lock, LCK_GRP_NULL);
614 }
615 
616 void
lck_spin_lock_nopreempt(lck_spin_t * lock)617 lck_spin_lock_nopreempt(lck_spin_t *lock)
618 {
619 	lck_ticket_lock_nopreempt(lock, LCK_GRP_NULL);
620 }
621 
622 int
lck_spin_try_lock(lck_spin_t * lock)623 lck_spin_try_lock(lck_spin_t *lock)
624 {
625 	return lck_ticket_lock_try(lock, LCK_GRP_NULL);
626 }
627 
628 int
lck_spin_try_lock_nopreempt(lck_spin_t * lock)629 lck_spin_try_lock_nopreempt(lck_spin_t *lock)
630 {
631 	return lck_ticket_lock_try_nopreempt(lock, LCK_GRP_NULL);
632 }
633 
634 void
lck_spin_unlock(lck_spin_t * lock)635 lck_spin_unlock(lck_spin_t *lock)
636 {
637 	lck_ticket_unlock(lock);
638 }
639 
640 void
lck_spin_destroy(lck_spin_t * lck,lck_grp_t * grp)641 lck_spin_destroy(lck_spin_t *lck, lck_grp_t *grp)
642 {
643 	lck_ticket_destroy(lck, grp);
644 }
645 
646 /*
647  * those really should be in an alias file instead,
648  * but you can't make that conditional.
649  *
650  * it will be good enough for perf evals for now
651  *
652  * we also can't make aliases for symbols that
653  * are in alias files like lck_spin_init and friends,
654  * so this suffers double jump penalties for kexts
655  * (LTO does the right thing for XNU).
656  */
657 #define make_alias(a, b) asm(".globl _" #a "\n" ".set   _" #a ", _" #b "\n")
658 make_alias(lck_spin_lock_grp, lck_ticket_lock);
659 make_alias(lck_spin_lock_nopreempt_grp, lck_ticket_lock_nopreempt);
660 make_alias(lck_spin_try_lock_grp, lck_ticket_lock_try);
661 make_alias(lck_spin_try_lock_nopreempt_grp, lck_ticket_lock_try_nopreempt);
662 make_alias(lck_spin_unlock_nopreempt, lck_ticket_unlock_nopreempt);
663 make_alias(kdp_lck_spin_is_acquired, kdp_lck_ticket_is_acquired);
664 #undef make_alias
665 
666 #else /* !LCK_SPIN_IS_TICKET_LOCK */
667 
668 #if DEVELOPMENT || DEBUG
669 __abortlike
670 static void
__lck_spin_invalid_panic(lck_spin_t * lck)671 __lck_spin_invalid_panic(lck_spin_t *lck)
672 {
673 	const char *how = "Invalid";
674 
675 	if (lck->type == LCK_SPIN_TYPE_DESTROYED ||
676 	    lck->lck_spin_data == LCK_SPIN_TAG_DESTROYED) {
677 		how = "Destroyed";
678 	}
679 
680 	panic("%s spinlock %p: <0x%016lx 0x%16lx>",
681 	    how, lck, lck->lck_spin_data, lck->type);
682 }
683 
684 static inline void
lck_spin_verify(lck_spin_t * lck)685 lck_spin_verify(lck_spin_t *lck)
686 {
687 	if (lck->type != LCK_SPIN_TYPE ||
688 	    lck->lck_spin_data == LCK_SPIN_TAG_DESTROYED) {
689 		__lck_spin_invalid_panic(lck);
690 	}
691 }
692 #else /* DEVELOPMENT || DEBUG */
693 #define lck_spin_verify(lck)            ((void)0)
694 #endif /* DEVELOPMENT || DEBUG */
695 
696 lck_spin_t *
lck_spin_alloc_init(lck_grp_t * grp,lck_attr_t * attr)697 lck_spin_alloc_init(lck_grp_t *grp, lck_attr_t *attr)
698 {
699 	lck_spin_t *lck;
700 
701 	lck = zalloc(KT_LCK_SPIN);
702 	lck_spin_init(lck, grp, attr);
703 	return lck;
704 }
705 
706 void
lck_spin_free(lck_spin_t * lck,lck_grp_t * grp)707 lck_spin_free(lck_spin_t *lck, lck_grp_t *grp)
708 {
709 	lck_spin_destroy(lck, grp);
710 	zfree(KT_LCK_SPIN, lck);
711 }
712 
713 void
lck_spin_init(lck_spin_t * lck,lck_grp_t * grp,__unused lck_attr_t * attr)714 lck_spin_init(lck_spin_t *lck, lck_grp_t *grp, __unused lck_attr_t *attr)
715 {
716 	lck->type = LCK_SPIN_TYPE;
717 	hw_lock_init(&lck->hwlock);
718 	if (grp) {
719 		lck_grp_reference(grp, &grp->lck_grp_spincnt);
720 	}
721 }
722 
723 /*
724  * arm_usimple_lock is a lck_spin_t without a group or attributes
725  */
726 MARK_AS_HIBERNATE_TEXT void inline
arm_usimple_lock_init(simple_lock_t lck,__unused unsigned short initial_value)727 arm_usimple_lock_init(simple_lock_t lck, __unused unsigned short initial_value)
728 {
729 	lck->type = LCK_SPIN_TYPE;
730 	hw_lock_init(&lck->hwlock);
731 }
732 
733 void
lck_spin_assert(lck_spin_t * lock,unsigned int type)734 lck_spin_assert(lck_spin_t *lock, unsigned int type)
735 {
736 	thread_t thread, holder;
737 
738 	if (lock->type != LCK_SPIN_TYPE) {
739 		panic("Invalid spinlock %p", lock);
740 	}
741 
742 	holder = HW_LOCK_STATE_TO_THREAD(lock->lck_spin_data);
743 	thread = current_thread();
744 	if (type == LCK_ASSERT_OWNED) {
745 		if (holder == 0) {
746 			panic("Lock not owned %p = %p", lock, holder);
747 		}
748 		if (holder != thread) {
749 			panic("Lock not owned by current thread %p = %p", lock, holder);
750 		}
751 	} else if (type == LCK_ASSERT_NOTOWNED) {
752 		if (holder != THREAD_NULL && holder == thread) {
753 			panic("Lock owned by current thread %p = %p", lock, holder);
754 		}
755 	} else {
756 		panic("lck_spin_assert(): invalid arg (%u)", type);
757 	}
758 }
759 
760 void
lck_spin_lock(lck_spin_t * lock)761 lck_spin_lock(lck_spin_t *lock)
762 {
763 	lck_spin_verify(lock);
764 	hw_lock_lock(&lock->hwlock, LCK_GRP_NULL);
765 }
766 
767 void
lck_spin_lock_grp(lck_spin_t * lock,lck_grp_t * grp)768 lck_spin_lock_grp(lck_spin_t *lock, lck_grp_t *grp)
769 {
770 #pragma unused(grp)
771 	lck_spin_verify(lock);
772 	hw_lock_lock(&lock->hwlock, grp);
773 }
774 
775 void
lck_spin_lock_nopreempt(lck_spin_t * lock)776 lck_spin_lock_nopreempt(lck_spin_t *lock)
777 {
778 	lck_spin_verify(lock);
779 	hw_lock_lock_nopreempt(&lock->hwlock, LCK_GRP_NULL);
780 }
781 
782 void
lck_spin_lock_nopreempt_grp(lck_spin_t * lock,lck_grp_t * grp)783 lck_spin_lock_nopreempt_grp(lck_spin_t *lock, lck_grp_t *grp)
784 {
785 #pragma unused(grp)
786 	lck_spin_verify(lock);
787 	hw_lock_lock_nopreempt(&lock->hwlock, grp);
788 }
789 
790 int
lck_spin_try_lock(lck_spin_t * lock)791 lck_spin_try_lock(lck_spin_t *lock)
792 {
793 	lck_spin_verify(lock);
794 	return hw_lock_try(&lock->hwlock, LCK_GRP_NULL);
795 }
796 
797 int
lck_spin_try_lock_grp(lck_spin_t * lock,lck_grp_t * grp)798 lck_spin_try_lock_grp(lck_spin_t *lock, lck_grp_t *grp)
799 {
800 #pragma unused(grp)
801 	lck_spin_verify(lock);
802 	return hw_lock_try(&lock->hwlock, grp);
803 }
804 
805 int
lck_spin_try_lock_nopreempt(lck_spin_t * lock)806 lck_spin_try_lock_nopreempt(lck_spin_t *lock)
807 {
808 	lck_spin_verify(lock);
809 	return hw_lock_try_nopreempt(&lock->hwlock, LCK_GRP_NULL);
810 }
811 
812 int
lck_spin_try_lock_nopreempt_grp(lck_spin_t * lock,lck_grp_t * grp)813 lck_spin_try_lock_nopreempt_grp(lck_spin_t *lock, lck_grp_t *grp)
814 {
815 #pragma unused(grp)
816 	lck_spin_verify(lock);
817 	return hw_lock_try_nopreempt(&lock->hwlock, grp);
818 }
819 
820 void
lck_spin_unlock(lck_spin_t * lock)821 lck_spin_unlock(lck_spin_t *lock)
822 {
823 	lck_spin_verify(lock);
824 	hw_lock_unlock(&lock->hwlock);
825 }
826 
827 void
lck_spin_unlock_nopreempt(lck_spin_t * lock)828 lck_spin_unlock_nopreempt(lck_spin_t *lock)
829 {
830 	lck_spin_verify(lock);
831 	hw_lock_unlock_nopreempt(&lock->hwlock);
832 }
833 
834 void
lck_spin_destroy(lck_spin_t * lck,lck_grp_t * grp)835 lck_spin_destroy(lck_spin_t *lck, lck_grp_t *grp)
836 {
837 	lck_spin_verify(lck);
838 	*lck = (lck_spin_t){
839 		.lck_spin_data = LCK_SPIN_TAG_DESTROYED,
840 		.type = LCK_SPIN_TYPE_DESTROYED,
841 	};
842 	if (grp) {
843 		lck_grp_deallocate(grp, &grp->lck_grp_spincnt);
844 	}
845 }
846 
847 /*
848  * Routine: kdp_lck_spin_is_acquired
849  * NOT SAFE: To be used only by kernel debugger to avoid deadlock.
850  */
851 boolean_t
kdp_lck_spin_is_acquired(lck_spin_t * lck)852 kdp_lck_spin_is_acquired(lck_spin_t *lck)
853 {
854 	if (not_in_kdp) {
855 		panic("panic: spinlock acquired check done outside of kernel debugger");
856 	}
857 	return ((lck->lck_spin_data & ~LCK_SPIN_TAG_DESTROYED) != 0) ? TRUE:FALSE;
858 }
859 
860 #endif /* !LCK_SPIN_IS_TICKET_LOCK */
861 
862 /*
863  *	Initialize a usimple_lock.
864  *
865  *	No change in preemption state.
866  */
867 void
usimple_lock_init(usimple_lock_t l,unsigned short tag)868 usimple_lock_init(
869 	usimple_lock_t l,
870 	unsigned short tag)
871 {
872 	simple_lock_init((simple_lock_t) l, tag);
873 }
874 
875 
876 /*
877  *	Acquire a usimple_lock.
878  *
879  *	Returns with preemption disabled.  Note
880  *	that the hw_lock routines are responsible for
881  *	maintaining preemption state.
882  */
883 void
884 (usimple_lock)(
885 	usimple_lock_t l
886 	LCK_GRP_ARG(lck_grp_t *grp))
887 {
888 	simple_lock((simple_lock_t) l, LCK_GRP_PROBEARG(grp));
889 }
890 
891 
892 /*
893  *	Release a usimple_lock.
894  *
895  *	Returns with preemption enabled.  Note
896  *	that the hw_lock routines are responsible for
897  *	maintaining preemption state.
898  */
899 void
900 (usimple_unlock)(
901 	usimple_lock_t l)
902 {
903 	simple_unlock((simple_lock_t)l);
904 }
905 
906 
907 /*
908  *	Conditionally acquire a usimple_lock.
909  *
910  *	On success, returns with preemption disabled.
911  *	On failure, returns with preemption in the same state
912  *	as when first invoked.  Note that the hw_lock routines
913  *	are responsible for maintaining preemption state.
914  *
915  *	XXX No stats are gathered on a miss; I preserved this
916  *	behavior from the original assembly-language code, but
917  *	doesn't it make sense to log misses?  XXX
918  */
919 unsigned
920 int
921 (usimple_lock_try)(
922 	usimple_lock_t l
923 	LCK_GRP_ARG(lck_grp_t *grp))
924 {
925 	return simple_lock_try((simple_lock_t) l, grp);
926 }
927