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