X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/de355530ae67247cbd0da700edb3a2a1dae884c2..d1ecb069dfe24481e4a83f44cb5217a2b06746d7:/iokit/Kernel/IOUserClient.cpp diff --git a/iokit/Kernel/IOUserClient.cpp b/iokit/Kernel/IOUserClient.cpp index 06f700f5b..084471c3c 100644 --- a/iokit/Kernel/IOUserClient.cpp +++ b/iokit/Kernel/IOUserClient.cpp @@ -1,43 +1,62 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. - * - * HISTORY - * - * 14 Aug 98 sdouglas created. - * 08 Dec 98 sdouglas cpp. + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ + +#include #include +#include #include #include #include #include #include +#include #include +#include +#include #include +#include "IOServicePrivate.h" +#include "IOKitKernelInternal.h" + +#define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x)) +#define SCALAR32(x) ((uint32_t )x) +#define ARG32(x) ((void *)SCALAR32(x)) +#define REF64(x) ((io_user_reference_t)((UInt64)(x))) +#define REF32(x) ((int)(x)) + +enum +{ + kIOUCAsync0Flags = 3ULL, + kIOUCAsync64Flag = 1ULL +}; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // definitions we should get from osfmk @@ -59,6 +78,8 @@ extern kern_return_t iokit_destroy_object_port( ipc_port_t port ); extern mach_port_name_t iokit_make_send_right( task_t task, io_object_t obj, ipc_kobject_type_t type ); +extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta ); + extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task); extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef); @@ -67,7 +88,11 @@ extern ipc_port_t master_device_port; extern void iokit_retain_port( ipc_port_t port ); extern void iokit_release_port( ipc_port_t port ); +extern void iokit_release_port_send( ipc_port_t port ); +extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type ); + +#include #include } /* extern "C" */ @@ -84,6 +109,7 @@ public: OSObject * object; ipc_port_t port; UInt32 mscount; + UInt8 holdDestroy; static IOMachPort * portForObject( OSObject * obj, ipc_kobject_type_t type ); @@ -91,6 +117,8 @@ public: ipc_kobject_type_t type, mach_port_mscount_t * mscount ); static void releasePortForObject( OSObject * obj, ipc_kobject_type_t type ); + static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type ); + static OSDictionary * dictForType( ipc_kobject_type_t type ); static mach_port_name_t makeSendRightForTask( task_t task, @@ -186,12 +214,12 @@ bool IOMachPort::noMoreSendersForObject( OSObject * obj, machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); if( machPort) { - destroyed = (machPort->mscount == *mscount); + destroyed = (machPort->mscount <= *mscount); if( destroyed) dict->removeObject( (const OSSymbol *) obj ); else *mscount = machPort->mscount; - } + } obj->release(); } @@ -204,22 +232,69 @@ void IOMachPort::releasePortForObject( OSObject * obj, ipc_kobject_type_t type ) { OSDictionary * dict; + IOMachPort * machPort; IOTakeLock( gIOObjectPortLock); if( (dict = dictForType( type ))) { obj->retain(); - dict->removeObject( (const OSSymbol *) obj ); + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort && !machPort->holdDestroy) + dict->removeObject( (const OSSymbol *) obj ); obj->release(); } IOUnlock( gIOObjectPortLock); } +void IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type ) +{ + OSDictionary * dict; + IOMachPort * machPort; + + IOLockLock( gIOObjectPortLock ); + + if( (dict = dictForType( type ))) { + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort) + machPort->holdDestroy = true; + } + + IOLockUnlock( gIOObjectPortLock ); +} + void IOUserClient::destroyUserReferences( OSObject * obj ) { IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT ); - IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT ); + + // panther, 3160200 + // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT ); + + OSDictionary * dict; + + IOTakeLock( gIOObjectPortLock); + obj->retain(); + + if( (dict = IOMachPort::dictForType( IKOT_IOKIT_CONNECT ))) + { + IOMachPort * port; + port = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if (port) + { + IOUserClient * uc; + if ((uc = OSDynamicCast(IOUserClient, obj)) && uc->mappings) + { + dict->setObject((const OSSymbol *) uc->mappings, port); + iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT); + + uc->mappings->release(); + uc->mappings = 0; + } + dict->removeObject( (const OSSymbol *) obj ); + } + } + obj->release(); + IOUnlock( gIOObjectPortLock); } mach_port_name_t IOMachPort::makeSendRightForTask( task_t task, @@ -237,6 +312,26 @@ void IOMachPort::free( void ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +class IOUserNotification : public OSIterator +{ + OSDeclareDefaultStructors(IOUserNotification) + + IONotifier * holdNotify; + IOLock * lock; + +public: + + virtual bool init( void ); + virtual void free(); + + virtual void setNotification( IONotifier * obj ); + + virtual void reset(); + virtual bool isValid(); +}; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + extern "C" { // functions called from osfmk/device/iokit_rpc.c @@ -281,16 +376,23 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */, { IOUserClient * client; IOMemoryMap * map; + IOUserNotification * notify; if( !IOMachPort::noMoreSendersForObject( obj, type, mscount )) return( kIOReturnNotReady ); - if( (IKOT_IOKIT_CONNECT == type) - && (client = OSDynamicCast( IOUserClient, obj ))) - client->clientDied(); - else if( (IKOT_IOKIT_OBJECT == type) - && (map = OSDynamicCast( IOMemoryMap, obj ))) - map->taskDied(); + if( IKOT_IOKIT_CONNECT == type) + { + if( (client = OSDynamicCast( IOUserClient, obj ))) + client->clientDied(); + } + else if( IKOT_IOKIT_OBJECT == type) + { + if( (map = OSDynamicCast( IOMemoryMap, obj ))) + map->taskDied(); + else if( (notify = OSDynamicCast( IOUserNotification, obj ))) + notify->setNotification( 0 ); + } return( kIOReturnSuccess ); } @@ -299,39 +401,19 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -class IOUserNotification : public OSIterator +class IOServiceUserNotification : public IOUserNotification { - OSDeclareDefaultStructors(IOUserNotification) + OSDeclareDefaultStructors(IOServiceUserNotification) struct PingMsg { - mach_msg_header_t msgHdr; - OSNotificationHeader notifyHeader; + mach_msg_header_t msgHdr; + OSNotificationHeader64 notifyHeader; }; - PingMsg * pingMsg; - vm_size_t msgSize; - IONotifier * holdNotify; - IOLock * lock; - -public: - - virtual bool init( mach_port_t port, natural_t type, - OSAsyncReference reference, - vm_size_t messageSize ); - virtual void free(); - - virtual void setNotification( IONotifier * obj ); - - virtual void reset(); - virtual bool isValid(); -}; - -class IOServiceUserNotification : public IOUserNotification -{ - OSDeclareDefaultStructors(IOServiceUserNotification) - - enum { kMaxOutstanding = 256 }; + enum { kMaxOutstanding = 1024 }; + PingMsg * pingMsg; + vm_size_t msgSize; OSArray * newSet; OSObject * lastEntry; bool armed; @@ -339,11 +421,12 @@ class IOServiceUserNotification : public IOUserNotification public: virtual bool init( mach_port_t port, natural_t type, - OSAsyncReference reference ); + void * reference, vm_size_t referenceSize, + bool clientIs64 ); virtual void free(); static bool _handler( void * target, - void * ref, IOService * newService ); + void * ref, IOService * newService, IONotifier * notifier ); virtual bool handler( void * ref, IOService * newService ); virtual OSObject * getNextObject(); @@ -353,10 +436,25 @@ class IOServiceMessageUserNotification : public IOUserNotification { OSDeclareDefaultStructors(IOServiceMessageUserNotification) + struct PingMsg { + mach_msg_header_t msgHdr; + mach_msg_body_t msgBody; + mach_msg_port_descriptor_t ports[1]; + OSNotificationHeader64 notifyHeader __attribute__ ((packed)); + }; + + PingMsg * pingMsg; + vm_size_t msgSize; + uint8_t clientIs64; + int owningPID; + public: virtual bool init( mach_port_t port, natural_t type, - OSAsyncReference reference, vm_size_t extraSize ); + void * reference, vm_size_t referenceSize, + vm_size_t extraSize, + bool clientIs64 ); + virtual void free(); static IOReturn _handler( void * target, void * ref, @@ -378,8 +476,7 @@ OSDefineAbstractStructors( IOUserNotification, OSIterator ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -bool IOUserNotification::init( mach_port_t port, natural_t type, - OSAsyncReference reference, vm_size_t extraSize ) +bool IOUserNotification::init( void ) { if( !super::init()) return( false ); @@ -388,24 +485,6 @@ bool IOUserNotification::init( mach_port_t port, natural_t type, if( !lock) return( false ); - msgSize = sizeof( PingMsg) + extraSize; - pingMsg = (PingMsg *) IOMalloc( msgSize); - if( !pingMsg) - return( false ); - - bzero( pingMsg, msgSize); - - pingMsg->msgHdr.msgh_remote_port = port; - pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS( - MACH_MSG_TYPE_COPY_SEND, - MACH_MSG_TYPE_MAKE_SEND ); - pingMsg->msgHdr.msgh_size = msgSize; - pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; - - pingMsg->notifyHeader.size = extraSize; - pingMsg->notifyHeader.type = type; - bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) ); - return( true ); } @@ -415,9 +494,6 @@ void IOUserNotification::free( void ) holdNotify->remove(); // can't be in handler now - if( pingMsg) - IOFree( pingMsg, msgSize); - if( lock) IOLockFree( lock ); @@ -427,10 +503,17 @@ void IOUserNotification::free( void ) void IOUserNotification::setNotification( IONotifier * notify ) { - if( holdNotify) - holdNotify->remove(); + IONotifier * previousNotify; + IOLockLock( gIOObjectPortLock); + + previousNotify = holdNotify; holdNotify = notify; + + IOLockUnlock( gIOObjectPortLock); + + if( previousNotify) + previousNotify->remove(); } void IOUserNotification::reset() @@ -452,33 +535,68 @@ OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOServiceUserNotification::init( mach_port_t port, natural_t type, - OSAsyncReference reference ) + void * reference, vm_size_t referenceSize, + bool clientIs64 ) { newSet = OSArray::withCapacity( 1 ); if( !newSet) return( false ); - return( super::init( port, type, reference, 0) ); + if (referenceSize > sizeof(OSAsyncReference64)) + return( false ); + + msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize; + pingMsg = (PingMsg *) IOMalloc( msgSize); + if( !pingMsg) + return( false ); + + bzero( pingMsg, msgSize); + + pingMsg->msgHdr.msgh_remote_port = port; + pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS( + MACH_MSG_TYPE_COPY_SEND /*remote*/, + MACH_MSG_TYPE_MAKE_SEND /*local*/); + pingMsg->msgHdr.msgh_size = msgSize; + pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; + + pingMsg->notifyHeader.size = 0; + pingMsg->notifyHeader.type = type; + bcopy( reference, pingMsg->notifyHeader.reference, referenceSize ); + + return( super::init() ); } void IOServiceUserNotification::free( void ) { - if( lastEntry) - lastEntry->release(); + PingMsg * _pingMsg; + vm_size_t _msgSize; + OSArray * _newSet; + OSObject * _lastEntry; - if( newSet) - newSet->release(); + _pingMsg = pingMsg; + _msgSize = msgSize; + _lastEntry = lastEntry; + _newSet = newSet; super::free(); + + if( _pingMsg && _msgSize) + IOFree( _pingMsg, _msgSize); + + if( _lastEntry) + _lastEntry->release(); + + if( _newSet) + _newSet->release(); } bool IOServiceUserNotification::_handler( void * target, - void * ref, IOService * newService ) + void * ref, IOService * newService, IONotifier * notifier ) { return( ((IOServiceUserNotification *) target)->handler( ref, newService )); } -bool IOServiceUserNotification::handler( void * /* ref */, +bool IOServiceUserNotification::handler( void * ref, IOService * newService ) { unsigned int count; @@ -498,19 +616,22 @@ bool IOServiceUserNotification::handler( void * /* ref */, IOUnlock( lock ); + if( kIOServiceTerminatedNotificationType == pingMsg->notifyHeader.type) + IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT ); + if( sendPing) { if( (port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ) )) pingMsg->msgHdr.msgh_local_port = port; else pingMsg->msgHdr.msgh_local_port = NULL; - kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, + kr = mach_msg_send_from_kernel_proper( &pingMsg->msgHdr, pingMsg->msgHdr.msgh_size); if( port) iokit_release_port( port ); if( KERN_SUCCESS != kr) - IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); + IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); } return( true ); @@ -549,15 +670,58 @@ OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotificati /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, - OSAsyncReference reference, vm_size_t extraSize ) + void * reference, vm_size_t referenceSize, vm_size_t extraSize, + bool client64 ) { - return( super::init( port, type, reference, - sizeof(IOServiceInterestContent) + extraSize) ); + + if (referenceSize > sizeof(OSAsyncReference64)) + return( false ); + + clientIs64 = client64; + + owningPID = proc_selfpid(); + + extraSize += sizeof(IOServiceInterestContent64); + msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize + extraSize; + pingMsg = (PingMsg *) IOMalloc( msgSize); + if( !pingMsg) + return( false ); + + bzero( pingMsg, msgSize); + + pingMsg->msgHdr.msgh_remote_port = port; + pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS( + MACH_MSG_TYPE_COPY_SEND /*remote*/, + MACH_MSG_TYPE_MAKE_SEND /*local*/); + pingMsg->msgHdr.msgh_size = msgSize; + pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; + + pingMsg->msgBody.msgh_descriptor_count = 1; + + pingMsg->ports[0].name = 0; + pingMsg->ports[0].disposition = MACH_MSG_TYPE_MAKE_SEND; + pingMsg->ports[0].type = MACH_MSG_PORT_DESCRIPTOR; + + pingMsg->notifyHeader.size = extraSize; + pingMsg->notifyHeader.type = type; + bcopy( reference, pingMsg->notifyHeader.reference, referenceSize ); + + return( super::init() ); } void IOServiceMessageUserNotification::free( void ) { + PingMsg * _pingMsg; + vm_size_t _msgSize; + + _pingMsg = pingMsg; + _msgSize = msgSize; + super::free(); + + if( _pingMsg && _msgSize) + IOFree( _pingMsg, _msgSize); } IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref, @@ -572,38 +736,55 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, UInt32 messageType, IOService * provider, void * messageArgument, vm_size_t argSize ) { - kern_return_t kr; - ipc_port_t port; - IOServiceInterestContent * data = (IOServiceInterestContent *) - pingMsg->notifyHeader.content; + kern_return_t kr; + ipc_port_t thisPort, providerPort; + IOServiceInterestContent64 * data = (IOServiceInterestContent64 *) + ((((uint8_t *) pingMsg) + msgSize) - pingMsg->notifyHeader.size); + // == pingMsg->notifyHeader.content; + + if (kIOMessageCopyClientID == messageType) + { + *((void **) messageArgument) = IOCopyLogNameForPID(owningPID); + return (kIOReturnSuccess); + } data->messageType = messageType; - if( argSize == 0) { - argSize = sizeof( messageArgument); - data->messageArgument[0] = messageArgument; - } else { + + if( argSize == 0) + { + data->messageArgument[0] = (io_user_reference_t) messageArgument; + if (clientIs64) + argSize = sizeof(data->messageArgument[0]); + else + { + data->messageArgument[0] |= (data->messageArgument[0] << 32); + argSize = sizeof(uint32_t); + } + } + else + { if( argSize > kIOUserNotifyMaxMessageSize) argSize = kIOUserNotifyMaxMessageSize; bcopy( messageArgument, data->messageArgument, argSize ); } - pingMsg->msgHdr.msgh_size = sizeof( PingMsg) - + sizeof( IOServiceInterestContent ) + pingMsg->msgHdr.msgh_size = msgSize - pingMsg->notifyHeader.size + + sizeof( IOServiceInterestContent64 ) - sizeof( data->messageArgument) + argSize; - if( (port = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT ) )) - pingMsg->msgHdr.msgh_local_port = port; - else - pingMsg->msgHdr.msgh_local_port = NULL; - - kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, - pingMsg->msgHdr.msgh_size); - - if( port) - iokit_release_port( port ); + providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT ); + pingMsg->ports[0].name = providerPort; + thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ); + pingMsg->msgHdr.msgh_local_port = thisPort; + kr = mach_msg_send_from_kernel_proper( &pingMsg->msgHdr, + pingMsg->msgHdr.msgh_size); + if( thisPort) + iokit_release_port( thisPort ); + if( providerPort) + iokit_release_port( providerPort ); if( KERN_SUCCESS != kr) - IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); + IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); return( kIOReturnSuccess ); } @@ -630,29 +811,142 @@ void IOUserClient::setAsyncReference(OSAsyncReference asyncRef, mach_port_t wakePort, void *callback, void *refcon) { - asyncRef[kIOAsyncReservedIndex] = (natural_t) wakePort; - asyncRef[kIOAsyncCalloutFuncIndex] = (natural_t) callback; - asyncRef[kIOAsyncCalloutRefconIndex] = (natural_t) refcon; + asyncRef[kIOAsyncReservedIndex] = ((uintptr_t) wakePort) + | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]); + asyncRef[kIOAsyncCalloutFuncIndex] = (uintptr_t) callback; + asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon; +} + +void IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef, + mach_port_t wakePort, + mach_vm_address_t callback, io_user_reference_t refcon) +{ + asyncRef[kIOAsyncReservedIndex] = ((io_user_reference_t) wakePort) + | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]); + asyncRef[kIOAsyncCalloutFuncIndex] = (io_user_reference_t) callback; + asyncRef[kIOAsyncCalloutRefconIndex] = refcon; +} + +static OSDictionary * CopyConsoleUser(UInt32 uid) +{ + OSArray * array; + OSDictionary * user = 0; + + if ((array = OSDynamicCast(OSArray, + IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) + { + for (unsigned int idx = 0; + (user = OSDynamicCast(OSDictionary, array->getObject(idx))); + idx++) { + OSNumber * num; + + if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey))) + && (uid == num->unsigned32BitValue())) { + user->retain(); + break; + } + } + array->release(); + } + return user; +} + +static bool IOUCIsBackgroundTask(task_t task, bool * isBg) +{ + kern_return_t kr; + task_category_policy_data_t info; + mach_msg_type_number_t count = TASK_CATEGORY_POLICY_COUNT; + boolean_t get_default = false; + + kr = task_policy_get(current_task(), + TASK_CATEGORY_POLICY, + (task_policy_t) &info, + &count, + &get_default); + + *isBg = ((KERN_SUCCESS == kr) && (info.role == TASK_THROTTLE_APPLICATION)); + return (kr); } IOReturn IOUserClient::clientHasPrivilege( void * securityToken, const char * privilegeName ) { - kern_return_t kr; - security_token_t token; - mach_msg_type_number_t count; - - if( 0 != strcmp( privilegeName, kIOClientPrivilegeAdministrator)) - return( kIOReturnUnsupported ); + kern_return_t kr; + security_token_t token; + mach_msg_type_number_t count; + task_t task; + OSDictionary * user; + bool secureConsole; + + + if (!strncmp(privilegeName, kIOClientPrivilegeForeground, + sizeof(kIOClientPrivilegeForeground))) + { + bool isBg; + kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg); + + if (KERN_SUCCESS != kr) + return (kr); + return (isBg ? kIOReturnNotPrivileged : kIOReturnSuccess); + } + if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess, + sizeof(kIOClientPrivilegeSecureConsoleProcess)))) + task = (task_t)((IOUCProcessToken *)securityToken)->token; + else + task = (task_t)securityToken; + count = TASK_SECURITY_TOKEN_COUNT; - kr = task_info( (task_t) securityToken, TASK_SECURITY_TOKEN, - (task_info_t) &token, &count ); - if( (kr == kIOReturnSuccess) - && (0 != token.val[0])) - kr = kIOReturnNotPrivileged; + kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count ); + + if (KERN_SUCCESS != kr) + {} + else if (!strncmp(privilegeName, kIOClientPrivilegeAdministrator, + sizeof(kIOClientPrivilegeAdministrator))) { + if (0 != token.val[0]) + kr = kIOReturnNotPrivileged; + } else if (!strncmp(privilegeName, kIOClientPrivilegeLocalUser, + sizeof(kIOClientPrivilegeLocalUser))) { + user = CopyConsoleUser(token.val[0]); + if ( user ) + user->release(); + else + kr = kIOReturnNotPrivileged; + } else if (secureConsole || !strncmp(privilegeName, kIOClientPrivilegeConsoleUser, + sizeof(kIOClientPrivilegeConsoleUser))) { + user = CopyConsoleUser(token.val[0]); + if ( user ) { + if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue) + kr = kIOReturnNotPrivileged; + else if ( secureConsole ) { + OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey)); + if ( pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid) + kr = kIOReturnNotPrivileged; + } + user->release(); + } + else + kr = kIOReturnNotPrivileged; + } else + kr = kIOReturnUnsupported; - return( kr ); + return (kr); +} + +bool IOUserClient::init() +{ + if( getPropertyTable()) + return true; + else + return super::init(); +} + +bool IOUserClient::init(OSDictionary * dictionary) +{ + if( getPropertyTable()) + return true; + else + return super::init(dictionary); } bool IOUserClient::initWithTask(task_t owningTask, @@ -709,6 +1003,14 @@ IOReturn IOUserClient::registerNotificationPort( return( kIOReturnUnsupported); } +IOReturn IOUserClient::registerNotificationPort( + mach_port_t port, + UInt32 type, + io_user_reference_t refCon) +{ + return (registerNotificationPort(port, type, (UInt32) refCon)); +} + IOReturn IOUserClient::getNotificationSemaphore( UInt32 notification_type, semaphore_t * semaphore ) { @@ -727,11 +1029,22 @@ IOReturn IOUserClient::clientMemoryForType( UInt32 type, return( kIOReturnUnsupported); } +#if !__LP64__ IOMemoryMap * IOUserClient::mapClientMemory( IOOptionBits type, task_t task, IOOptionBits mapFlags, IOVirtualAddress atAddress ) +{ + return (NULL); +} +#endif + +IOMemoryMap * IOUserClient::mapClientMemory64( + IOOptionBits type, + task_t task, + IOOptionBits mapFlags, + mach_vm_address_t atAddress ) { IOReturn err; IOOptionBits options = 0; @@ -744,7 +1057,7 @@ IOMemoryMap * IOUserClient::mapClientMemory( options = (options & ~kIOMapUserOptionsMask) | (mapFlags & kIOMapUserOptionsMask); - map = memory->map( task, atAddress, options ); + map = memory->createMappingInTask( task, atAddress, options ); memory->release(); } @@ -813,48 +1126,126 @@ getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) return trap; } +IOReturn IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference) +{ + mach_port_t port; + port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags); + + if (MACH_PORT_NULL != port) + iokit_release_port_send(port); + + return (kIOReturnSuccess); +} + +IOReturn IOUserClient::releaseNotificationPort(mach_port_t port) +{ + if (MACH_PORT_NULL != port) + iokit_release_port_send(port); + + return (kIOReturnSuccess); +} + IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference, IOReturn result, void *args[], UInt32 numArgs) { - struct ReplyMsg { - mach_msg_header_t msgHdr; - OSNotificationHeader notifyHdr; - IOAsyncCompletionContent asyncContent; - void * args[kMaxAsyncArgs]; + OSAsyncReference64 reference64; + io_user_reference_t args64[kMaxAsyncArgs]; + unsigned int idx; + + if (numArgs > kMaxAsyncArgs) + return kIOReturnMessageTooLarge; + + for (idx = 0; idx < kOSAsyncRef64Count; idx++) + reference64[idx] = REF64(reference[idx]); + + for (idx = 0; idx < numArgs; idx++) + args64[idx] = REF64(args[idx]); + + return (sendAsyncResult64(reference64, result, args64, numArgs)); +} + +IOReturn IOUserClient::sendAsyncResult64(OSAsyncReference64 reference, + IOReturn result, io_user_reference_t args[], UInt32 numArgs) +{ + struct ReplyMsg + { + mach_msg_header_t msgHdr; + union + { + struct + { + OSNotificationHeader notifyHdr; + IOAsyncCompletionContent asyncContent; + uint32_t args[kMaxAsyncArgs]; + } msg32; + struct + { + OSNotificationHeader64 notifyHdr; + IOAsyncCompletionContent asyncContent; + io_user_reference_t args[kMaxAsyncArgs] __attribute__ ((packed)); + } msg64; + } m; }; - ReplyMsg replyMsg; - mach_port_t replyPort; + ReplyMsg replyMsg; + mach_port_t replyPort; kern_return_t kr; // If no reply port, do nothing. - replyPort = (mach_port_t) reference[0]; - if(replyPort == MACH_PORT_NULL) + replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags); + if (replyPort == MACH_PORT_NULL) return kIOReturnSuccess; - if(numArgs > kMaxAsyncArgs) + if (numArgs > kMaxAsyncArgs) return kIOReturnMessageTooLarge; - replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0); - replyMsg.msgHdr.msgh_size = - sizeof(replyMsg) - (kMaxAsyncArgs-numArgs)*sizeof(void *); + + replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/, + 0 /*local*/); replyMsg.msgHdr.msgh_remote_port = replyPort; - replyMsg.msgHdr.msgh_local_port = 0; - replyMsg.msgHdr.msgh_id = kOSNotificationMessageID; - - replyMsg.notifyHdr.size = sizeof(IOAsyncCompletionContent) - + numArgs*sizeof(void *); - replyMsg.notifyHdr.type = kIOAsyncCompletionNotificationType; - bcopy( reference, replyMsg.notifyHdr.reference, sizeof(OSAsyncReference)); - - replyMsg.asyncContent.result = result; - if(numArgs > 0) - bcopy(args, replyMsg.args, sizeof(void *)*numArgs); - kr = mach_msg_send_from_kernel( &replyMsg.msgHdr, + replyMsg.msgHdr.msgh_local_port = 0; + replyMsg.msgHdr.msgh_id = kOSNotificationMessageID; + if (kIOUCAsync64Flag & reference[0]) + { + replyMsg.msgHdr.msgh_size = + sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64) + - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t); + replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent) + + numArgs * sizeof(io_user_reference_t); + replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType; + bcopy(reference, replyMsg.m.msg64.notifyHdr.reference, sizeof(OSAsyncReference64)); + + replyMsg.m.msg64.asyncContent.result = result; + if (numArgs) + bcopy(args, replyMsg.m.msg64.args, numArgs * sizeof(io_user_reference_t)); + } + else + { + unsigned int idx; + + replyMsg.msgHdr.msgh_size = + sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32) + - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t); + + replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent) + + numArgs * sizeof(uint32_t); + replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType; + + for (idx = 0; idx < kOSAsyncRefCount; idx++) + replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]); + + replyMsg.m.msg32.asyncContent.result = result; + + for (idx = 0; idx < numArgs; idx++) + replyMsg.m.msg32.args[idx] = REF32(args[idx]); + } + + kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr, replyMsg.msgHdr.msgh_size); if( KERN_SUCCESS != kr) - IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); + IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); return kr; } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ extern "C" { @@ -869,35 +1260,122 @@ kern_return_t is_io_object_get_class( io_object_t object, io_name_t className ) { - if( !object) - return( kIOReturnBadArgument ); - - strcpy( className, object->getMetaClass()->getClassName()); + const OSMetaClass* my_obj = NULL; + + if( !object) + return( kIOReturnBadArgument ); + + my_obj = object->getMetaClass(); + if (!my_obj) { + return (kIOReturnNotFound); + } + + strlcpy( className, my_obj->getClassName(), sizeof(io_name_t)); return( kIOReturnSuccess ); } -/* Routine io_object_conforms_to */ -kern_return_t is_io_object_conforms_to( - io_object_t object, - io_name_t className, - boolean_t *conforms ) +/* Routine io_object_get_superclass */ +kern_return_t is_io_object_get_superclass( + mach_port_t master_port, + io_name_t obj_name, + io_name_t class_name) { - if( !object) - return( kIOReturnBadArgument ); + const OSMetaClass* my_obj = NULL; + const OSMetaClass* superclass = NULL; + const OSSymbol *my_name = NULL; + const char *my_cstr = NULL; - *conforms = (0 != object->metaCast( className )); - return( kIOReturnSuccess ); -} + if (!obj_name || !class_name) + return (kIOReturnBadArgument); -/* Routine io_object_get_retain_count */ -kern_return_t is_io_object_get_retain_count( - io_object_t object, - int *retainCount ) -{ - if( !object) - return( kIOReturnBadArgument ); + if( master_port != master_device_port) + return( kIOReturnNotPrivileged); - *retainCount = object->getRetainCount(); + my_name = OSSymbol::withCString(obj_name); + + if (my_name) { + my_obj = OSMetaClass::getMetaClassWithName(my_name); + my_name->release(); + } + if (my_obj) { + superclass = my_obj->getSuperClass(); + } + + if (!superclass) { + return( kIOReturnNotFound ); + } + + my_cstr = superclass->getClassName(); + + if (my_cstr) { + strlcpy(class_name, my_cstr, sizeof(io_name_t)); + return( kIOReturnSuccess ); + } + return (kIOReturnNotFound); +} + +/* Routine io_object_get_bundle_identifier */ +kern_return_t is_io_object_get_bundle_identifier( + mach_port_t master_port, + io_name_t obj_name, + io_name_t bundle_name) +{ + const OSMetaClass* my_obj = NULL; + const OSSymbol *my_name = NULL; + const OSSymbol *identifier = NULL; + const char *my_cstr = NULL; + + if (!obj_name || !bundle_name) + return (kIOReturnBadArgument); + + if( master_port != master_device_port) + return( kIOReturnNotPrivileged); + + my_name = OSSymbol::withCString(obj_name); + + if (my_name) { + my_obj = OSMetaClass::getMetaClassWithName(my_name); + my_name->release(); + } + + if (my_obj) { + identifier = my_obj->getKmodName(); + } + if (!identifier) { + return( kIOReturnNotFound ); + } + + my_cstr = identifier->getCStringNoCopy(); + if (my_cstr) { + strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t)); + return( kIOReturnSuccess ); + } + + return (kIOReturnBadArgument); +} + +/* Routine io_object_conforms_to */ +kern_return_t is_io_object_conforms_to( + io_object_t object, + io_name_t className, + boolean_t *conforms ) +{ + if( !object) + return( kIOReturnBadArgument ); + + *conforms = (0 != object->metaCast( className )); + return( kIOReturnSuccess ); +} + +/* Routine io_object_get_retain_count */ +kern_return_t is_io_object_get_retain_count( + io_object_t object, + uint32_t *retainCount ) +{ + if( !object) + return( kIOReturnBadArgument ); + + *retainCount = object->getRetainCount(); return( kIOReturnSuccess ); } @@ -968,6 +1446,31 @@ kern_return_t is_io_service_match_property_table( return( kr ); } +/* Routine io_service_match_property_table_ool */ +kern_return_t is_io_service_match_property_table_ool( + io_object_t service, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + kern_return_t *result, + boolean_t *matches ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = is_io_service_match_property_table( service, + (char *) data, matches ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + /* Routine io_service_get_matching_services */ kern_return_t is_io_service_get_matching_services( mach_port_t master_port, @@ -995,17 +1498,41 @@ kern_return_t is_io_service_get_matching_services( return( kr ); } -/* Routine io_service_add_notification */ -kern_return_t is_io_service_add_notification( +/* Routine io_service_get_matching_services_ool */ +kern_return_t is_io_service_get_matching_services_ool( + mach_port_t master_port, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + kern_return_t *result, + io_object_t *existing ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = is_io_service_get_matching_services( master_port, + (char *) data, existing ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + +static kern_return_t internal_io_service_add_notification( mach_port_t master_port, io_name_t notification_type, io_string_t matching, mach_port_t port, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, + void * reference, + vm_size_t referenceSize, + bool client64, io_object_t * notification ) { - IOServiceUserNotification * userNotify = 0; IONotifier * notify = 0; const OSSymbol * sym; @@ -1043,17 +1570,16 @@ kern_return_t is_io_service_add_notification( userNotify = new IOServiceUserNotification; if( userNotify && !userNotify->init( port, userMsgType, - reference)) { + reference, referenceSize, client64)) { userNotify->release(); userNotify = 0; } if( !userNotify) continue; - notify = IOService::addNotification( sym, dict, + notify = IOService::addMatchingNotification( sym, dict, &userNotify->_handler, userNotify ); if( notify) { - dict = 0; *notification = userNotify; userNotify->setNotification( notify ); err = kIOReturnSuccess; @@ -1070,12 +1596,108 @@ kern_return_t is_io_service_add_notification( return( err ); } + +/* Routine io_service_add_notification */ +kern_return_t is_io_service_add_notification( + mach_port_t master_port, + io_name_t notification_type, + io_string_t matching, + mach_port_t port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + io_object_t * notification ) +{ + return (internal_io_service_add_notification(master_port, notification_type, + matching, port, &reference[0], sizeof(io_async_ref_t), + false, notification)); +} + +/* Routine io_service_add_notification_64 */ +kern_return_t is_io_service_add_notification_64( + mach_port_t master_port, + io_name_t notification_type, + io_string_t matching, + mach_port_t wake_port, + io_async_ref64_t reference, + mach_msg_type_number_t referenceCnt, + io_object_t *notification ) +{ + return (internal_io_service_add_notification(master_port, notification_type, + matching, wake_port, &reference[0], sizeof(io_async_ref64_t), + true, notification)); +} + + +static kern_return_t internal_io_service_add_notification_ool( + mach_port_t master_port, + io_name_t notification_type, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + mach_port_t wake_port, + void * reference, + vm_size_t referenceSize, + bool client64, + kern_return_t *result, + io_object_t *notification ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = internal_io_service_add_notification( master_port, notification_type, + (char *) data, wake_port, reference, referenceSize, client64, notification ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + +/* Routine io_service_add_notification_ool */ +kern_return_t is_io_service_add_notification_ool( + mach_port_t master_port, + io_name_t notification_type, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + kern_return_t *result, + io_object_t *notification ) +{ + return (internal_io_service_add_notification_ool(master_port, notification_type, + matching, matchingCnt, wake_port, &reference[0], sizeof(io_async_ref_t), + false, result, notification)); +} + +/* Routine io_service_add_notification_ool_64 */ +kern_return_t is_io_service_add_notification_ool_64( + mach_port_t master_port, + io_name_t notification_type, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + mach_port_t wake_port, + io_async_ref64_t reference, + mach_msg_type_number_t referenceCnt, + kern_return_t *result, + io_object_t *notification ) +{ + return (internal_io_service_add_notification_ool(master_port, notification_type, + matching, matchingCnt, wake_port, &reference[0], sizeof(io_async_ref64_t), + true, result, notification)); +} + /* Routine io_service_add_notification_old */ kern_return_t is_io_service_add_notification_old( mach_port_t master_port, io_name_t notification_type, io_string_t matching, mach_port_t port, + // for binary compatibility reasons, this must be natural_t for ILP32 natural_t ref, io_object_t * notification ) { @@ -1083,13 +1705,14 @@ kern_return_t is_io_service_add_notification_old( matching, port, &ref, 1, notification )); } -/* Routine io_service_add_message_notification */ -kern_return_t is_io_service_add_interest_notification( + +static kern_return_t internal_io_service_add_interest_notification( io_object_t _service, io_name_t type_of_interest, mach_port_t port, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, + void * reference, + vm_size_t referenceSize, + bool client64, io_object_t * notification ) { @@ -1106,7 +1729,9 @@ kern_return_t is_io_service_add_interest_notification( userNotify = new IOServiceMessageUserNotification; if( userNotify && !userNotify->init( port, kIOServiceMessageNotificationType, - reference, kIOUserNotifyMaxMessageSize )) { + reference, referenceSize, + kIOUserNotifyMaxMessageSize, + client64 )) { userNotify->release(); userNotify = 0; } @@ -1122,11 +1747,40 @@ kern_return_t is_io_service_add_interest_notification( } else err = kIOReturnUnsupported; + sym->release(); + } while( false ); return( err ); } +/* Routine io_service_add_message_notification */ +kern_return_t is_io_service_add_interest_notification( + io_object_t service, + io_name_t type_of_interest, + mach_port_t port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + io_object_t * notification ) +{ + return (internal_io_service_add_interest_notification(service, type_of_interest, + port, &reference[0], sizeof(io_async_ref_t), false, notification)); +} + +/* Routine io_service_add_interest_notification_64 */ +kern_return_t is_io_service_add_interest_notification_64( + io_object_t service, + io_name_t type_of_interest, + mach_port_t wake_port, + io_async_ref64_t reference, + mach_msg_type_number_t referenceCnt, + io_object_t *notification ) +{ + return (internal_io_service_add_interest_notification(service, type_of_interest, + wake_port, &reference[0], sizeof(io_async_ref64_t), true, notification)); +} + + /* Routine io_service_acknowledge_notification */ kern_return_t is_io_service_acknowledge_notification( io_object_t _service, @@ -1174,7 +1828,7 @@ kern_return_t is_io_registry_get_root_entry( kern_return_t is_io_registry_create_iterator( mach_port_t master_port, io_name_t plane, - int options, + uint32_t options, io_object_t *iterator ) { if( master_port != master_device_port) @@ -1190,7 +1844,7 @@ kern_return_t is_io_registry_create_iterator( kern_return_t is_io_registry_entry_create_iterator( io_object_t registry_entry, io_name_t plane, - int options, + uint32_t options, io_object_t *iterator ) { CHECK( IORegistryEntry, registry_entry, entry ); @@ -1328,6 +1982,18 @@ kern_return_t is_io_registry_entry_get_location_in_plane( return( kIOReturnNotFound ); } +/* Routine io_registry_entry_get_registry_entry_id */ +kern_return_t is_io_registry_entry_get_registry_entry_id( + io_object_t registry_entry, + uint64_t *entry_id ) +{ + CHECK( IORegistryEntry, registry_entry, entry ); + + *entry_id = entry->getRegistryEntryID(); + + return (kIOReturnSuccess); +} + // Create a vm_map_copy_t or kalloc'ed data for memory // to be copied out. ipc will free after the copyout. @@ -1337,7 +2003,7 @@ static kern_return_t copyoutkdata( void * data, vm_size_t len, kern_return_t err; vm_map_copy_t copy; - err = vm_map_copyin( kernel_map, (vm_offset_t) data, len, + err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len, false /* src_destroy */, ©); assert( err == KERN_SUCCESS ); @@ -1351,7 +2017,7 @@ static kern_return_t copyoutkdata( void * data, vm_size_t len, kern_return_t is_io_registry_entry_get_property_bytes( io_object_t registry_entry, io_name_t property_name, - io_scalar_inband_t buf, + io_struct_inband_t buf, mach_msg_type_number_t *dataCnt ) { OSObject * obj; @@ -1388,7 +2054,7 @@ kern_return_t is_io_registry_entry_get_property_bytes( offsetBytes = off->unsigned64BitValue(); len = off->numberOfBytes(); bytes = &offsetBytes; -#if __BIG_ENDIAN__ +#ifdef __BIG_ENDIAN__ bytes = (const void *) (((UInt32) bytes) + (sizeof( UInt64) - len)); #endif @@ -1409,6 +2075,7 @@ kern_return_t is_io_registry_entry_get_property_bytes( return( ret ); } + /* Routine io_registry_entry_get_property */ kern_return_t is_io_registry_entry_get_property( io_object_t registry_entry, @@ -1452,7 +2119,7 @@ kern_return_t is_io_registry_entry_get_property_recursively( io_object_t registry_entry, io_name_t plane, io_name_t property_name, - int options, + uint32_t options, io_buf_ptr_t *properties, mach_msg_type_number_t *propertiesCnt ) { @@ -1525,16 +2192,18 @@ kern_return_t is_io_registry_entry_set_properties io_object_t registry_entry, io_buf_ptr_t properties, mach_msg_type_number_t propertiesCnt, - natural_t * result) + kern_return_t * result) { OSObject * obj; kern_return_t err; IOReturn res; vm_offset_t data; + vm_map_offset_t map_data; CHECK( IORegistryEntry, registry_entry, entry ); - err = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) properties ); + err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties ); + data = CAST_DOWN(vm_offset_t, map_data); if( KERN_SUCCESS == err) { @@ -1585,7 +2254,7 @@ kern_return_t is_io_registry_entry_get_parent_iterator( /* Routine io_service_get_busy_state */ kern_return_t is_io_service_get_busy_state( io_object_t _service, - int *busyState ) + uint32_t *busyState ) { CHECK( IOService, _service, service ); @@ -1594,20 +2263,42 @@ kern_return_t is_io_service_get_busy_state( return( kIOReturnSuccess ); } +/* Routine io_service_get_state */ +kern_return_t is_io_service_get_state( + io_object_t _service, + uint64_t *state, + uint32_t *busy_state, + uint64_t *accumulated_busy_time ) +{ + CHECK( IOService, _service, service ); + + *state = service->getState(); + *busy_state = service->getBusyState(); + *accumulated_busy_time = service->getAccumulatedBusyTime(); + + return( kIOReturnSuccess ); +} + /* Routine io_service_wait_quiet */ kern_return_t is_io_service_wait_quiet( io_object_t _service, mach_timespec_t wait_time ) { + uint64_t timeoutNS; + CHECK( IOService, _service, service ); - return( service->waitQuiet( &wait_time )); + timeoutNS = wait_time.tv_sec; + timeoutNS *= kSecondScale; + timeoutNS += wait_time.tv_nsec; + + return( service->waitQuiet(timeoutNS) ); } /* Routine io_service_request_probe */ kern_return_t is_io_service_request_probe( io_object_t _service, - int options ) + uint32_t options ) { CHECK( IOService, _service, service ); @@ -1619,7 +2310,7 @@ kern_return_t is_io_service_request_probe( kern_return_t is_io_service_open( io_object_t _service, task_t owningTask, - int connect_type, + uint32_t connect_type, io_object_t *connection ) { IOUserClient * client; @@ -1628,7 +2319,7 @@ kern_return_t is_io_service_open( CHECK( IOService, _service, service ); err = service->newUserClient( owningTask, (void *) owningTask, - connect_type, &client ); + connect_type, 0, &client ); if( err == kIOReturnSuccess) { assert( OSDynamicCast(IOUserClient, client) ); @@ -1638,10 +2329,115 @@ kern_return_t is_io_service_open( return( err); } +/* Routine io_service_open_ndr */ +kern_return_t is_io_service_open_extended( + io_object_t _service, + task_t owningTask, + uint32_t connect_type, + NDR_record_t ndr, + io_buf_ptr_t properties, + mach_msg_type_number_t propertiesCnt, + kern_return_t * result, + io_object_t *connection ) +{ + IOUserClient * client = 0; + kern_return_t err = KERN_SUCCESS; + IOReturn res = kIOReturnSuccess; + OSDictionary * propertiesDict = 0; + bool crossEndian; + bool disallowAccess; + + CHECK( IOService, _service, service ); + + do + { + if (properties) + { + OSObject * obj; + vm_offset_t data; + vm_map_offset_t map_data; + + err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties ); + res = err; + data = CAST_DOWN(vm_offset_t, map_data); + if (KERN_SUCCESS == err) + { + // must return success after vm_map_copyout() succeeds + obj = OSUnserializeXML( (const char *) data ); + vm_deallocate( kernel_map, data, propertiesCnt ); + propertiesDict = OSDynamicCast(OSDictionary, obj); + if (!propertiesDict) + { + res = kIOReturnBadArgument; + if (obj) + obj->release(); + } + } + if (kIOReturnSuccess != res) + break; + } + + crossEndian = (ndr.int_rep != NDR_record.int_rep); + if (crossEndian) + { + if (!propertiesDict) + propertiesDict = OSDictionary::withCapacity(4); + OSData * data = OSData::withBytes(&ndr, sizeof(ndr)); + if (data) + { + if (propertiesDict) + propertiesDict->setObject(kIOUserClientCrossEndianKey, data); + data->release(); + } + } + + res = service->newUserClient( owningTask, (void *) owningTask, + connect_type, propertiesDict, &client ); + + if (propertiesDict) + propertiesDict->release(); + + if (res == kIOReturnSuccess) + { + assert( OSDynamicCast(IOUserClient, client) ); + + disallowAccess = (crossEndian + && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey)) + && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey))); + + if (disallowAccess) + { + client->clientClose(); + client->release(); + client = 0; + res = kIOReturnUnsupported; + break; + } + client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey)); + OSString * creatorName = IOCopyLogNameForPID(proc_selfpid()); + if (creatorName) + { + client->setProperty(kIOUserClientCreatorKey, creatorName); + creatorName->release(); + } + } + } + while (false); + + *connection = client; + *result = res; + + return (err); +} + /* Routine io_service_close */ kern_return_t is_io_service_close( io_object_t connection ) { + OSSet * mappings; + if ((mappings = OSDynamicCast(OSSet, connection))) + return( kIOReturnSuccess ); + CHECK( IOUserClient, connection, client ); client->clientClose(); @@ -1670,9 +2466,22 @@ kern_return_t is_io_connect_get_service( /* Routine io_connect_set_notification_port */ kern_return_t is_io_connect_set_notification_port( io_object_t connection, - int notification_type, + uint32_t notification_type, + mach_port_t port, + uint32_t reference) +{ + CHECK( IOUserClient, connection, client ); + + return( client->registerNotificationPort( port, notification_type, + (io_user_reference_t) reference )); +} + +/* Routine io_connect_set_notification_port */ +kern_return_t is_io_connect_set_notification_port_64( + io_object_t connection, + uint32_t notification_type, mach_port_t port, - int reference) + io_user_reference_t reference) { CHECK( IOUserClient, connection, client ); @@ -1680,31 +2489,36 @@ kern_return_t is_io_connect_set_notification_port( reference )); } -kern_return_t is_io_connect_map_memory( - io_object_t connect, - int type, - task_t task, - vm_address_t * mapAddr, - vm_size_t * mapSize, - int flags ) +/* Routine io_connect_map_memory_into_task */ +kern_return_t is_io_connect_map_memory_into_task +( + io_connect_t connection, + uint32_t memory_type, + task_t into_task, + mach_vm_address_t *address, + mach_vm_size_t *size, + uint32_t flags +) { IOReturn err; IOMemoryMap * map; - CHECK( IOUserClient, connect, client ); + CHECK( IOUserClient, connection, client ); - map = client->mapClientMemory( type, task, flags, *mapAddr ); + map = client->mapClientMemory64( memory_type, into_task, flags, *address ); if( map) { - *mapAddr = map->getVirtualAddress(); - if( mapSize) - *mapSize = map->getLength(); + *address = map->getAddress(); + if( size) + *size = map->getSize(); - if( task != current_task()) { + if( client->sharedInstance + || (into_task != current_task())) { // push a name out to the task owning the map, // so we can clean up maps - mach_port_name_t name = IOMachPort::makeSendRightForTask( - task, map, IKOT_IOKIT_OBJECT ); + mach_port_name_t name __unused = + IOMachPort::makeSendRightForTask( + into_task, map, IKOT_IOKIT_OBJECT ); assert( name ); } else { @@ -1725,42 +2539,125 @@ kern_return_t is_io_connect_map_memory( return( err ); } -kern_return_t is_io_connect_unmap_memory( +/* Routine is_io_connect_map_memory */ +kern_return_t is_io_connect_map_memory( io_object_t connect, - int type, + uint32_t type, task_t task, - vm_address_t mapAddr ) + vm_address_t * mapAddr, + vm_size_t * mapSize, + uint32_t flags ) +{ + IOReturn err; + mach_vm_address_t address; + mach_vm_size_t size; + + address = SCALAR64(*mapAddr); + size = SCALAR64(*mapSize); + + err = is_io_connect_map_memory_into_task(connect, type, task, &address, &size, flags); + + *mapAddr = SCALAR32(address); + *mapSize = SCALAR32(size); + + return (err); +} + +IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem) +{ + OSIterator * iter; + IOMemoryMap * map = 0; + + IOLockLock(gIOObjectPortLock); + + iter = OSCollectionIterator::withCollection(mappings); + if(iter) + { + while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) + { + if(mem == map->getMemoryDescriptor()) + { + map->retain(); + mappings->removeObject(map); + break; + } + } + iter->release(); + } + + IOLockUnlock(gIOObjectPortLock); + + return (map); +} + +/* Routine io_connect_unmap_memory_from_task */ +kern_return_t is_io_connect_unmap_memory_from_task +( + io_connect_t connection, + uint32_t memory_type, + task_t from_task, + mach_vm_address_t address) { IOReturn err; IOOptionBits options = 0; IOMemoryDescriptor * memory; IOMemoryMap * map; - CHECK( IOUserClient, connect, client ); + CHECK( IOUserClient, connection, client ); - err = client->clientMemoryForType( (UInt32) type, &options, &memory ); + err = client->clientMemoryForType( (UInt32) memory_type, &options, &memory ); if( memory && (kIOReturnSuccess == err)) { options = (options & ~kIOMapUserOptionsMask) | kIOMapAnywhere | kIOMapReference; - map = memory->map( task, mapAddr, options ); + map = memory->createMappingInTask( from_task, address, options ); memory->release(); - if( map) { + if( map) + { IOLockLock( gIOObjectPortLock); if( client->mappings) client->mappings->removeObject( map); IOLockUnlock( gIOObjectPortLock); - IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT ); - map->release(); - } else + + mach_port_name_t name = 0; + if (from_task != current_task()) + name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT ); + if (name) + { + map->userClientUnmap(); + err = iokit_mod_send_right( from_task, name, -2 ); + err = kIOReturnSuccess; + } + else + IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT ); + if (from_task == current_task()) + map->release(); + } + else err = kIOReturnBadArgument; } return( err ); } +kern_return_t is_io_connect_unmap_memory( + io_object_t connect, + uint32_t type, + task_t task, + vm_address_t mapAddr ) +{ + IOReturn err; + mach_vm_address_t address; + + address = SCALAR64(mapAddr); + + err = is_io_connect_unmap_memory_from_task(connect, type, task, mapAddr); + + return (err); +} + /* Routine io_connect_add_client */ kern_return_t is_io_connect_add_client( @@ -1779,417 +2676,671 @@ kern_return_t is_io_connect_set_properties( io_object_t connection, io_buf_ptr_t properties, mach_msg_type_number_t propertiesCnt, - natural_t * result) + kern_return_t * result) { return( is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result )); } -/* Routine io_connect_method_scalarI_scalarO */ -kern_return_t is_io_connect_method_scalarI_scalarO( - io_object_t connect, - UInt32 index, - void * input[], - IOByteCount inputCount, - void * output[], - IOByteCount * outputCount ) +/* Routine io_user_client_method */ +kern_return_t is_io_connect_method +( + io_connect_t connection, + uint32_t selector, + io_scalar_inband64_t scalar_input, + mach_msg_type_number_t scalar_inputCnt, + io_struct_inband_t inband_input, + mach_msg_type_number_t inband_inputCnt, + mach_vm_address_t ool_input, + mach_vm_size_t ool_input_size, + io_scalar_inband64_t scalar_output, + mach_msg_type_number_t *scalar_outputCnt, + io_struct_inband_t inband_output, + mach_msg_type_number_t *inband_outputCnt, + mach_vm_address_t ool_output, + mach_vm_size_t * ool_output_size +) { - IOReturn err; - IOExternalMethod * method; - IOService * object; - IOMethod func; + CHECK( IOUserClient, connection, client ); - CHECK( IOUserClient, connect, client); - if( (method = client->getTargetAndMethodForIndex(&object, index))) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIScalarO != (method->flags & kIOUCTypeMask)) - continue; - if( inputCount != method->count0) - continue; - if( *outputCount != method->count1) - continue; + IOExternalMethodArguments args; + IOReturn ret; + IOMemoryDescriptor * inputMD = 0; + IOMemoryDescriptor * outputMD = 0; - func = method->func; + bzero(&args.__reserved[0], sizeof(args.__reserved)); + args.version = kIOExternalMethodArgumentsCurrentVersion; - switch( inputCount) { + args.selector = selector; - case 6: - err = (object->*func)( input[0], input[1], input[2], - input[3], input[4], input[5] ); - break; - case 5: - err = (object->*func)( input[0], input[1], input[2], - input[3], input[4], - &output[0] ); - break; - case 4: - err = (object->*func)( input[0], input[1], input[2], - input[3], - &output[0], &output[1] ); - break; - case 3: - err = (object->*func)( input[0], input[1], input[2], - &output[0], &output[1], &output[2] ); - break; - case 2: - err = (object->*func)( input[0], input[1], - &output[0], &output[1], &output[2], - &output[3] ); - break; - case 1: - err = (object->*func)( input[0], - &output[0], &output[1], &output[2], - &output[3], &output[4] ); - break; - case 0: - err = (object->*func)( &output[0], &output[1], &output[2], - &output[3], &output[4], &output[5] ); - break; + args.asyncWakePort = MACH_PORT_NULL; + args.asyncReference = 0; + args.asyncReferenceCount = 0; - default: - IOLog("%s: Bad method table\n", client->getName()); - } - } while( false); + args.scalarInput = scalar_input; + args.scalarInputCount = scalar_inputCnt; + args.structureInput = inband_input; + args.structureInputSize = inband_inputCnt; - } else - err = kIOReturnUnsupported; + if (ool_input) + inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, + kIODirectionOut, current_task()); - return( err); + args.structureInputDescriptor = inputMD; + + args.scalarOutput = scalar_output; + args.scalarOutputCount = *scalar_outputCnt; + args.structureOutput = inband_output; + args.structureOutputSize = *inband_outputCnt; + + if (ool_output) + { + outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size, + kIODirectionIn, current_task()); + } + + args.structureOutputDescriptor = outputMD; + args.structureOutputDescriptorSize = *ool_output_size; + + ret = client->externalMethod( selector, &args ); + + *scalar_outputCnt = args.scalarOutputCount; + *inband_outputCnt = args.structureOutputSize; + *ool_output_size = args.structureOutputDescriptorSize; + + if (inputMD) + inputMD->release(); + if (outputMD) + outputMD->release(); + + return (ret); } -/* Routine io_connect_method_scalarI_structureO */ -kern_return_t is_io_connect_method_scalarI_structureO( - io_object_t connect, - UInt32 index, - void * input[], - IOByteCount inputCount, - void * output, - IOByteCount * outputCount ) +/* Routine io_async_user_client_method */ +kern_return_t is_io_connect_async_method +( + io_connect_t connection, + mach_port_t wake_port, + io_async_ref64_t reference, + mach_msg_type_number_t referenceCnt, + uint32_t selector, + io_scalar_inband64_t scalar_input, + mach_msg_type_number_t scalar_inputCnt, + io_struct_inband_t inband_input, + mach_msg_type_number_t inband_inputCnt, + mach_vm_address_t ool_input, + mach_vm_size_t ool_input_size, + io_scalar_inband64_t scalar_output, + mach_msg_type_number_t *scalar_outputCnt, + io_struct_inband_t inband_output, + mach_msg_type_number_t *inband_outputCnt, + mach_vm_address_t ool_output, + mach_vm_size_t * ool_output_size +) { - IOReturn err; - IOExternalMethod * method; - IOService * object; - IOMethod func; + CHECK( IOUserClient, connection, client ); - CHECK( IOUserClient, connect, client); + IOExternalMethodArguments args; + IOReturn ret; + IOMemoryDescriptor * inputMD = 0; + IOMemoryDescriptor * outputMD = 0; - if( (method = client->getTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIStructO != (method->flags & kIOUCTypeMask)) - continue; - if( inputCount != method->count0) - continue; - if( (0xffffffff != method->count1) - && (*outputCount != method->count1)) - continue; + bzero(&args.__reserved[0], sizeof(args.__reserved)); + args.version = kIOExternalMethodArgumentsCurrentVersion; - func = method->func; + reference[0] = (io_user_reference_t) wake_port; + if (vm_map_is_64bit(get_task_map(current_task()))) + reference[0] |= kIOUCAsync64Flag; - switch( inputCount) { + args.selector = selector; - case 5: - err = (object->*func)( input[0], input[1], input[2], - input[3], input[4], - output ); - break; - case 4: - err = (object->*func)( input[0], input[1], input[2], - input[3], - output, (void *)outputCount ); - break; - case 3: - err = (object->*func)( input[0], input[1], input[2], - output, (void *)outputCount, 0 ); - break; - case 2: - err = (object->*func)( input[0], input[1], - output, (void *)outputCount, 0, 0 ); - break; - case 1: - err = (object->*func)( input[0], - output, (void *)outputCount, 0, 0, 0 ); - break; - case 0: - err = (object->*func)( output, (void *)outputCount, 0, 0, 0, 0 ); - break; + args.asyncWakePort = wake_port; + args.asyncReference = reference; + args.asyncReferenceCount = referenceCnt; - default: - IOLog("%s: Bad method table\n", client->getName()); - } - } while( false); + args.scalarInput = scalar_input; + args.scalarInputCount = scalar_inputCnt; + args.structureInput = inband_input; + args.structureInputSize = inband_inputCnt; - } else - err = kIOReturnUnsupported; + if (ool_input) + inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, + kIODirectionOut, current_task()); - return( err); + args.structureInputDescriptor = inputMD; + + args.scalarOutput = scalar_output; + args.scalarOutputCount = *scalar_outputCnt; + args.structureOutput = inband_output; + args.structureOutputSize = *inband_outputCnt; + + if (ool_output) + { + outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size, + kIODirectionIn, current_task()); + } + + args.structureOutputDescriptor = outputMD; + args.structureOutputDescriptorSize = *ool_output_size; + + ret = client->externalMethod( selector, &args ); + + *inband_outputCnt = args.structureOutputSize; + *ool_output_size = args.structureOutputDescriptorSize; + + if (inputMD) + inputMD->release(); + if (outputMD) + outputMD->release(); + + return (ret); } -/* Routine io_connect_method_scalarI_structureI */ -kern_return_t is_io_connect_method_scalarI_structureI( - io_connect_t connect, - UInt32 index, - void * input[], - IOByteCount inputCount, - UInt8 * inputStruct, - IOByteCount inputStructCount ) +/* Routine io_connect_method_scalarI_scalarO */ +kern_return_t is_io_connect_method_scalarI_scalarO( + io_object_t connect, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_scalar_inband_t output, + mach_msg_type_number_t * outputCount ) +{ + IOReturn err; + uint32_t i; + io_scalar_inband64_t _input; + io_scalar_inband64_t _output; + + mach_msg_type_number_t struct_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + err = is_io_connect_method(connect, index, + _input, inputCount, + NULL, 0, + 0, 0, + _output, outputCount, + NULL, &struct_outputCnt, + 0, &ool_output_size); + + for (i = 0; i < *outputCount; i++) + output[i] = SCALAR32(_output[i]); + + return (err); +} + +kern_return_t shim_io_connect_method_scalarI_scalarO( + IOExternalMethod * method, + IOService * object, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_user_scalar_t * output, + mach_msg_type_number_t * outputCount ) { - IOReturn err; - IOExternalMethod * method; - IOService * object; IOMethod func; + io_scalar_inband_t _output; + IOReturn err; + err = kIOReturnBadArgument; - CHECK( IOUserClient, connect, client); + do { - if( (method = client->getTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIStructI != (method->flags & kIOUCTypeMask)) - continue; - if( (0xffffffff != method->count0) - && (inputCount != method->count0)) + if( inputCount != method->count0) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); continue; - if( (0xffffffff != method->count1) - && (inputStructCount != method->count1)) + } + if( *outputCount != method->count1) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); continue; + } func = method->func; switch( inputCount) { + case 6: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), ARG32(input[5]) ); + break; case 5: - err = (object->*func)( input[0], input[1], input[2], - input[3], input[4], - inputStruct ); + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), + &_output[0] ); break; case 4: - err = (object->*func)( input[0], input[1], input[2], - input[3], - inputStruct, (void *)inputStructCount ); + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), + &_output[0], &_output[1] ); break; case 3: - err = (object->*func)( input[0], input[1], input[2], - inputStruct, (void *)inputStructCount, - 0 ); + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + &_output[0], &_output[1], &_output[2] ); break; case 2: - err = (object->*func)( input[0], input[1], - inputStruct, (void *)inputStructCount, - 0, 0 ); + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), + &_output[0], &_output[1], &_output[2], + &_output[3] ); break; case 1: - err = (object->*func)( input[0], - inputStruct, (void *)inputStructCount, - 0, 0, 0 ); + err = (object->*func)( ARG32(input[0]), + &_output[0], &_output[1], &_output[2], + &_output[3], &_output[4] ); break; case 0: - err = (object->*func)( inputStruct, (void *)inputStructCount, - 0, 0, 0, 0 ); + err = (object->*func)( &_output[0], &_output[1], &_output[2], + &_output[3], &_output[4], &_output[5] ); break; default: - IOLog("%s: Bad method table\n", client->getName()); + IOLog("%s: Bad method table\n", object->getName()); } - } while( false); + } + while( false); - } else - err = kIOReturnUnsupported; + uint32_t i; + for (i = 0; i < *outputCount; i++) + output[i] = SCALAR32(_output[i]); return( err); } -/* Routine io_connect_method_structureI_structureO */ -kern_return_t is_io_connect_method_structureI_structureO( +/* Routine io_async_method_scalarI_scalarO */ +kern_return_t is_io_async_method_scalarI_scalarO( + io_object_t connect, + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_scalar_inband_t output, + mach_msg_type_number_t * outputCount ) +{ + IOReturn err; + uint32_t i; + io_scalar_inband64_t _input; + io_scalar_inband64_t _output; + io_async_ref64_t _reference; + + for (i = 0; i < referenceCnt; i++) + _reference[i] = REF64(reference[i]); + + mach_msg_type_number_t struct_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + err = is_io_connect_async_method(connect, + wake_port, _reference, referenceCnt, + index, + _input, inputCount, + NULL, 0, + 0, 0, + _output, outputCount, + NULL, &struct_outputCnt, + 0, &ool_output_size); + + for (i = 0; i < *outputCount; i++) + output[i] = SCALAR32(_output[i]); + + return (err); +} +/* Routine io_async_method_scalarI_structureO */ +kern_return_t is_io_async_method_scalarI_structureO( io_object_t connect, - UInt32 index, - UInt8 * input, - IOByteCount inputCount, - UInt8 * output, - IOByteCount * outputCount ) + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) { - IOReturn err; - IOExternalMethod * method; - IOService * object; - IOMethod func; - - CHECK( IOUserClient, connect, client); + uint32_t i; + io_scalar_inband64_t _input; + io_async_ref64_t _reference; + + for (i = 0; i < referenceCnt; i++) + _reference[i] = REF64(reference[i]); + + mach_msg_type_number_t scalar_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + return (is_io_connect_async_method(connect, + wake_port, _reference, referenceCnt, + index, + _input, inputCount, + NULL, 0, + 0, 0, + NULL, &scalar_outputCnt, + output, outputCount, + 0, &ool_output_size)); +} - if( (method = client->getTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCStructIStructO != (method->flags & kIOUCTypeMask)) - continue; - if( (0xffffffff != method->count0) - && (inputCount != method->count0)) - continue; - if( (0xffffffff != method->count1) - && (*outputCount != method->count1)) - continue; +/* Routine io_async_method_scalarI_structureI */ +kern_return_t is_io_async_method_scalarI_structureI( + io_connect_t connect, + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t inputStruct, + mach_msg_type_number_t inputStructCount ) +{ + uint32_t i; + io_scalar_inband64_t _input; + io_async_ref64_t _reference; + + for (i = 0; i < referenceCnt; i++) + _reference[i] = REF64(reference[i]); + + mach_msg_type_number_t scalar_outputCnt = 0; + mach_msg_type_number_t inband_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + return (is_io_connect_async_method(connect, + wake_port, _reference, referenceCnt, + index, + _input, inputCount, + inputStruct, inputStructCount, + 0, 0, + NULL, &scalar_outputCnt, + NULL, &inband_outputCnt, + 0, &ool_output_size)); +} - func = method->func; +/* Routine io_async_method_structureI_structureO */ +kern_return_t is_io_async_method_structureI_structureO( + io_object_t connect, + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + uint32_t index, + io_struct_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) +{ + uint32_t i; + mach_msg_type_number_t scalar_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + io_async_ref64_t _reference; + + for (i = 0; i < referenceCnt; i++) + _reference[i] = REF64(reference[i]); + + return (is_io_connect_async_method(connect, + wake_port, _reference, referenceCnt, + index, + NULL, 0, + input, inputCount, + 0, 0, + NULL, &scalar_outputCnt, + output, outputCount, + 0, &ool_output_size)); +} - if( method->count1) { - if( method->count0) { - err = (object->*func)( input, output, - (void *)inputCount, outputCount, 0, 0 ); - } else { - err = (object->*func)( output, outputCount, 0, 0, 0, 0 ); - } - } else { - err = (object->*func)( input, (void *)inputCount, 0, 0, 0, 0 ); - } - } while( false); +kern_return_t shim_io_async_method_scalarI_scalarO( + IOExternalAsyncMethod * method, + IOService * object, + mach_port_t asyncWakePort, + io_user_reference_t * asyncReference, + uint32_t asyncReferenceCount, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_user_scalar_t * output, + mach_msg_type_number_t * outputCount ) +{ + IOAsyncMethod func; + uint32_t i; + io_scalar_inband_t _output; + IOReturn err; + io_async_ref_t reference; - } else - err = kIOReturnUnsupported; + for (i = 0; i < asyncReferenceCount; i++) + reference[i] = REF32(asyncReference[i]); - return( err); -} + err = kIOReturnBadArgument; -kern_return_t is_io_async_method_scalarI_scalarO( - io_object_t connect, - mach_port_t wakePort, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, - UInt32 index, - void * input[], - IOByteCount inputCount, - void * output[], - IOByteCount * outputCount ) -{ - IOReturn err; - IOExternalAsyncMethod *method; - IOService * object; - IOAsyncMethod func; + do { - CHECK( IOUserClient, connect, client); - if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIScalarO != (method->flags & kIOUCTypeMask)) - continue; - if( inputCount != method->count0) - continue; - if( *outputCount != method->count1) - continue; + if( inputCount != method->count0) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( *outputCount != method->count1) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } - reference[0] = (natural_t) wakePort; - func = method->func; + func = method->func; switch( inputCount) { case 6: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], input[4], input[5] ); + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), ARG32(input[5]) ); break; case 5: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], input[4], - &output[0] ); + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), + &_output[0] ); break; case 4: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], - &output[0], &output[1] ); + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), + &_output[0], &_output[1] ); break; case 3: err = (object->*func)( reference, - input[0], input[1], input[2], - &output[0], &output[1], &output[2] ); + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + &_output[0], &_output[1], &_output[2] ); break; case 2: err = (object->*func)( reference, - input[0], input[1], - &output[0], &output[1], &output[2], - &output[3] ); + ARG32(input[0]), ARG32(input[1]), + &_output[0], &_output[1], &_output[2], + &_output[3] ); break; case 1: err = (object->*func)( reference, - input[0], - &output[0], &output[1], &output[2], - &output[3], &output[4] ); + ARG32(input[0]), + &_output[0], &_output[1], &_output[2], + &_output[3], &_output[4] ); break; case 0: err = (object->*func)( reference, - &output[0], &output[1], &output[2], - &output[3], &output[4], &output[5] ); + &_output[0], &_output[1], &_output[2], + &_output[3], &_output[4], &_output[5] ); break; default: - IOLog("%s: Bad method table\n", client->getName()); + IOLog("%s: Bad method table\n", object->getName()); } - } while( false); + } + while( false); - } else - err = kIOReturnUnsupported; + for (i = 0; i < *outputCount; i++) + output[i] = SCALAR32(_output[i]); return( err); } -kern_return_t is_io_async_method_scalarI_structureO( - io_object_t connect, - mach_port_t wakePort, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, - UInt32 index, - void * input[], - IOByteCount inputCount, - void * output, + +/* Routine io_connect_method_scalarI_structureO */ +kern_return_t is_io_connect_method_scalarI_structureO( + io_object_t connect, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) +{ + uint32_t i; + io_scalar_inband64_t _input; + + mach_msg_type_number_t scalar_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + return (is_io_connect_method(connect, index, + _input, inputCount, + NULL, 0, + 0, 0, + NULL, &scalar_outputCnt, + output, outputCount, + 0, &ool_output_size)); +} + +kern_return_t shim_io_connect_method_scalarI_structureO( + + IOExternalMethod * method, + IOService * object, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, IOByteCount * outputCount ) { + IOMethod func; IOReturn err; - IOExternalAsyncMethod *method; - IOService * object; + + err = kIOReturnBadArgument; + + do { + if( inputCount != method->count0) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (*outputCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } + + func = method->func; + + switch( inputCount) { + + case 5: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), + output ); + break; + case 4: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), + output, (void *)outputCount ); + break; + case 3: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + output, (void *)outputCount, 0 ); + break; + case 2: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), + output, (void *)outputCount, 0, 0 ); + break; + case 1: + err = (object->*func)( ARG32(input[0]), + output, (void *)outputCount, 0, 0, 0 ); + break; + case 0: + err = (object->*func)( output, (void *)outputCount, 0, 0, 0, 0 ); + break; + + default: + IOLog("%s: Bad method table\n", object->getName()); + } + } + while( false); + + return( err); +} + + +kern_return_t shim_io_async_method_scalarI_structureO( + IOExternalAsyncMethod * method, + IOService * object, + mach_port_t asyncWakePort, + io_user_reference_t * asyncReference, + uint32_t asyncReferenceCount, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) +{ IOAsyncMethod func; + uint32_t i; + IOReturn err; + io_async_ref_t reference; - CHECK( IOUserClient, connect, client); + for (i = 0; i < asyncReferenceCount; i++) + reference[i] = REF32(asyncReference[i]); - if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIStructO != (method->flags & kIOUCTypeMask)) - continue; - if( inputCount != method->count0) - continue; - if( (0xffffffff != method->count1) - && (*outputCount != method->count1)) - continue; + err = kIOReturnBadArgument; + do { + if( inputCount != method->count0) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (*outputCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } - reference[0] = (natural_t) wakePort; - func = method->func; + func = method->func; switch( inputCount) { case 5: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], input[4], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), output ); break; case 4: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), output, (void *)outputCount ); break; case 3: err = (object->*func)( reference, - input[0], input[1], input[2], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), output, (void *)outputCount, 0 ); break; case 2: err = (object->*func)( reference, - input[0], input[1], + ARG32(input[0]), ARG32(input[1]), output, (void *)outputCount, 0, 0 ); break; case 1: err = (object->*func)( reference, - input[0], + ARG32(input[0]), output, (void *)outputCount, 0, 0, 0 ); break; case 0: @@ -2198,78 +3349,176 @@ kern_return_t is_io_async_method_scalarI_structureO( break; default: - IOLog("%s: Bad method table\n", client->getName()); + IOLog("%s: Bad method table\n", object->getName()); } - } while( false); + } + while( false); - } else - err = kIOReturnUnsupported; + return( err); +} + +/* Routine io_connect_method_scalarI_structureI */ +kern_return_t is_io_connect_method_scalarI_structureI( + io_connect_t connect, + uint32_t index, + io_scalar_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t inputStruct, + mach_msg_type_number_t inputStructCount ) +{ + uint32_t i; + io_scalar_inband64_t _input; + + mach_msg_type_number_t scalar_outputCnt = 0; + mach_msg_type_number_t inband_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + for (i = 0; i < inputCount; i++) + _input[i] = SCALAR64(input[i]); + + return (is_io_connect_method(connect, index, + _input, inputCount, + inputStruct, inputStructCount, + 0, 0, + NULL, &scalar_outputCnt, + NULL, &inband_outputCnt, + 0, &ool_output_size)); +} + +kern_return_t shim_io_connect_method_scalarI_structureI( + IOExternalMethod * method, + IOService * object, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_struct_inband_t inputStruct, + mach_msg_type_number_t inputStructCount ) +{ + IOMethod func; + IOReturn err = kIOReturnBadArgument; + + do + { + if( (kIOUCVariableStructureSize != method->count0) + && (inputCount != method->count0)) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (inputStructCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } + + func = method->func; + + switch( inputCount) { + + case 5: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), + inputStruct ); + break; + case 4: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *) input[2], + ARG32(input[3]), + inputStruct, (void *)inputStructCount ); + break; + case 3: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + inputStruct, (void *)inputStructCount, + 0 ); + break; + case 2: + err = (object->*func)( ARG32(input[0]), ARG32(input[1]), + inputStruct, (void *)inputStructCount, + 0, 0 ); + break; + case 1: + err = (object->*func)( ARG32(input[0]), + inputStruct, (void *)inputStructCount, + 0, 0, 0 ); + break; + case 0: + err = (object->*func)( inputStruct, (void *)inputStructCount, + 0, 0, 0, 0 ); + break; + + default: + IOLog("%s: Bad method table\n", object->getName()); + } + } + while (false); return( err); } -kern_return_t is_io_async_method_scalarI_structureI( - io_connect_t connect, - mach_port_t wakePort, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, - UInt32 index, - void * input[], - IOByteCount inputCount, - UInt8 * inputStruct, - IOByteCount inputStructCount ) +kern_return_t shim_io_async_method_scalarI_structureI( + IOExternalAsyncMethod * method, + IOService * object, + mach_port_t asyncWakePort, + io_user_reference_t * asyncReference, + uint32_t asyncReferenceCount, + const io_user_scalar_t * input, + mach_msg_type_number_t inputCount, + io_struct_inband_t inputStruct, + mach_msg_type_number_t inputStructCount ) { - IOReturn err; - IOExternalAsyncMethod *method; - IOService * object; IOAsyncMethod func; + uint32_t i; + IOReturn err = kIOReturnBadArgument; + io_async_ref_t reference; - CHECK( IOUserClient, connect, client); + for (i = 0; i < asyncReferenceCount; i++) + reference[i] = REF32(asyncReference[i]); - if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCScalarIStructI != (method->flags & kIOUCTypeMask)) - continue; - if( (0xffffffff != method->count0) - && (inputCount != method->count0)) - continue; - if( (0xffffffff != method->count1) - && (inputStructCount != method->count1)) - continue; + do + { + if( (kIOUCVariableStructureSize != method->count0) + && (inputCount != method->count0)) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (inputStructCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } - reference[0] = (natural_t) wakePort; func = method->func; switch( inputCount) { case 5: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], input[4], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), ARG32(input[4]), inputStruct ); break; case 4: err = (object->*func)( reference, - input[0], input[1], input[2], - input[3], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), + ARG32(input[3]), inputStruct, (void *)inputStructCount ); break; case 3: err = (object->*func)( reference, - input[0], input[1], input[2], + ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), inputStruct, (void *)inputStructCount, 0 ); break; case 2: err = (object->*func)( reference, - input[0], input[1], + ARG32(input[0]), ARG32(input[1]), inputStruct, (void *)inputStructCount, 0, 0 ); break; case 1: err = (object->*func)( reference, - input[0], + ARG32(input[0]), inputStruct, (void *)inputStructCount, 0, 0, 0 ); break; @@ -2280,47 +3529,115 @@ kern_return_t is_io_async_method_scalarI_structureI( break; default: - IOLog("%s: Bad method table\n", client->getName()); + IOLog("%s: Bad method table\n", object->getName()); } - } while( false); - - } else - err = kIOReturnUnsupported; + } + while (false); return( err); } -kern_return_t is_io_async_method_structureI_structureO( - io_object_t connect, - mach_port_t wakePort, - io_async_ref_t reference, - mach_msg_type_number_t referenceCnt, - UInt32 index, - UInt8 * input, - IOByteCount inputCount, - UInt8 * output, +/* Routine io_connect_method_structureI_structureO */ +kern_return_t is_io_connect_method_structureI_structureO( + io_object_t connect, + uint32_t index, + io_struct_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) +{ + mach_msg_type_number_t scalar_outputCnt = 0; + mach_vm_size_t ool_output_size = 0; + + return (is_io_connect_method(connect, index, + NULL, 0, + input, inputCount, + 0, 0, + NULL, &scalar_outputCnt, + output, outputCount, + 0, &ool_output_size)); +} + +kern_return_t shim_io_connect_method_structureI_structureO( + IOExternalMethod * method, + IOService * object, + io_struct_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, IOByteCount * outputCount ) { - IOReturn err; - IOExternalAsyncMethod *method; - IOService * object; + IOMethod func; + IOReturn err = kIOReturnBadArgument; + + do + { + if( (kIOUCVariableStructureSize != method->count0) + && (inputCount != method->count0)) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (*outputCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } + + func = method->func; + + if( method->count1) { + if( method->count0) { + err = (object->*func)( input, output, + (void *)inputCount, outputCount, 0, 0 ); + } else { + err = (object->*func)( output, outputCount, 0, 0, 0, 0 ); + } + } else { + err = (object->*func)( input, (void *)inputCount, 0, 0, 0, 0 ); + } + } + while( false); + + + return( err); +} + +kern_return_t shim_io_async_method_structureI_structureO( + IOExternalAsyncMethod * method, + IOService * object, + mach_port_t asyncWakePort, + io_user_reference_t * asyncReference, + uint32_t asyncReferenceCount, + io_struct_inband_t input, + mach_msg_type_number_t inputCount, + io_struct_inband_t output, + mach_msg_type_number_t * outputCount ) +{ IOAsyncMethod func; + uint32_t i; + IOReturn err; + io_async_ref_t reference; - CHECK( IOUserClient, connect, client); + for (i = 0; i < asyncReferenceCount; i++) + reference[i] = REF32(asyncReference[i]); - if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) { - do { - err = kIOReturnBadArgument; - if( kIOUCStructIStructO != (method->flags & kIOUCTypeMask)) - continue; - if( (0xffffffff != method->count0) - && (inputCount != method->count0)) - continue; - if( (0xffffffff != method->count1) - && (*outputCount != method->count1)) - continue; + err = kIOReturnBadArgument; + do + { + if( (kIOUCVariableStructureSize != method->count0) + && (inputCount != method->count0)) + { + IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + continue; + } + if( (kIOUCVariableStructureSize != method->count1) + && (*outputCount != method->count1)) + { + IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + continue; + } - reference[0] = (natural_t) wakePort; func = method->func; if( method->count1) { @@ -2336,21 +3653,19 @@ kern_return_t is_io_async_method_structureI_structureO( err = (object->*func)( reference, input, (void *)inputCount, 0, 0, 0, 0 ); } - - } while( false); - - } else - err = kIOReturnUnsupported; + } + while( false); return( err); } + /* Routine io_make_matching */ kern_return_t is_io_make_matching( - mach_port_t master_port, - UInt32 type, - IOOptionBits options, - UInt8 * input, - IOByteCount inputCount, + mach_port_t master_port, + uint32_t type, + uint32_t options, + io_struct_inband_t input, + mach_msg_type_number_t inputCount, io_string_t matching ) { OSSerialize * s; @@ -2398,9 +3713,9 @@ kern_return_t is_io_make_matching( err = kIOReturnNoMemory; continue; } else - strcpy( matching, s->text()); - - } while( false); + strlcpy(matching, s->text(), sizeof(io_string_t)); + } + while( false); if( s) s->release(); @@ -2413,10 +3728,10 @@ kern_return_t is_io_make_matching( /* Routine io_catalog_send_data */ kern_return_t is_io_catalog_send_data( mach_port_t master_port, - int flag, + uint32_t flag, io_buf_ptr_t inData, mach_msg_type_number_t inDataCount, - natural_t * result) + kern_return_t * result) { OSObject * obj = 0; vm_offset_t data; @@ -2427,12 +3742,20 @@ kern_return_t is_io_catalog_send_data( if( master_port != master_device_port) return kIOReturnNotPrivileged; - // FIXME: This is a hack. Should have own function for removeKernelLinker() - if(flag != kIOCatalogRemoveKernelLinker && ( !inData || !inDataCount) ) + if( (flag != kIOCatalogRemoveKernelLinker && + flag != kIOCatalogKextdActive && + flag != kIOCatalogKextdFinishedLaunching) && + ( !inData || !inDataCount) ) + { return kIOReturnBadArgument; + } + + if (inData) { + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData); + data = CAST_DOWN(vm_offset_t, map_data); - if (data) { - kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t)inData); if( kr != KERN_SUCCESS) return kr; @@ -2498,12 +3821,35 @@ kern_return_t is_io_catalog_send_data( } break; - case kIOCatalogRemoveKernelLinker: { - if (gIOCatalogue->removeKernelLinker() != KERN_SUCCESS) { - kr = kIOReturnError; - } else { - kr = kIOReturnSuccess; + case kIOCatalogRemoveKernelLinker: + kr = KERN_NOT_SUPPORTED; + break; + + case kIOCatalogKextdActive: +#if !NO_KEXTD + OSKext::setKextdActive(); + + /* Dump all nonloaded startup extensions; kextd will now send them + * down on request. + */ + OSKext::flushNonloadedKexts( /* flushPrelinkedKexts */ false); +#endif + kr = kIOReturnSuccess; + break; + + case kIOCatalogKextdFinishedLaunching: { +#if !NO_KEXTD + static bool clearedBusy = false; + + if (!clearedBusy) { + IOService * serviceRoot = IOService::getServiceRoot(); + if (serviceRoot) { + serviceRoot->adjustBusy(-1); + clearedBusy = true; + } } +#endif + kr = kIOReturnSuccess; } break; @@ -2521,7 +3867,7 @@ kern_return_t is_io_catalog_send_data( /* Routine io_catalog_terminate */ kern_return_t is_io_catalog_terminate( mach_port_t master_port, - int flag, + uint32_t flag, io_name_t name ) { kern_return_t kr; @@ -2576,7 +3922,7 @@ kern_return_t is_io_catalog_terminate( /* Routine io_catalog_get_data */ kern_return_t is_io_catalog_get_data( mach_port_t master_port, - int flag, + uint32_t flag, io_buf_ptr_t *outData, mach_msg_type_number_t *outDataCount) { @@ -2593,17 +3939,8 @@ kern_return_t is_io_catalog_get_data( return kIOReturnNoMemory; s->clearText(); - switch ( flag ) { - case kIOCatalogGetContents: - if ( !gIOCatalogue->serialize(s) ) { - kr = kIOReturnNoMemory; - } - break; - default: - kr = kIOReturnBadArgument; - break; - } + kr = gIOCatalogue->serializeData(flag, s); if ( kr == kIOReturnSuccess ) { vm_offset_t data; @@ -2611,10 +3948,11 @@ kern_return_t is_io_catalog_get_data( vm_size_t size; size = s->getLength(); - kr = vm_allocate(kernel_map, &data, size, true); + kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE); if ( kr == kIOReturnSuccess ) { bcopy(s->text(), (void *)data, size); - kr = vm_map_copyin(kernel_map, data, size, true, ©); + kr = vm_map_copyin(kernel_map, (vm_map_address_t)data, + (vm_map_size_t)size, true, ©); *outData = (char *)copy; *outDataCount = size; } @@ -2628,7 +3966,7 @@ kern_return_t is_io_catalog_get_data( /* Routine io_catalog_get_gen_count */ kern_return_t is_io_catalog_get_gen_count( mach_port_t master_port, - int *genCount) + uint32_t *genCount) { if( master_port != master_device_port) return kIOReturnNotPrivileged; @@ -2643,7 +3981,9 @@ kern_return_t is_io_catalog_get_gen_count( return kIOReturnSuccess; } -/* Routine io_catalog_module_loaded */ +/* Routine io_catalog_module_loaded. + * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used. + */ kern_return_t is_io_catalog_module_loaded( mach_port_t master_port, io_name_t name) @@ -2663,7 +4003,7 @@ kern_return_t is_io_catalog_module_loaded( kern_return_t is_io_catalog_reset( mach_port_t master_port, - int flag) + uint32_t flag) { if( master_port != master_device_port) return kIOReturnNotPrivileged; @@ -2680,19 +4020,17 @@ kern_return_t is_io_catalog_reset( return kIOReturnSuccess; } -kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index, - void *p1, void *p2, void *p3, - void *p4, void *p5, void *p6) +kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args) { kern_return_t result = kIOReturnBadArgument; IOUserClient *userClient; if ((userClient = OSDynamicCast(IOUserClient, - iokit_lookup_connect_ref_current_task(userClientRef)))) { + iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) { IOExternalTrap *trap; IOService *target = NULL; - trap = userClient->getTargetAndTrapForIndex(&target, index); + trap = userClient->getTargetAndTrapForIndex(&target, args->index); if (trap && target) { IOTrap func; @@ -2700,7 +4038,7 @@ kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index, func = trap->func; if (func) { - result = (target->*func)(p1, p2, p3, p4, p5, p6); + result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6); } } @@ -2710,10 +4048,178 @@ kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index, return result; } +IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args, + IOExternalMethodDispatch * dispatch, OSObject * target, void * reference ) +{ + IOReturn err; + IOService * object; + IOByteCount structureOutputSize; + + if (dispatch) + { + uint32_t count; + count = dispatch->checkScalarInputCount; + if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) + { + return (kIOReturnBadArgument); + } + + count = dispatch->checkStructureInputSize; + if ((kIOUCVariableStructureSize != count) + && (count != ((args->structureInputDescriptor) + ? args->structureInputDescriptor->getLength() : args->structureInputSize))) + { + return (kIOReturnBadArgument); + } + + count = dispatch->checkScalarOutputCount; + if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) + { + return (kIOReturnBadArgument); + } + + count = dispatch->checkStructureOutputSize; + if ((kIOUCVariableStructureSize != count) + && (count != ((args->structureOutputDescriptor) + ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) + { + return (kIOReturnBadArgument); + } + + if (dispatch->function) + err = (*dispatch->function)(target, reference, args); + else + err = kIOReturnNoCompletion; /* implementator can dispatch */ + + return (err); + } + + + // pre-Leopard API's don't do ool structs + if (args->structureInputDescriptor || args->structureOutputDescriptor) + { + err = kIOReturnIPCError; + return (err); + } + + structureOutputSize = args->structureOutputSize; + + if (args->asyncWakePort) + { + IOExternalAsyncMethod * method; + + if( !(method = getAsyncTargetAndMethodForIndex(&object, selector)) ) + return (kIOReturnUnsupported); + + if (kIOUCForegroundOnly & method->flags) + { + bool isBg; + kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg); + + if ((KERN_SUCCESS == kr) && isBg) + return (kIOReturnNotPermitted); + } + + switch (method->flags & kIOUCTypeMask) + { + case kIOUCScalarIStructI: + err = shim_io_async_method_scalarI_structureI( method, object, + args->asyncWakePort, args->asyncReference, args->asyncReferenceCount, + args->scalarInput, args->scalarInputCount, + (char *)args->structureInput, args->structureInputSize ); + break; + + case kIOUCScalarIScalarO: + err = shim_io_async_method_scalarI_scalarO( method, object, + args->asyncWakePort, args->asyncReference, args->asyncReferenceCount, + args->scalarInput, args->scalarInputCount, + args->scalarOutput, &args->scalarOutputCount ); + break; + + case kIOUCScalarIStructO: + err = shim_io_async_method_scalarI_structureO( method, object, + args->asyncWakePort, args->asyncReference, args->asyncReferenceCount, + args->scalarInput, args->scalarInputCount, + (char *) args->structureOutput, &args->structureOutputSize ); + break; + + + case kIOUCStructIStructO: + err = shim_io_async_method_structureI_structureO( method, object, + args->asyncWakePort, args->asyncReference, args->asyncReferenceCount, + (char *)args->structureInput, args->structureInputSize, + (char *) args->structureOutput, &args->structureOutputSize ); + break; + + default: + err = kIOReturnBadArgument; + break; + } + } + else + { + IOExternalMethod * method; + + if( !(method = getTargetAndMethodForIndex(&object, selector)) ) + return (kIOReturnUnsupported); + + if (kIOUCForegroundOnly & method->flags) + { + bool isBg; + kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg); + + if ((KERN_SUCCESS == kr) && isBg) + return (kIOReturnNotPermitted); + } + + switch (method->flags & kIOUCTypeMask) + { + case kIOUCScalarIStructI: + err = shim_io_connect_method_scalarI_structureI( method, object, + args->scalarInput, args->scalarInputCount, + (char *) args->structureInput, args->structureInputSize ); + break; + + case kIOUCScalarIScalarO: + err = shim_io_connect_method_scalarI_scalarO( method, object, + args->scalarInput, args->scalarInputCount, + args->scalarOutput, &args->scalarOutputCount ); + break; + + case kIOUCScalarIStructO: + err = shim_io_connect_method_scalarI_structureO( method, object, + args->scalarInput, args->scalarInputCount, + (char *) args->structureOutput, &structureOutputSize ); + break; + + + case kIOUCStructIStructO: + err = shim_io_connect_method_structureI_structureO( method, object, + (char *) args->structureInput, args->structureInputSize, + (char *) args->structureOutput, &structureOutputSize ); + break; + + default: + err = kIOReturnBadArgument; + break; + } + } + + args->structureOutputSize = structureOutputSize; + + return (err); +} + + }; /* extern "C" */ +#if __LP64__ OSMetaClassDefineReservedUnused(IOUserClient, 0); OSMetaClassDefineReservedUnused(IOUserClient, 1); +#else +OSMetaClassDefineReservedUsed(IOUserClient, 0); +OSMetaClassDefineReservedUsed(IOUserClient, 1); +#endif OSMetaClassDefineReservedUnused(IOUserClient, 2); OSMetaClassDefineReservedUnused(IOUserClient, 3); OSMetaClassDefineReservedUnused(IOUserClient, 4);