]> git.saurik.com Git - apple/xnu.git/blame - osfmk/device/iokit_rpc.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / device / iokit_rpc.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
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 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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
28#include <mach/boolean.h>
29#include <mach/kern_return.h>
30#include <mach/mig_errors.h>
31#include <mach/port.h>
32#include <mach/vm_param.h>
33#include <mach/notify.h>
2d21ac55 34//#include <mach/mach_host_server.h>
1c79356b
A
35#include <mach/mach_types.h>
36
0a7de745 37#include <machine/machparam.h> /* spl definitions */
1c79356b
A
38
39#include <ipc/ipc_port.h>
40#include <ipc/ipc_space.h>
41
42#include <kern/clock.h>
43#include <kern/spl.h>
1c79356b
A
44#include <kern/queue.h>
45#include <kern/zalloc.h>
46#include <kern/thread.h>
1c79356b
A
47#include <kern/task.h>
48#include <kern/sched_prim.h>
49#include <kern/misc_protos.h>
50
51#include <vm/pmap.h>
52#include <vm/vm_map.h>
53#include <vm/vm_kern.h>
54
55#include <device/device_types.h>
56#include <device/device_port.h>
57#include <device/device_server.h>
58
1c79356b
A
59#include <machine/machparam.h>
60
b0d623f7 61#if defined(__i386__) || defined(__x86_64__)
91447636
A
62#include <i386/pmap.h>
63#endif
5ba3f43e
A
64#if defined(__arm__) || defined(__arm64__)
65#include <arm/pmap.h>
66#endif
a39ff7e2 67#include <IOKit/IOKitServer.h>
1c79356b
A
68
69#define EXTERN
70#define MIGEXTERN
71
f427ee49
A
72LCK_GRP_DECLARE(dev_lck_grp, "device");
73LCK_MTX_DECLARE(iokit_obj_to_port_binding_lock, &dev_lck_grp);
74
1c79356b
A
75/*
76 * Lookup a device by its port.
77 * Doesn't consume the naked send right; produces a device reference.
78 */
cb323159 79io_object_t
a39ff7e2 80iokit_lookup_io_object(ipc_port_t port, ipc_kobject_type_t type)
1c79356b 81{
0a7de745 82 io_object_t obj;
1c79356b 83
0a7de745
A
84 if (!IP_VALID(port)) {
85 return NULL;
86 }
1c79356b 87
316670eb 88 iokit_lock_port(port);
a39ff7e2 89 if (ip_active(port) && (ip_kotype(port) == type)) {
ea3f0419 90 obj = (io_object_t) ip_get_kobject(port);
0a7de745
A
91 iokit_add_reference( obj, type );
92 } else {
93 obj = NULL;
1c79356b 94 }
1c79356b 95
316670eb 96 iokit_unlock_port(port);
1c79356b 97
0a7de745 98 return obj;
1c79356b
A
99}
100
101MIGEXTERN io_object_t
a39ff7e2 102iokit_lookup_object_port(
0a7de745 103 ipc_port_t port)
1c79356b 104{
0a7de745 105 return iokit_lookup_io_object(port, IKOT_IOKIT_OBJECT);
a39ff7e2 106}
1c79356b 107
a39ff7e2
A
108MIGEXTERN io_object_t
109iokit_lookup_connect_port(
0a7de745 110 ipc_port_t port)
a39ff7e2 111{
0a7de745 112 return iokit_lookup_io_object(port, IKOT_IOKIT_CONNECT);
1c79356b
A
113}
114
cb323159
A
115MIGEXTERN io_object_t
116iokit_lookup_uext_object_port(
117 ipc_port_t port)
118{
119 return iokit_lookup_io_object(port, IKOT_UEXT_OBJECT);
120}
121
a39ff7e2
A
122static io_object_t
123iokit_lookup_object_in_space_with_port_name(mach_port_name_t name, ipc_kobject_type_t type, ipc_space_t space)
1c79356b
A
124{
125 io_object_t obj = NULL;
126
a39ff7e2 127 if (name && MACH_PORT_VALID(name)) {
1c79356b
A
128 ipc_port_t port;
129 kern_return_t kr;
130
cb323159 131 kr = ipc_port_translate_send(space, name, &port);
1c79356b
A
132
133 if (kr == KERN_SUCCESS) {
316670eb 134 assert(IP_VALID(port));
cb323159 135 require_ip_active(port);
316670eb
A
136 ip_reference(port);
137 ip_unlock(port);
138
139 iokit_lock_port(port);
cb323159 140 if (ip_kotype(port) == type) {
ea3f0419 141 obj = (io_object_t) ip_get_kobject(port);
a39ff7e2 142 iokit_add_reference(obj, type);
316670eb
A
143 }
144 iokit_unlock_port(port);
145
146 ip_release(port);
1c79356b
A
147 }
148 }
149
150 return obj;
151}
152
153EXTERN io_object_t
a39ff7e2 154iokit_lookup_object_with_port_name(mach_port_name_t name, ipc_kobject_type_t type, task_t task)
1c79356b 155{
0a7de745 156 return iokit_lookup_object_in_space_with_port_name(name, type, task->itk_space);
a39ff7e2
A
157}
158
159EXTERN io_object_t
160iokit_lookup_connect_ref_current_task(mach_port_name_t name)
161{
0a7de745 162 return iokit_lookup_object_in_space_with_port_name(name, IKOT_IOKIT_CONNECT, current_space());
1c79356b
A
163}
164
cb323159
A
165EXTERN io_object_t
166iokit_lookup_uext_ref_current_task(mach_port_name_t name)
167{
168 return iokit_lookup_object_in_space_with_port_name(name, IKOT_UEXT_OBJECT, current_space());
169}
170
9bccf70c
A
171EXTERN void
172iokit_retain_port( ipc_port_t port )
173{
0a7de745 174 ipc_port_reference( port );
9bccf70c
A
175}
176
177EXTERN void
178iokit_release_port( ipc_port_t port )
179{
0a7de745 180 ipc_port_release( port );
9bccf70c
A
181}
182
c3c9b80d
A
183EXTERN void
184iokit_make_port_send( ipc_port_t port )
185{
186 ipc_port_make_send( port );
187}
188
b0d623f7
A
189EXTERN void
190iokit_release_port_send( ipc_port_t port )
191{
0a7de745 192 ipc_port_release_send( port );
b0d623f7
A
193}
194
316670eb
A
195EXTERN void
196iokit_lock_port( __unused ipc_port_t port )
197{
0a7de745 198 lck_mtx_lock(&iokit_obj_to_port_binding_lock);
316670eb
A
199}
200
201EXTERN void
202iokit_unlock_port( __unused ipc_port_t port )
203{
0a7de745 204 lck_mtx_unlock(&iokit_obj_to_port_binding_lock);
316670eb
A
205}
206
1c79356b
A
207/*
208 * Get the port for a device.
209 * Consumes a device reference; produces a naked send right.
210 */
a39ff7e2
A
211
212static ipc_port_t
213iokit_make_port_of_type(io_object_t obj, ipc_kobject_type_t type)
1c79356b 214{
0a7de745
A
215 ipc_port_t port;
216 ipc_port_t sendPort;
1c79356b 217
0a7de745
A
218 if (obj == NULL) {
219 return IP_NULL;
220 }
1c79356b 221
0a7de745
A
222 port = iokit_port_for_object( obj, type );
223 if (port) {
224 sendPort = ipc_port_make_send( port);
225 iokit_release_port( port );
226 } else {
227 sendPort = IP_NULL;
228 }
1c79356b 229
0a7de745 230 iokit_remove_reference( obj );
1c79356b 231
0a7de745 232 return sendPort;
1c79356b
A
233}
234
235MIGEXTERN ipc_port_t
a39ff7e2 236iokit_make_object_port(
0a7de745 237 io_object_t obj )
1c79356b 238{
0a7de745 239 return iokit_make_port_of_type(obj, IKOT_IOKIT_OBJECT);
a39ff7e2 240}
1c79356b 241
a39ff7e2
A
242MIGEXTERN ipc_port_t
243iokit_make_connect_port(
0a7de745 244 io_object_t obj )
a39ff7e2 245{
0a7de745 246 return iokit_make_port_of_type(obj, IKOT_IOKIT_CONNECT);
1c79356b
A
247}
248
1c79356b
A
249int gIOKitPortCount;
250
251EXTERN ipc_port_t
252iokit_alloc_object_port( io_object_t obj, ipc_kobject_type_t type )
253{
cb323159
A
254 /* Allocate port, keeping a reference for it. */
255 gIOKitPortCount++;
256 ipc_kobject_alloc_options_t options = IPC_KOBJECT_ALLOC_NSREQUEST;
257 if (type == IKOT_IOKIT_CONNECT) {
258 options |= IPC_KOBJECT_ALLOC_IMMOVABLE_SEND;
259 }
ea3f0419
A
260 if (type == IKOT_UEXT_OBJECT) {
261 ipc_label_t label = IPC_LABEL_DEXT;
262 return ipc_kobject_alloc_labeled_port((ipc_kobject_t) obj, type, label, options);
263 } else {
264 return ipc_kobject_alloc_port((ipc_kobject_t) obj, type, options);
265 }
1c79356b
A
266}
267
1c79356b
A
268EXTERN kern_return_t
269iokit_destroy_object_port( ipc_port_t port )
270{
0a7de745
A
271 iokit_lock_port(port);
272 ipc_kobject_set( port, IKO_NULL, IKOT_NONE);
1c79356b
A
273
274// iokit_remove_reference( obj );
0a7de745
A
275 iokit_unlock_port(port);
276 ipc_port_dealloc_kernel( port);
277 gIOKitPortCount--;
1c79356b 278
0a7de745 279 return KERN_SUCCESS;
1c79356b
A
280}
281
43866e37
A
282EXTERN kern_return_t
283iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type )
284{
0a7de745
A
285 iokit_lock_port(port);
286 ipc_kobject_set( port, (ipc_kobject_t) obj, type);
287 iokit_unlock_port(port);
43866e37 288
0a7de745 289 return KERN_SUCCESS;
43866e37
A
290}
291
1c79356b
A
292EXTERN mach_port_name_t
293iokit_make_send_right( task_t task, io_object_t obj, ipc_kobject_type_t type )
294{
0a7de745
A
295 ipc_port_t port;
296 ipc_port_t sendPort;
297 mach_port_name_t name = 0;
298
299 if (obj == NULL) {
300 return MACH_PORT_NULL;
39236c6e 301 }
1c79356b 302
0a7de745
A
303 port = iokit_port_for_object( obj, type );
304 if (port) {
305 sendPort = ipc_port_make_send( port);
306 iokit_release_port( port );
307 } else {
308 sendPort = IP_NULL;
309 }
310
311 if (IP_VALID( sendPort )) {
312 kern_return_t kr;
cb323159
A
313 // Remove once <rdar://problem/45522961> is fixed.
314 // We need to make ith_knote NULL as ipc_object_copyout() uses
315 // thread-argument-passing and its value should not be garbage
316 current_thread()->ith_knote = ITH_KNOTE_NULL;
317 kr = ipc_object_copyout( task->itk_space, ip_to_object(sendPort),
c3c9b80d 318 MACH_MSG_TYPE_PORT_SEND, IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, &name);
0a7de745 319 if (kr != KERN_SUCCESS) {
0a7de745
A
320 name = MACH_PORT_NULL;
321 }
322 } else if (sendPort == IP_NULL) {
323 name = MACH_PORT_NULL;
324 } else if (sendPort == IP_DEAD) {
325 name = MACH_PORT_DEAD;
326 }
327
328 return name;
1c79356b
A
329}
330
91447636
A
331EXTERN kern_return_t
332iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta )
333{
0a7de745 334 return mach_port_mod_refs( task->itk_space, name, MACH_PORT_RIGHT_SEND, delta );
91447636
A
335}
336
1c79356b
A
337/*
338 * Handle the No-More_Senders notification generated from a device port destroy.
339 * Since there are no longer any tasks which hold a send right to this device
0a7de745 340 * port a NMS notification has been generated.
1c79356b
A
341 */
342
343static void
344iokit_no_senders( mach_no_senders_notification_t * notification )
345{
0a7de745
A
346 ipc_port_t port;
347 io_object_t obj = NULL;
348 ipc_kobject_type_t type = IKOT_NONE;
349 ipc_port_t notify;
1c79356b 350
cb323159 351 port = notification->not_header.msgh_remote_port;
9bccf70c 352
0a7de745
A
353 // convert a port to io_object_t.
354 if (IP_VALID(port)) {
355 iokit_lock_port(port);
316670eb 356 if (ip_active(port)) {
ea3f0419 357 obj = (io_object_t) ip_get_kobject(port);
0a7de745
A
358 type = ip_kotype( port );
359 if ((IKOT_IOKIT_OBJECT == type)
360 || (IKOT_IOKIT_CONNECT == type)
cb323159
A
361 || (IKOT_IOKIT_IDENT == type)
362 || (IKOT_UEXT_OBJECT == type)) {
0a7de745
A
363 iokit_add_reference( obj, IKOT_IOKIT_OBJECT );
364 } else {
365 obj = NULL;
366 }
316670eb 367 }
0a7de745
A
368 iokit_unlock_port(port);
369
370 if (obj) {
371 mach_port_mscount_t mscount = notification->not_count;
372
373 if (KERN_SUCCESS != iokit_client_died( obj, port, type, &mscount )) {
374 /* Re-request no-senders notifications on the port (if still active) */
375 ip_lock(port);
376 if (ip_active(port)) {
377 notify = ipc_port_make_sonce_locked(port);
378 ipc_port_nsrequest( port, mscount + 1, notify, &notify);
379 /* port unlocked */
380 if (notify != IP_NULL) {
381 ipc_port_release_sonce(notify);
382 }
383 } else {
384 ip_unlock(port);
385 }
386 }
387 iokit_remove_reference( obj );
388 }
389 }
1c79356b
A
390}
391
392
393EXTERN
394boolean_t
395iokit_notify( mach_msg_header_t * msg )
396{
0a7de745
A
397 switch (msg->msgh_id) {
398 case MACH_NOTIFY_NO_SENDERS:
399 iokit_no_senders((mach_no_senders_notification_t *) msg);
400 return TRUE;
401
402 case MACH_NOTIFY_PORT_DELETED:
403 case MACH_NOTIFY_PORT_DESTROYED:
404 case MACH_NOTIFY_SEND_ONCE:
405 case MACH_NOTIFY_DEAD_NAME:
406 default:
407 printf("iokit_notify: strange notification %d\n", msg->msgh_id);
408 return FALSE;
409 }
1c79356b
A
410}
411
ea3f0419
A
412kern_return_t
413iokit_label_dext_task(task_t task)
414{
415 return ipc_space_add_label(task->itk_space, IPC_LABEL_DEXT);
416}
417
55e303ae 418/* need to create a pmap function to generalize */
0a7de745
A
419unsigned int
420IODefaultCacheBits(addr64_t pa)
de355530 421{
0a7de745 422 return pmap_cache_attributes((ppnum_t)(pa >> PAGE_SHIFT));
9bccf70c 423}
9bccf70c 424
0a7de745
A
425kern_return_t
426IOMapPages(vm_map_t map, mach_vm_address_t va, mach_vm_address_t pa,
427 mach_vm_size_t length, unsigned int options)
1c79356b 428{
0a7de745
A
429 vm_prot_t prot;
430 unsigned int flags;
431 ppnum_t pagenum;
432 pmap_t pmap = map->pmap;
1c79356b 433
0a7de745
A
434 prot = (options & kIOMapReadOnly)
435 ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_WRITE);
1c79356b 436
0a7de745 437 pagenum = (ppnum_t)atop_64(pa);
55e303ae 438
0a7de745 439 switch (options & kIOMapCacheMask) { /* What cache mode do we need? */
55e303ae
A
440 case kIOMapDefaultCache:
441 default:
0a7de745
A
442 flags = IODefaultCacheBits(pa);
443 break;
55e303ae
A
444
445 case kIOMapInhibitCache:
0a7de745
A
446 flags = VM_WIMG_IO;
447 break;
55e303ae
A
448
449 case kIOMapWriteThruCache:
0a7de745
A
450 flags = VM_WIMG_WTHRU;
451 break;
55e303ae 452
0c530ab8 453 case kIOMapWriteCombineCache:
0a7de745
A
454 flags = VM_WIMG_WCOMB;
455 break;
55e303ae
A
456
457 case kIOMapCopybackCache:
0a7de745
A
458 flags = VM_WIMG_COPYBACK;
459 break;
5ba3f43e 460
316670eb 461 case kIOMapCopybackInnerCache:
0a7de745
A
462 flags = VM_WIMG_INNERWBACK;
463 break;
5ba3f43e
A
464
465 case kIOMapPostedWrite:
0a7de745
A
466 flags = VM_WIMG_POSTED;
467 break;
cb323159
A
468
469 case kIOMapRealTimeCache:
470 flags = VM_WIMG_RT;
471 break;
0a7de745 472 }
1c79356b 473
0a7de745 474 pmap_set_cache_attributes(pagenum, flags);
6d2010ae 475
0a7de745 476 vm_map_set_cache_attr(map, (vm_map_offset_t)va);
6d2010ae
A
477
478
0a7de745
A
479 // Set up a block mapped area
480 return pmap_map_block(pmap, va, pagenum, (uint32_t) atop_64(round_page_64(length)), prot, 0, 0);
0c530ab8
A
481}
482
0a7de745
A
483kern_return_t
484IOUnmapPages(vm_map_t map, mach_vm_address_t va, mach_vm_size_t length)
0c530ab8 485{
0a7de745 486 pmap_t pmap = map->pmap;
0c530ab8 487
0a7de745 488 pmap_remove(pmap, trunc_page_64(va), round_page_64(va + length));
0c530ab8 489
0a7de745 490 return KERN_SUCCESS;
0c530ab8
A
491}
492
0a7de745
A
493kern_return_t
494IOProtectCacheMode(vm_map_t __unused map, mach_vm_address_t __unused va,
495 mach_vm_size_t __unused length, unsigned int __unused options)
0c530ab8 496{
0a7de745
A
497 mach_vm_size_t off;
498 vm_prot_t prot;
499 unsigned int flags;
500 pmap_t pmap = map->pmap;
501 pmap_flush_context pmap_flush_context_storage;
502 boolean_t delayed_pmap_flush = FALSE;
503
504 prot = (options & kIOMapReadOnly)
505 ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_WRITE);
506
507 switch (options & kIOMapCacheMask) {
2d21ac55 508 // what cache mode do we need?
0c530ab8
A
509 case kIOMapDefaultCache:
510 default:
0a7de745 511 return KERN_INVALID_ARGUMENT;
0c530ab8
A
512
513 case kIOMapInhibitCache:
0a7de745
A
514 flags = VM_WIMG_IO;
515 break;
0c530ab8
A
516
517 case kIOMapWriteThruCache:
0a7de745
A
518 flags = VM_WIMG_WTHRU;
519 break;
4452a7af 520
0c530ab8 521 case kIOMapWriteCombineCache:
0a7de745
A
522 flags = VM_WIMG_WCOMB;
523 break;
0c530ab8
A
524
525 case kIOMapCopybackCache:
0a7de745
A
526 flags = VM_WIMG_COPYBACK;
527 break;
5ba3f43e
A
528
529 case kIOMapCopybackInnerCache:
0a7de745
A
530 flags = VM_WIMG_INNERWBACK;
531 break;
5ba3f43e
A
532
533 case kIOMapPostedWrite:
0a7de745
A
534 flags = VM_WIMG_POSTED;
535 break;
cb323159
A
536
537 case kIOMapRealTimeCache:
538 flags = VM_WIMG_RT;
539 break;
39236c6e 540 }
55e303ae 541
0a7de745
A
542 pmap_flush_context_init(&pmap_flush_context_storage);
543 delayed_pmap_flush = FALSE;
544
545 // enter each page's physical address in the target map
546 for (off = 0; off < length; off += page_size) {
547 ppnum_t ppnum = pmap_find_phys(pmap, va + off);
548 if (ppnum) {
549 pmap_enter_options(pmap, va + off, ppnum, prot, VM_PROT_NONE, flags, TRUE,
550 PMAP_OPTIONS_NOFLUSH, (void *)&pmap_flush_context_storage);
551 delayed_pmap_flush = TRUE;
552 }
553 }
554 if (delayed_pmap_flush == TRUE) {
555 pmap_flush(&pmap_flush_context_storage);
556 }
557
558 return KERN_SUCCESS;
1c79356b
A
559}
560
0a7de745
A
561ppnum_t
562IOGetLastPageNumber(void)
e3027f41 563{
6d2010ae 564#if __i386__ || __x86_64__
0a7de745 565 ppnum_t lastPage, highest = 0;
6d2010ae
A
566 unsigned int idx;
567
0a7de745 568 for (idx = 0; idx < pmap_memory_region_count; idx++) {
6d2010ae 569 lastPage = pmap_memory_regions[idx].end - 1;
0a7de745 570 if (lastPage > highest) {
6d2010ae 571 highest = lastPage;
0a7de745 572 }
6d2010ae 573 }
0a7de745 574 return highest;
5ba3f43e
A
575#elif __arm__ || __arm64__
576 return 0;
0c530ab8 577#else
6d2010ae 578#error unknown arch
0c530ab8 579#endif
6601e61a 580}
4452a7af 581
0c530ab8 582
1c79356b 583void IOGetTime( mach_timespec_t * clock_time);
0a7de745
A
584void
585IOGetTime( mach_timespec_t * clock_time)
1c79356b 586{
b0d623f7
A
587 clock_sec_t sec;
588 clock_nsec_t nsec;
589 clock_get_system_nanotime(&sec, &nsec);
590 clock_time->tv_sec = (typeof(clock_time->tv_sec))sec;
591 clock_time->tv_nsec = nsec;
1c79356b 592}