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