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