1/*
2 * Copyright (c) 2000 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#include <sys/time.h>
29#include <kern/task.h>
30#include <kern/thread.h>
31#include <mach/mach_types.h>
32#include <mach/vm_prot.h>
33#include <vm/vm_kern.h>
34#include <sys/stat.h>
35#include <vm/vm_map.h>
36#include <sys/systm.h>
37#include <kern/assert.h>
38#include <sys/conf.h>
39#include <sys/proc_internal.h>
40#include <sys/buf.h>	/* for SET */
41#include <sys/kernel.h>
42#include <sys/user.h>
43#include <sys/sysent.h>
44#include <sys/sysproto.h>
45
46/* XXX these should be in a common header somwhere, but aren't */
47extern int chrtoblk_set(int, int);
48extern vm_offset_t kmem_mb_alloc(vm_map_t, int, int);
49
50/* XXX most of these just exist to export; there's no good header for them*/
51void	pcb_synch(void);
52void	tbeproc(void *);
53
54TAILQ_HEAD(,devsw_lock) devsw_locks;
55lck_mtx_t devsw_lock_list_mtx;
56lck_grp_t *devsw_lock_grp;
57
58/* Just to satisfy pstat command */
59int     dmmin, dmmax, dmtext;
60
61vm_offset_t
62kmem_mb_alloc(vm_map_t  mbmap, int size, int physContig)
63{
64        vm_offset_t addr = 0;
65	kern_return_t kr = KERN_SUCCESS;
66
67	if(!physContig)
68		kr = kernel_memory_allocate(mbmap, &addr, size,
69			0, KMA_NOPAGEWAIT|KMA_KOBJECT|KMA_LOMEM);
70	else
71		kr = kmem_alloc_contig(mbmap, &addr, size, PAGE_MASK,
72			0xfffff, 0, KMA_NOPAGEWAIT | KMA_KOBJECT | KMA_LOMEM);
73
74	if( kr != KERN_SUCCESS)
75		addr = 0;
76
77	return addr;
78}
79
80/*
81 * XXX this function only exists to be exported and do nothing.
82 */
83void
84pcb_synch(void)
85{
86}
87
88struct proc *
89current_proc(void)
90{
91	/* Never returns a NULL */
92	struct uthread * ut;
93	struct proc *p;
94	thread_t thread = current_thread();
95
96	ut = (struct uthread *)get_bsdthread_info(thread);
97	if (ut &&  (ut->uu_flag & UT_VFORK) && ut->uu_proc) {
98		p = ut->uu_proc;
99		if ((p->p_lflag & P_LINVFORK) == 0)
100			panic("returning child proc not under vfork");
101		if (p->p_vforkact != (void *)thread)
102			panic("returning child proc which is not cur_act");
103		return(p);
104	}
105
106	p = (struct proc *)get_bsdtask_info(current_task());
107
108	if (p == NULL)
109		return (kernproc);
110
111	return (p);
112}
113
114/* Device switch add delete routines */
115
116struct bdevsw nobdev = NO_BDEVICE;
117struct cdevsw nocdev = NO_CDEVICE;
118/*
119 *	if index is -1, return a free slot if avaliable
120 *	  else see whether the index is free
121 *	return the major number that is free else -1
122 *
123 *	if index is negative, we start
124 *	looking for a free slot at the absolute value of index,
125 *	instead of starting at 0
126 */
127int
128bdevsw_isfree(int index)
129{
130	struct bdevsw *devsw;
131
132	if (index < 0) {
133	    if (index == -1)
134	    	index = 1;	/* start at 1 to avoid collision with volfs (Radar 2842228) */
135	    else
136	        index = -index;	/* start at least this far up in the table */
137	    devsw = &bdevsw[index];
138	    for(; index < nblkdev; index++, devsw++) {
139	        if(memcmp((char *)devsw,
140	        	    (char *)&nobdev,
141	        	    sizeof(struct bdevsw)) == 0)
142	            break;
143	    }
144	}
145	devsw = &bdevsw[index];
146	if ((index < 0) || (index >= nblkdev) ||
147	    (memcmp((char *)devsw,
148		          (char *)&nobdev,
149			  sizeof(struct bdevsw)) != 0)) {
150		return(-1);
151	}
152	return(index);
153}
154
155/*
156 *	if index is -1, find a free slot to add
157 *	  else see whether the slot is free
158 *	return the major number that is used else -1
159 *
160 *	if index is negative, we start
161 *	looking for a free slot at the absolute value of index,
162 *	instead of starting at 0
163 */
164int
165bdevsw_add(int index, struct bdevsw * bsw)
166{
167	index = bdevsw_isfree(index);
168	if (index < 0) {
169		return(-1);
170	}
171	bdevsw[index] = *bsw;
172	return(index);
173}
174/*
175 *	if the slot has the same bsw, then remove
176 *	else -1
177 */
178int
179bdevsw_remove(int index, struct bdevsw * bsw)
180{
181	struct bdevsw *devsw;
182
183	devsw = &bdevsw[index];
184	if ((index < 0) || (index >= nblkdev) ||
185	    (memcmp((char *)devsw,
186		          (char *)bsw,
187			  sizeof(struct bdevsw)) != 0)) {
188		return(-1);
189	}
190	bdevsw[index] = nobdev;
191	return(index);
192}
193
194/*
195 *	if index is -1, return a free slot if avaliable
196 *	  else see whether the index is free
197 *	return the major number that is free else -1
198 *
199 *	if index is negative, we start
200 *	looking for a free slot at the absolute value of index,
201 *	instead of starting at 0
202 */
203int
204cdevsw_isfree(int index)
205{
206	struct cdevsw *devsw;
207
208	if (index < 0) {
209	    if (index == -1)
210	    	index = 0;
211	    else
212	        index = -index;	/* start at least this far up in the table */
213	    devsw = &cdevsw[index];
214	    for(; index < nchrdev; index++, devsw++) {
215	        if(memcmp((char *)devsw,
216	        	    (char *)&nocdev,
217	        	    sizeof(struct cdevsw)) == 0)
218	            break;
219	    }
220	}
221	devsw = &cdevsw[index];
222	if ((index < 0) || (index >= nchrdev) ||
223	    (memcmp((char *)devsw,
224		          (char *)&nocdev,
225			  sizeof(struct cdevsw)) != 0)) {
226		return(-1);
227	}
228	return(index);
229}
230
231/*
232 *	if index is -1, find a free slot to add
233 *	  else see whether the slot is free
234 *	return the major number that is used else -1
235 *
236 *	if index is negative, we start
237 *	looking for a free slot at the absolute value of index,
238 *	instead of starting at 0
239 *
240 * NOTE:	In practice, -1 is unusable, since there are kernel internal
241 *		devices that call this function with absolute index values,
242 *		which will stomp on free-slot based assignments that happen
243 *		before them.  -24 is currently a safe starting point.
244 */
245int
246cdevsw_add(int index, struct cdevsw * csw)
247{
248	index = cdevsw_isfree(index);
249	if (index < 0) {
250		return(-1);
251	}
252	cdevsw[index] = *csw;
253	return(index);
254}
255/*
256 *	if the slot has the same csw, then remove
257 *	else -1
258 */
259int
260cdevsw_remove(int index, struct cdevsw * csw)
261{
262	struct cdevsw *devsw;
263
264	devsw = &cdevsw[index];
265	if ((index < 0) || (index >= nchrdev) ||
266	    (memcmp((char *)devsw,
267		          (char *)csw,
268			  sizeof(struct cdevsw)) != 0)) {
269		return(-1);
270	}
271	cdevsw[index] = nocdev;
272	cdevsw_flags[index] = 0;
273	return(index);
274}
275
276static int
277cdev_set_bdev(int cdev, int bdev)
278{
279	return (chrtoblk_set(cdev, bdev));
280}
281
282int
283cdevsw_add_with_bdev(int index, struct cdevsw * csw, int bdev)
284{
285	index = cdevsw_add(index, csw);
286	if (index < 0) {
287		return (index);
288	}
289	if (cdev_set_bdev(index, bdev) < 0) {
290		cdevsw_remove(index, csw);
291		return (-1);
292	}
293	return (index);
294}
295
296int
297cdevsw_setkqueueok(int index, struct cdevsw *csw, int use_offset)
298{
299	struct cdevsw *devsw;
300	uint64_t flags = CDEVSW_SELECT_KQUEUE;
301
302	devsw = &cdevsw[index];
303	if ((index < 0) || (index >= nchrdev) ||
304	    (memcmp((char *)devsw,
305		          (char *)csw,
306			  sizeof(struct cdevsw)) != 0)) {
307		return(-1);
308	}
309
310	if (use_offset) {
311		flags |= CDEVSW_USE_OFFSET;
312	}
313
314	cdevsw_flags[index] = flags;
315	return 0;
316}
317
318#include <pexpert/pexpert.h>	/* for PE_parse_boot_arg */
319
320void
321tbeproc(void *procp)
322{
323	struct proc *p = procp;
324
325	if (p)
326		OSBitOrAtomic(P_TBE, &p->p_flag);
327	return;
328}
329
330/*
331 * Copy the "hostname" variable into a caller-provided buffer
332 * Returns: 0 for success, ENAMETOOLONG for insufficient buffer space.
333 * On success, "len" will be set to the number of characters preceding
334 * the NULL character in the hostname.
335 */
336int
337bsd_hostname(char *buf, int bufsize, int *len)
338{
339	/*
340 	 * "hostname" is null-terminated, and "hostnamelen" is equivalent to strlen(hostname).
341	 */
342	if (hostnamelen < bufsize) {
343		strlcpy(buf, hostname, bufsize);
344		*len = hostnamelen;
345		return 0;
346	} else {
347		return ENAMETOOLONG;
348	}
349}
350
351void
352devsw_lock(dev_t dev, int mode)
353{
354	devsw_lock_t newlock, tmplock;
355	int res;
356
357	assert(0 <= major(dev) && major(dev) < nchrdev);
358	assert(mode == S_IFCHR || mode == S_IFBLK);
359
360	MALLOC(newlock, devsw_lock_t, sizeof(struct devsw_lock), M_TEMP, M_WAITOK | M_ZERO);
361	newlock->dl_dev = dev;
362	newlock->dl_thread = current_thread();
363	newlock->dl_mode = mode;
364
365	lck_mtx_lock_spin(&devsw_lock_list_mtx);
366retry:
367	TAILQ_FOREACH(tmplock, &devsw_locks, dl_list) {
368		if (tmplock->dl_dev == dev && tmplock->dl_mode == mode) {
369			res = msleep(tmplock, &devsw_lock_list_mtx, PVFS, "devsw_lock", NULL);
370			assert(res == 0);
371			goto retry;
372		}
373	}
374
375	TAILQ_INSERT_TAIL(&devsw_locks, newlock, dl_list);
376	lck_mtx_unlock(&devsw_lock_list_mtx);
377
378}
379void
380devsw_unlock(dev_t dev, int mode)
381{
382	devsw_lock_t tmplock;
383
384	assert(0 <= major(dev) && major(dev) < nchrdev);
385
386	lck_mtx_lock_spin(&devsw_lock_list_mtx);
387
388	TAILQ_FOREACH(tmplock, &devsw_locks, dl_list) {
389		if (tmplock->dl_dev == dev && tmplock->dl_mode == mode) {
390			break;
391		}
392	}
393
394	if (tmplock == NULL) {
395		panic("Trying to unlock, and couldn't find lock.");
396	}
397
398	if (tmplock->dl_thread != current_thread()) {
399		panic("Trying to unlock, but I don't hold the lock.");
400	}
401
402	wakeup(tmplock);
403	TAILQ_REMOVE(&devsw_locks, tmplock, dl_list);
404
405	lck_mtx_unlock(&devsw_lock_list_mtx);
406
407	FREE(tmplock, M_TEMP);
408}
409
410void
411devsw_init()
412{
413	devsw_lock_grp = lck_grp_alloc_init("devsw", NULL);
414	assert(devsw_lock_grp != NULL);
415
416	lck_mtx_init(&devsw_lock_list_mtx, devsw_lock_grp, NULL);
417	TAILQ_INIT(&devsw_locks);
418}
419