1/*
2 * Copyright (c) 2000-2004 Apple Computer, 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 * Copyright (C) 1998 Apple Computer
30 * All Rights Reserved
31 */
32/*
33 * @OSF_COPYRIGHT@
34 */
35/*
36 * Mach Operating System
37 * Copyright (c) 1991,1990 Carnegie Mellon University
38 * All Rights Reserved.
39 *
40 * Permission to use, copy, modify and distribute this software and its
41 * documentation is hereby granted, provided that both the copyright
42 * notice and this permission notice appear in all copies of the
43 * software, derivative works or modified versions, and any portions
44 * thereof, and that both notices appear in supporting documentation.
45 *
46 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
48 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49 *
50 * Carnegie Mellon requests users of this software to return to
51 *
52 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53 *  School of Computer Science
54 *  Carnegie Mellon University
55 *  Pittsburgh PA 15213-3890
56 *
57 * any improvements or extensions that they make and grant Carnegie Mellon
58 * the rights to redistribute these changes.
59 */
60
61/*
62 */
63
64/*
65 * Machine-dependent simple locks for the i386.
66 */
67#ifdef	KERNEL_PRIVATE
68
69#ifndef	_I386_LOCK_H_
70#define	_I386_LOCK_H_
71
72#include <sys/appleapiopts.h>
73
74#ifdef __APPLE_API_PRIVATE
75
76#ifdef MACH_KERNEL_PRIVATE
77
78#include <kern/macro_help.h>
79#include <kern/assert.h>
80#include <i386/hw_lock_types.h>
81#include <i386/locks.h>
82
83#include <mach_rt.h>
84#include <mach_ldebug.h>
85
86typedef struct {
87	lck_mtx_t	lck_mtx;	/* inlined lck_mtx, need to be first */
88#if     MACH_LDEBUG
89	int				type;
90#define MUTEX_TAG       0x4d4d
91	vm_offset_t		pc;
92	vm_offset_t		thread;
93#endif  /* MACH_LDEBUG */
94} mutex_t;
95
96typedef lck_rw_t lock_t;
97
98extern unsigned int LockTimeOutTSC;	/* Lock timeout in TSC ticks */
99extern unsigned int LockTimeOut;	/* Lock timeout in absolute time */
100
101
102#if defined(__GNUC__)
103
104/*
105 *	General bit-lock routines.
106 */
107
108#define	bit_lock(bit,l)							\
109	__asm__ volatile("	jmp	1f	\n			\
110		 	0:	btl	%0, %1	\n			\
111				jb	0b	\n			\
112			1:	lock		\n			\
113				btsl	%0,%1	\n			\
114				jb	0b"			:	\
115								:	\
116			"r" (bit), "m" (*(volatile int *)(l))	:	\
117			"memory");
118
119#define	bit_unlock(bit,l)						\
120	__asm__ volatile("	lock		\n			\
121				btrl	%0,%1"			:	\
122								:	\
123			"r" (bit), "m" (*(volatile int *)(l)));
124
125/*
126 *      Set or clear individual bits in a long word.
127 *      The locked access is needed only to lock access
128 *      to the word, not to individual bits.
129 */
130
131#define	i_bit_set(bit,l)						\
132	__asm__ volatile("	lock		\n			\
133				btsl	%0,%1"			:	\
134								:	\
135			"r" (bit), "m" (*(volatile int *)(l)));
136
137#define	i_bit_clear(bit,l)						\
138	__asm__ volatile("	lock		\n			\
139				btrl	%0,%1"			:	\
140								:	\
141			"r" (bit), "m" (*(volatile int *)(l)));
142
143static inline unsigned long i_bit_isset(unsigned int test, volatile unsigned long *word)
144{
145	int	bit;
146
147	__asm__ volatile("btl %2,%1\n\tsbbl %0,%0" : "=r" (bit)
148		: "m" (word), "ir" (test));
149	return bit;
150}
151
152static inline char	xchgb(volatile char * cp, char new);
153
154static inline void	atomic_incl(volatile long * p, long delta);
155static inline void	atomic_incs(volatile short * p, short delta);
156static inline void	atomic_incb(volatile char * p, char delta);
157
158static inline void	atomic_decl(volatile long * p, long delta);
159static inline void	atomic_decs(volatile short * p, short delta);
160static inline void	atomic_decb(volatile char * p, char delta);
161
162static inline long	atomic_getl(const volatile long * p);
163static inline short	atomic_gets(const volatile short * p);
164static inline char	atomic_getb(const volatile char * p);
165
166static inline void	atomic_setl(volatile long * p, long value);
167static inline void	atomic_sets(volatile short * p, short value);
168static inline void	atomic_setb(volatile char * p, char value);
169
170static inline char	xchgb(volatile char * cp, char new)
171{
172	register char	old = new;
173
174	__asm__ volatile ("	xchgb	%0,%2"			:
175			"=q" (old)				:
176			"0" (new), "m" (*(volatile char *)cp) : "memory");
177	return (old);
178}
179
180/*
181 * Compare and exchange:
182 * - returns failure (0) if the location did not contain the old value,
183 * - returns success (1) if the location was set to the new value.
184 */
185static inline uint32_t
186atomic_cmpxchg(uint32_t *p, uint32_t old, uint32_t new)
187{
188	uint32_t res = old;
189
190	__asm__ volatile(
191		"lock;	cmpxchgl	%1,%2;	\n\t"
192		"	setz		%%al;	\n\t"
193		"	movzbl		%%al,%0"
194		: "+a" (res)	/* %0: old value to compare, returns success */
195		: "r" (new),	/* %1: new value to set */
196		  "m" (*(p))	/* %2: memory address */
197		: "memory");
198	return (res);
199}
200
201static inline void	atomic_incl(volatile long * p, long delta)
202{
203	__asm__ volatile ("	lock		\n		\
204				addl    %0,%1"		:	\
205							:	\
206				"r" (delta), "m" (*(volatile long *)p));
207}
208
209static inline void	atomic_incs(volatile short * p, short delta)
210{
211	__asm__ volatile ("	lock		\n		\
212				addw    %0,%1"		:	\
213							:	\
214				"q" (delta), "m" (*(volatile short *)p));
215}
216
217static inline void	atomic_incb(volatile char * p, char delta)
218{
219	__asm__ volatile ("	lock		\n		\
220				addb    %0,%1"		:	\
221							:	\
222				"q" (delta), "m" (*(volatile char *)p));
223}
224
225static inline void	atomic_decl(volatile long * p, long delta)
226{
227	__asm__ volatile ("	lock		\n		\
228				subl	%0,%1"		:	\
229							:	\
230				"r" (delta), "m" (*(volatile long *)p));
231}
232
233static inline int	atomic_decl_and_test(volatile long * p, long delta)
234{
235	uint8_t	ret;
236	__asm__ volatile (
237		"	lock		\n\t"
238		"	subl	%1,%2	\n\t"
239		"	sete	%0"
240		: "=qm" (ret)
241		: "r" (delta), "m" (*(volatile long *)p));
242	return ret;
243}
244
245static inline void	atomic_decs(volatile short * p, short delta)
246{
247	__asm__ volatile ("	lock		\n		\
248				subw    %0,%1"		:	\
249							:	\
250				"q" (delta), "m" (*(volatile short *)p));
251}
252
253static inline void	atomic_decb(volatile char * p, char delta)
254{
255	__asm__ volatile ("	lock		\n		\
256				subb    %0,%1"		:	\
257							:	\
258				"q" (delta), "m" (*(volatile char *)p));
259}
260
261static inline long	atomic_getl(const volatile long * p)
262{
263	return (*p);
264}
265
266static inline short	atomic_gets(const volatile short * p)
267{
268	return (*p);
269}
270
271static inline char	atomic_getb(const volatile char * p)
272{
273	return (*p);
274}
275
276static inline void	atomic_setl(volatile long * p, long value)
277{
278	*p = value;
279}
280
281static inline void	atomic_sets(volatile short * p, short value)
282{
283	*p = value;
284}
285
286static inline void	atomic_setb(volatile char * p, char value)
287{
288	*p = value;
289}
290
291
292#else	/* !defined(__GNUC__) */
293
294extern void	i_bit_set(
295	int index,
296	void *addr);
297
298extern void	i_bit_clear(
299	int index,
300	void *addr);
301
302extern void bit_lock(
303	int index,
304	void *addr);
305
306extern void bit_unlock(
307	int index,
308	void *addr);
309
310/*
311 * All other routines defined in __GNUC__ case lack
312 * definitions otherwise. - XXX
313 */
314
315#endif	/* !defined(__GNUC__) */
316
317extern void		kernel_preempt_check (void);
318
319#endif /* MACH_KERNEL_PRIVATE */
320
321#endif /* __APLE_API_PRIVATE */
322
323#endif	/* _I386_LOCK_H_ */
324
325#endif	/* KERNEL_PRIVATE */
326