]> git.saurik.com Git - apple/xnu.git/blame - osfmk/device/iokit_rpc.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / osfmk / device / iokit_rpc.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
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>
1c79356b
A
42#include <kern/counters.h>
43#include <kern/queue.h>
44#include <kern/zalloc.h>
45#include <kern/thread.h>
1c79356b
A
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
1c79356b
A
58#include <machine/machparam.h>
59
60#ifdef __ppc__
61#include <ppc/mappings.h>
1c79356b 62#endif
91447636
A
63#ifdef __i386
64#include <i386/pmap.h>
65#endif
1c79356b
A
66#include <IOKit/IOTypes.h>
67
68#define EXTERN
69#define MIGEXTERN
70
71/*
72 * Functions in iokit:IOUserClient.cpp
73 */
74
75extern void iokit_add_reference( io_object_t obj );
76
1c79356b
A
77extern ipc_port_t iokit_port_for_object( io_object_t obj,
78 ipc_kobject_type_t type );
79
80extern kern_return_t iokit_client_died( io_object_t obj,
55e303ae 81 ipc_port_t port, ipc_kobject_type_t type, mach_port_mscount_t * mscount );
1c79356b
A
82
83extern kern_return_t
84iokit_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
c0fea474
A
91
92extern ppnum_t IOGetLastPageNumber(void);
93
1c79356b
A
94/*
95 * Lookup a device by its port.
96 * Doesn't consume the naked send right; produces a device reference.
97 */
98MIGEXTERN io_object_t
99iokit_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
120MIGEXTERN io_object_t
121iokit_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
142EXTERN io_object_t
143iokit_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
168EXTERN io_object_t
169iokit_lookup_connect_ref_current_task(io_object_t connectRef)
170{
171 return iokit_lookup_connect_ref(connectRef, current_space());
172}
173
9bccf70c
A
174EXTERN void
175iokit_retain_port( ipc_port_t port )
176{
177 ipc_port_reference( port );
178}
179
180EXTERN void
181iokit_release_port( ipc_port_t port )
182{
183 ipc_port_release( port );
184}
185
1c79356b
A
186/*
187 * Get the port for a device.
188 * Consumes a device reference; produces a naked send right.
189 */
190MIGEXTERN ipc_port_t
191iokit_make_object_port(
192 io_object_t obj )
193{
194 register ipc_port_t port;
9bccf70c 195 register ipc_port_t sendPort;
1c79356b
A
196
197 if( obj == NULL)
198 return IP_NULL;
199
200 port = iokit_port_for_object( obj, IKOT_IOKIT_OBJECT );
9bccf70c
A
201 if( port) {
202 sendPort = ipc_port_make_send( port);
203 iokit_release_port( port );
204 } else
205 sendPort = IP_NULL;
1c79356b
A
206
207 iokit_remove_reference( obj );
208
9bccf70c 209 return( sendPort);
1c79356b
A
210}
211
212MIGEXTERN ipc_port_t
213iokit_make_connect_port(
214 io_object_t obj )
215{
216 register ipc_port_t port;
9bccf70c 217 register ipc_port_t sendPort;
1c79356b
A
218
219 if( obj == NULL)
220 return IP_NULL;
221
222 port = iokit_port_for_object( obj, IKOT_IOKIT_CONNECT );
9bccf70c
A
223 if( port) {
224 sendPort = ipc_port_make_send( port);
225 iokit_release_port( port );
226 } else
227 sendPort = IP_NULL;
1c79356b
A
228
229 iokit_remove_reference( obj );
230
9bccf70c 231 return( sendPort);
1c79356b
A
232}
233
234
235EXTERN ipc_port_t
236iokit_alloc_object_port( io_object_t obj, ipc_kobject_type_t type );
237
238int gIOKitPortCount;
239
240EXTERN ipc_port_t
241iokit_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
270EXTERN kern_return_t
271iokit_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
43866e37
A
283EXTERN kern_return_t
284iokit_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
1c79356b
A
291EXTERN mach_port_name_t
292iokit_make_send_right( task_t task, io_object_t obj, ipc_kobject_type_t type )
293{
1c79356b 294 ipc_port_t port;
9bccf70c 295 ipc_port_t sendPort;
1c79356b
A
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 );
9bccf70c
A
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,
1c79356b 311 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
9bccf70c
A
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;
1c79356b
A
318
319 iokit_remove_reference( obj );
320
321 return( name );
322}
323
91447636
A
324EXTERN kern_return_t
325iokit_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
1c79356b
A
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
336static void
337iokit_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;
9bccf70c 342 ipc_port_t notify;
1c79356b
A
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 );
e3027f41 355 else
1c79356b
A
356 obj = NULL;
357 }
358 ip_unlock(port);
359
360 if( obj ) {
9bccf70c
A
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 }
1c79356b
A
372 iokit_remove_reference( obj );
373 }
374 }
375}
376
377
378EXTERN
379boolean_t
380iokit_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
55e303ae
A
397/* need to create a pmap function to generalize */
398unsigned int IODefaultCacheBits(addr64_t pa)
de355530 399{
9bccf70c 400
c0fea474 401 return(pmap_cache_attributes(pa >> PAGE_SHIFT));
9bccf70c 402}
9bccf70c 403
c0fea474
A
404kern_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)
1c79356b 406{
1c79356b 407 vm_prot_t prot;
55e303ae
A
408 unsigned int flags;
409 pmap_t pmap = map->pmap;
1c79356b
A
410
411 prot = (options & kIOMapReadOnly)
412 ? VM_PROT_READ : (VM_PROT_READ|VM_PROT_WRITE);
413
55e303ae
A
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
c0fea474 429 case kIOMapWriteCombineCache:
55e303ae
A
430 flags = VM_WIMG_WCOMB;
431 break;
432
433 case kIOMapCopybackCache:
434 flags = VM_WIMG_COPYBACK;
435 break;
436 }
1c79356b 437
55e303ae 438 // Set up a block mapped area
c0fea474
A
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
444kern_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
453kern_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;
1c79356b 478
c0fea474
A
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
1c79356b 489#else
55e303ae 490
c0fea474 491 // enter each page's physical address in the target map
55e303ae 492 for (off = 0; off < length; off += page_size)
c0fea474
A
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 }
55e303ae 498
1c79356b
A
499#endif
500
c0fea474 501 return (KERN_SUCCESS);
1c79356b
A
502}
503
c0fea474 504ppnum_t IOGetLastPageNumber(void)
e3027f41 505{
c0fea474 506 ppnum_t lastPage, highest = 0;
e3027f41 507
c0fea474
A
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);
e3027f41
A
525}
526
c0fea474 527
1c79356b
A
528void IOGetTime( mach_timespec_t * clock_time);
529void IOGetTime( mach_timespec_t * clock_time)
530{
55e303ae 531 clock_get_system_nanotime(&clock_time->tv_sec, &clock_time->tv_nsec);
1c79356b 532}
c0fea474 533