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