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