1/* 2 * Copyright (c) 2000-2006 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 <mach_kdb.h> 29#include <zone_debug.h> 30#include <mach_kdb.h> 31 32#include <mach/boolean.h> 33#include <mach/kern_return.h> 34#include <mach/mig_errors.h> 35#include <mach/port.h> 36#include <mach/vm_param.h> 37#include <mach/notify.h> 38//#include <mach/mach_host_server.h> 39#include <mach/mach_types.h> 40 41#include <machine/machparam.h> /* spl definitions */ 42 43#include <ipc/ipc_port.h> 44#include <ipc/ipc_space.h> 45 46#include <kern/clock.h> 47#include <kern/spl.h> 48#include <kern/counters.h> 49#include <kern/queue.h> 50#include <kern/zalloc.h> 51#include <kern/thread.h> 52#include <kern/task.h> 53#include <kern/sched_prim.h> 54#include <kern/misc_protos.h> 55 56#include <vm/pmap.h> 57#include <vm/vm_map.h> 58#include <vm/vm_kern.h> 59 60#include <device/device_types.h> 61#include <device/device_port.h> 62#include <device/device_server.h> 63 64#include <machine/machparam.h> 65 66#ifdef __ppc__ 67#include <ppc/mappings.h> 68#endif 69#ifdef __i386 70#include <i386/pmap.h> 71#endif 72#include <IOKit/IOTypes.h> 73 74#define EXTERN 75#define MIGEXTERN 76 77/* 78 * Functions in iokit:IOUserClient.cpp 79 */ 80 81extern void iokit_add_reference( io_object_t obj ); 82 83extern ipc_port_t iokit_port_for_object( io_object_t obj, 84 ipc_kobject_type_t type ); 85 86extern kern_return_t iokit_client_died( io_object_t obj, 87 ipc_port_t port, ipc_kobject_type_t type, mach_port_mscount_t * mscount ); 88 89extern kern_return_t 90iokit_client_memory_for_type( 91 io_object_t connect, 92 unsigned int type, 93 unsigned int * flags, 94 vm_address_t * address, 95 vm_size_t * size ); 96 97 98extern ppnum_t IOGetLastPageNumber(void); 99 100/* 101 * Functions imported by iokit:IOUserClient.cpp 102 */ 103 104extern ipc_port_t iokit_alloc_object_port( io_object_t obj, 105 ipc_kobject_type_t type ); 106 107extern kern_return_t iokit_destroy_object_port( ipc_port_t port ); 108 109extern mach_port_name_t iokit_make_send_right( task_t task, 110 io_object_t obj, ipc_kobject_type_t type ); 111 112extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta ); 113 114extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task); 115 116extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef); 117 118extern void iokit_retain_port( ipc_port_t port ); 119extern void iokit_release_port( ipc_port_t port ); 120 121extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type ); 122 123/* 124 * Functions imported by iokit:IOMemoryDescriptor.cpp 125 */ 126 127extern kern_return_t IOMapPages(vm_map_t map, mach_vm_address_t va, mach_vm_address_t pa, 128 mach_vm_size_t length, unsigned int mapFlags); 129 130extern kern_return_t IOUnmapPages(vm_map_t map, mach_vm_address_t va, mach_vm_size_t length); 131 132extern kern_return_t IOProtectCacheMode(vm_map_t map, mach_vm_address_t va, 133 mach_vm_size_t length, unsigned int options); 134 135extern unsigned int IODefaultCacheBits(addr64_t pa); 136 137/* 138 * Lookup a device by its port. 139 * Doesn't consume the naked send right; produces a device reference. 140 */ 141MIGEXTERN io_object_t 142iokit_lookup_object_port( 143 ipc_port_t port) 144{ 145 register io_object_t obj; 146 147 if (!IP_VALID(port)) 148 return (NULL); 149 150 ip_lock(port); 151 if (ip_active(port) && (ip_kotype(port) == IKOT_IOKIT_OBJECT)) { 152 obj = (io_object_t) port->ip_kobject; 153 iokit_add_reference( obj ); 154 } 155 else 156 obj = NULL; 157 158 ip_unlock(port); 159 160 return( obj ); 161} 162 163MIGEXTERN io_object_t 164iokit_lookup_connect_port( 165 ipc_port_t port) 166{ 167 register io_object_t obj; 168 169 if (!IP_VALID(port)) 170 return (NULL); 171 172 ip_lock(port); 173 if (ip_active(port) && (ip_kotype(port) == IKOT_IOKIT_CONNECT)) { 174 obj = (io_object_t) port->ip_kobject; 175 iokit_add_reference( obj ); 176 } 177 else 178 obj = NULL; 179 180 ip_unlock(port); 181 182 return( obj ); 183} 184 185EXTERN io_object_t 186iokit_lookup_connect_ref(io_object_t connectRef, ipc_space_t space) 187{ 188 io_object_t obj = NULL; 189 190 if (connectRef && MACH_PORT_VALID((mach_port_name_t)connectRef)) { 191 ipc_port_t port; 192 kern_return_t kr; 193 194 kr = ipc_object_translate(space, (mach_port_name_t)connectRef, MACH_PORT_RIGHT_SEND, (ipc_object_t *)&port); 195 196 if (kr == KERN_SUCCESS) { 197 assert(IP_VALID(port)); 198 199 if (ip_active(port) && (ip_kotype(port) == IKOT_IOKIT_CONNECT)) { 200 obj = (io_object_t) port->ip_kobject; 201 iokit_add_reference(obj); 202 } 203 204 ip_unlock(port); 205 } 206 } 207 208 return obj; 209} 210 211EXTERN io_object_t 212iokit_lookup_connect_ref_current_task(io_object_t connectRef) 213{ 214 return iokit_lookup_connect_ref(connectRef, current_space()); 215} 216 217EXTERN void 218iokit_retain_port( ipc_port_t port ) 219{ 220 ipc_port_reference( port ); 221} 222 223EXTERN void 224iokit_release_port( ipc_port_t port ) 225{ 226 ipc_port_release( port ); 227} 228 229/* 230 * Get the port for a device. 231 * Consumes a device reference; produces a naked send right. 232 */ 233MIGEXTERN ipc_port_t 234iokit_make_object_port( 235 io_object_t obj ) 236{ 237 register ipc_port_t port; 238 register ipc_port_t sendPort; 239 240 if( obj == NULL) 241 return IP_NULL; 242 243 port = iokit_port_for_object( obj, IKOT_IOKIT_OBJECT ); 244 if( port) { 245 sendPort = ipc_port_make_send( port); 246 iokit_release_port( port ); 247 } else 248 sendPort = IP_NULL; 249 250 iokit_remove_reference( obj ); 251 252 return( sendPort); 253} 254 255MIGEXTERN ipc_port_t 256iokit_make_connect_port( 257 io_object_t obj ) 258{ 259 register ipc_port_t port; 260 register ipc_port_t sendPort; 261 262 if( obj == NULL) 263 return IP_NULL; 264 265 port = iokit_port_for_object( obj, IKOT_IOKIT_CONNECT ); 266 if( port) { 267 sendPort = ipc_port_make_send( port); 268 iokit_release_port( port ); 269 } else 270 sendPort = IP_NULL; 271 272 iokit_remove_reference( obj ); 273 274 return( sendPort); 275} 276 277int gIOKitPortCount; 278 279EXTERN ipc_port_t 280iokit_alloc_object_port( io_object_t obj, ipc_kobject_type_t type ) 281{ 282 ipc_port_t notify; 283 ipc_port_t port; 284 285 do { 286 287 /* Allocate port, keeping a reference for it. */ 288 port = ipc_port_alloc_kernel(); 289 if( port == IP_NULL) 290 continue; 291 292 /* set kobject & type */ 293// iokit_add_reference( obj ); 294 ipc_kobject_set( port, (ipc_kobject_t) obj, type); 295 296 /* Request no-senders notifications on the port. */ 297 notify = ipc_port_make_sonce( port); 298 ip_lock( port); 299 ipc_port_nsrequest( port, 1, notify, ¬ify); 300 assert( notify == IP_NULL); 301 gIOKitPortCount++; 302 303 } while( FALSE); 304 305 return( port ); 306} 307 308 309EXTERN kern_return_t 310iokit_destroy_object_port( ipc_port_t port ) 311{ 312 ipc_kobject_set( port, IKO_NULL, IKOT_NONE); 313 314// iokit_remove_reference( obj ); 315 316 ipc_port_dealloc_kernel( port); 317 gIOKitPortCount--; 318 319 return( KERN_SUCCESS); 320} 321 322EXTERN kern_return_t 323iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type ) 324{ 325 ipc_kobject_set( port, (ipc_kobject_t) obj, type); 326 327 return( KERN_SUCCESS); 328} 329 330EXTERN mach_port_name_t 331iokit_make_send_right( task_t task, io_object_t obj, ipc_kobject_type_t type ) 332{ 333 ipc_port_t port; 334 ipc_port_t sendPort; 335 mach_port_name_t name; 336 337 if( obj == NULL) 338 return MACH_PORT_NULL; 339 340 port = iokit_port_for_object( obj, type ); 341 if( port) { 342 sendPort = ipc_port_make_send( port); 343 iokit_release_port( port ); 344 } else 345 sendPort = IP_NULL; 346 347 if (IP_VALID( sendPort )) { 348 kern_return_t kr; 349 kr = ipc_object_copyout( task->itk_space, (ipc_object_t) sendPort, 350 MACH_MSG_TYPE_PORT_SEND, TRUE, &name); 351 if ( kr != KERN_SUCCESS) 352 name = MACH_PORT_NULL; 353 } else if ( sendPort == IP_NULL) 354 name = MACH_PORT_NULL; 355 else if ( sendPort == IP_DEAD) 356 name = MACH_PORT_DEAD; 357 358 iokit_remove_reference( obj ); 359 360 return( name ); 361} 362 363EXTERN kern_return_t 364iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta ) 365{ 366 return (mach_port_mod_refs( task->itk_space, name, MACH_PORT_RIGHT_SEND, delta )); 367} 368 369/* 370 * Handle the No-More_Senders notification generated from a device port destroy. 371 * Since there are no longer any tasks which hold a send right to this device 372 * port a NMS notification has been generated. 373 */ 374 375static void 376iokit_no_senders( mach_no_senders_notification_t * notification ) 377{ 378 ipc_port_t port; 379 io_object_t obj = NULL; 380 ipc_kobject_type_t type = IKOT_NONE; 381 ipc_port_t notify; 382 383 port = (ipc_port_t) notification->not_header.msgh_remote_port; 384 385 // convert a port to io_object_t. 386 if( IP_VALID(port)) { 387 ip_lock(port); 388 if( ip_active(port)) { 389 obj = (io_object_t) port->ip_kobject; 390 type = ip_kotype( port ); 391 if( (IKOT_IOKIT_OBJECT == type) 392 || (IKOT_IOKIT_CONNECT == type)) 393 iokit_add_reference( obj ); 394 else 395 obj = NULL; 396 } 397 ip_unlock(port); 398 399 if( obj ) { 400 401 mach_port_mscount_t mscount = notification->not_count; 402 403 if( KERN_SUCCESS != iokit_client_died( obj, port, type, &mscount )) 404 { 405 /* Re-request no-senders notifications on the port. */ 406 notify = ipc_port_make_sonce( port); 407 ip_lock( port); 408 ipc_port_nsrequest( port, mscount + 1, notify, ¬ify); 409 assert( notify == IP_NULL); 410 } 411 iokit_remove_reference( obj ); 412 } 413 } 414} 415 416 417EXTERN 418boolean_t 419iokit_notify( mach_msg_header_t * msg ) 420{ 421 switch (msg->msgh_id) { 422 case MACH_NOTIFY_NO_SENDERS: 423 iokit_no_senders((mach_no_senders_notification_t *) msg); 424 return TRUE; 425 426 case MACH_NOTIFY_PORT_DELETED: 427 case MACH_NOTIFY_PORT_DESTROYED: 428 case MACH_NOTIFY_SEND_ONCE: 429 case MACH_NOTIFY_DEAD_NAME: 430 default: 431 printf("iokit_notify: strange notification %d\n", msg->msgh_id); 432 return FALSE; 433 } 434} 435 436/* need to create a pmap function to generalize */ 437unsigned int IODefaultCacheBits(addr64_t pa) 438{ 439 return(pmap_cache_attributes(pa >> PAGE_SHIFT)); 440} 441 442kern_return_t IOMapPages(vm_map_t map, mach_vm_address_t va, mach_vm_address_t pa, 443 mach_vm_size_t length, unsigned int options) 444{ 445 vm_prot_t prot; 446 unsigned int flags; 447 pmap_t pmap = map->pmap; 448 449 prot = (options & kIOMapReadOnly) 450 ? VM_PROT_READ : (VM_PROT_READ|VM_PROT_WRITE); 451 452 switch(options & kIOMapCacheMask ) { /* What cache mode do we need? */ 453 454 case kIOMapDefaultCache: 455 default: 456 flags = IODefaultCacheBits(pa); 457 break; 458 459 case kIOMapInhibitCache: 460 flags = VM_WIMG_IO; 461 break; 462 463 case kIOMapWriteThruCache: 464 flags = VM_WIMG_WTHRU; 465 break; 466 467 case kIOMapWriteCombineCache: 468 flags = VM_WIMG_WCOMB; 469 break; 470 471 case kIOMapCopybackCache: 472 flags = VM_WIMG_COPYBACK; 473 break; 474 } 475 476 // Set up a block mapped area 477 pmap_map_block(pmap, va, (ppnum_t)atop_64(pa), (uint32_t) atop_64(round_page_64(length)), prot, flags, 0); 478 479 return( KERN_SUCCESS ); 480} 481 482kern_return_t IOUnmapPages(vm_map_t map, mach_vm_address_t va, mach_vm_size_t length) 483{ 484 pmap_t pmap = map->pmap; 485 486 pmap_remove(pmap, trunc_page_64(va), round_page_64(va + length)); 487 488 return( KERN_SUCCESS ); 489} 490 491kern_return_t IOProtectCacheMode(vm_map_t __unused map, mach_vm_address_t __unused va, 492 mach_vm_size_t __unused length, unsigned int __unused options) 493{ 494#if __ppc__ 495 // can't remap block mappings, but ppc doesn't speculatively read from WC 496#else 497 498 mach_vm_size_t off; 499 vm_prot_t prot; 500 unsigned int flags; 501 pmap_t pmap = map->pmap; 502 503 prot = (options & kIOMapReadOnly) 504 ? VM_PROT_READ : (VM_PROT_READ|VM_PROT_WRITE); 505 506 switch (options & kIOMapCacheMask) 507 { 508 // what cache mode do we need? 509 case kIOMapDefaultCache: 510 default: 511 return (KERN_INVALID_ARGUMENT); 512 513 case kIOMapInhibitCache: 514 flags = VM_WIMG_IO; 515 break; 516 517 case kIOMapWriteThruCache: 518 flags = VM_WIMG_WTHRU; 519 break; 520 521 case kIOMapWriteCombineCache: 522 flags = VM_WIMG_WCOMB; 523 break; 524 525 case kIOMapCopybackCache: 526 flags = VM_WIMG_COPYBACK; 527 break; 528 } 529 530 // enter each page's physical address in the target map 531 for (off = 0; off < length; off += page_size) 532 { 533 ppnum_t ppnum = pmap_find_phys(pmap, va + off); 534 if (ppnum) 535 pmap_enter(pmap, va + off, ppnum, prot, flags, TRUE); 536 } 537 538#endif 539 540 return (KERN_SUCCESS); 541} 542 543ppnum_t IOGetLastPageNumber(void) 544{ 545 ppnum_t lastPage, highest = 0; 546 unsigned int idx; 547 548#if __ppc__ 549 for (idx = 0; idx < pmap_mem_regions_count; idx++) 550 { 551 lastPage = pmap_mem_regions[idx].mrEnd; 552#elif __i386__ 553 for (idx = 0; idx < pmap_memory_region_count; idx++) 554 { 555 lastPage = pmap_memory_regions[idx].end - 1; 556#else 557#error arch 558#endif 559 if (lastPage > highest) 560 highest = lastPage; 561 } 562 return (highest); 563} 564 565 566void IOGetTime( mach_timespec_t * clock_time); 567void IOGetTime( mach_timespec_t * clock_time) 568{ 569 clock_get_system_nanotime(&clock_time->tv_sec, (uint32_t *) &clock_time->tv_nsec); 570} 571 572