This is xnu-8019. See this file in:
/*
 * Copyright (c) 2019-2019 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * 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.
 *
 * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

#if !__IIG
#if KERNEL
#include <IOKit/IOUserClient.h>
#endif
#endif

#ifndef _IOKIT_UIOUSERCLIENT_H
#define _IOKIT_UIOUSERCLIENT_H

#include <DriverKit/OSAction.iig>
#include <DriverKit/IOService.iig>
#include <DriverKit/IOBufferMemoryDescriptor.iig>


enum {
	kIOUserClientScalarArrayCountMax  = 16,
};
typedef uint64_t IOUserClientScalarArray[kIOUserClientScalarArrayCountMax];

enum {
	kIOUserClientAsyncReferenceCountMax  = 16,
};
typedef uint64_t IOUserClientAsyncReferenceArray[kIOUserClientAsyncReferenceCountMax];

enum {
	kIOUserClientAsyncArgumentsCountMax  = 16,
};
typedef uint64_t IOUserClientAsyncArgumentsArray[kIOUserClientAsyncArgumentsCountMax];

// CopyClientMemoryForType options
enum {
	kIOUserClientMemoryReadOnly  = 0x00000001,
};

#define kIOUserClientQueueNameExternalMethod  "IOUserClientQueueExternalMethod"


/*! @enum
 *   @abstract Constant to denote a variable length structure argument to IOUserClient.
 *   @constant kIOUserClientVariableStructureSize Use in the structures IOUserClientMethodDispatch to specify the size of the structure is variable.
 */
enum {
	kIOUserClientVariableStructureSize = 0xffffffff
};


enum {
#define IO_USER_CLIENT_METHOD_ARGUMENTS_CURRENT_VERSION    2
	kIOUserClientMethodArgumentsCurrentVersion = IO_USER_CLIENT_METHOD_ARGUMENTS_CURRENT_VERSION
};

/*!
 * @struct      IOUserClientMethodArguments
 * @brief       Holds arguments from IOKit.framework IOConnectMethod calls.
 * @discussion  Any argument may be passed as NULL if not passed by the caller.
 * @field       selector Selector argument to IOConnectMethod.
 * @field       scalarInput Array of scalars from caller.
 * @field       scalarInputCount Count of valid scalars in scalarInput.
 * @field       structureInput OSData object containing structure input from IOConnectMethod.
 * @field       structureInputDescriptor IOMemoryDescriptor containing structure input from IOConnectMethod.
 *				This parameter is only set for large structures, and if set structureInput will be NULL.
 * @field       scalarOutput Array of scalars to return to the caller.
 * @field       scalarOutputCount Count of scalars to return to the caller in scalarOutput.
 * @field       structureOutput An OSData to be returned to the caller as structure output.
 *              This field should be set by the driver to an OSData object it created with
 *              the data to be returned, and the OSData instance will be released by the OS.
 *              It is an error for the driver to set this field if structureOutputDescriptor was passed in
 * @field       structureOutputDescriptor A IOMemoryDescriptor specified by the caller for structure output.
 * @field       structureOutputMaximumSize Maximum size of structure output specified by caller
 *              or kIOUserClientVariableStructureSize.
 * @field       completion For IOConnectAsyncMethod, an OSAction used to deliver async data to the caller.
 *              It is only retained during the invocation of ExternalMethod and should be retained if
 *              used beyond then.
 */

struct IOUserClientMethodArguments {
	uint64_t            			version;
	uint64_t                        selector;
	OSAction                      * completion;
    const uint64_t			      * scalarInput;
	uint32_t						scalarInputCount;
	OSData 						  * structureInput;
	IOMemoryDescriptor            * structureInputDescriptor;
	uint64_t                      * scalarOutput;
	uint32_t                        scalarOutputCount;
	OSData                        * structureOutput;
	IOMemoryDescriptor            * structureOutputDescriptor;
	uint64_t                        structureOutputMaximumSize;
	uint64_t                        __reserved[30];
};

typedef kern_return_t (*IOUserClientMethodFunction)(
	OSObject * target,
	void * reference,
    IOUserClientMethodArguments * arguments);

/*!
 * @struct      IOUserClientMethodDispatch
 * @brief       Used to check fields in IOUserClientMethodArguments
 * @field       function to invoke after making the checks specified below. If NULL and all checks pass,
 *              kIOReturnNoCompletion will be returned for the caller to implement the method.
 * @field       checkCompletionExists
 *              if true completion field must be set,
 *              if false must be zero,
 *              if -1U don't care
 * @field       checkScalarInputCount
 *              if has value kIOUserClientVariableStructureSize don't care,
 *              otherwise must equal args->scalarInputCount
 * @field       checkStructureInputSize
 *              if has value kIOUserClientVariableStructureSize don't care,
 *              otherwise must equal length of structureInput or structureInputDescriptor
 * @field       checkScalarOutputCount
 *              if has value kIOUserClientVariableStructureSize don't care,
 *              otherwise must equal args->scalarOutputCount
 * @field       checkStructureOutputSize
 *              if has value kIOUserClientVariableStructureSize don't care,
 *              otherwise must equal length of structureOutputMaximumSize
 */

struct IOUserClientMethodDispatch {
	IOUserClientMethodFunction function;
	uint32_t			       checkCompletionExists;
	uint32_t			       checkScalarInputCount;
	uint32_t			       checkStructureInputSize;
	uint32_t			       checkScalarOutputCount;
	uint32_t			       checkStructureOutputSize;
};

/*!
 * @class IOUserClient
 *
 * @abstract
 * IOUserClient represents a connection opened by IOServiceOpen in the IOKit.framework.
 *
 * @discussion
 * An application may open an IOUserClient by calling IOServiceOpen(). This results in a call
 * to the IOService::NewUserClient API to create an instance representing the connection.
 * and to receive untyped data via IOConnectMethod/IOConnectAsyncMethod.
 * As an IOService subclass, IOUserClient receives the normal Start()/Stop() lifecyle calls.
 *

@iig implementation
#include <DriverKit/IOBufferMemoryDescriptor.h>
@iig end
*/

class KERNEL IOUserClient : public IOService
{
public:
	virtual bool
	init() override;

	virtual void
	free() override;

	/*!
	 * @brief       Receive arguments from IOKit.framework IOConnectMethod calls.
	 * @discussion  IOConnectMethod calls from the owner of the connection come here.
	 *              Any argument may be passed as NULL if not passed by the caller.
	 *              The method runs on a queue set by IOService::SetDispatchQueuue()
	 *              with the name kIOUserClientQueueNameExternalMethod, or the default
	 *              queue for the IOUserClient object if one was not set.
	 * @param       selector Selector argument to IOConnectMethod.
	 * @param       arguments Structure describing all arguments being passed to IOConnectMethod.
	 * 				          See the IOUserClientMethodArguments definition.
	 * @param       dispatch NULL when called in the driver. The IOUserClient::ExternalMethod()
	 *				         implementation may be called with a non-NULL argument to check
	 *				         certain fields of the arguments structure before calling a target procedure
	 *				         specified by the dispatch structure 'function' field, and the
	 *				         'target' and 'reference' parameters to this method.
	 *				         See the IOUserClientMethodDispatch definition.
	 * @param       target Target for the dispatch function
	 * @param       reference Reference constant for the dispatch function
	 * @return      kIOReturnSuccess on success. See IOReturn.h for error codes.
	 */

	virtual kern_return_t
	ExternalMethod(
		uint64_t                            selector,
	    IOUserClientMethodArguments       * arguments,
	    const IOUserClientMethodDispatch  * dispatch,
	    OSObject                          * target,
	    void                              * reference) LOCALONLY
	QUEUENAME(IOUserClientQueueExternalMethod);


    /*!
     * @brief       Send asynchronous arguments to a completion supplied by ExternalMethod().
     * @discussion  IOConnectAsyncMethod calls from the owner of the connection come will pass an OSAction instance.
     *              To deliver the asynchronous results the driver calls AsyncCompletion().
     * @param       action OSAction passed to IOExternalMethod().
     * @param       status An IOReturn status value to be sent.
     * @param       asyncData An array of scalar data to be sent.
     * @param       asyncDataCount Count of valid data in asyncData.
     */
    virtual void
    AsyncCompletion(
        OSAction                            * action TARGET,
        IOReturn                              status,
        const IOUserClientAsyncArgumentsArray asyncData,
		uint32_t                              asyncDataCount) = 0;

    /*!
     * @brief       Return an IOMemoryDescriptor to be mapped into the client task.
     * @discussion  IOConnectMapMemory()/UnmapMemory() will result in a call to this method to obtain
     *              an IOMemoryDescriptor instance for shared memory. For a given IOUserClient instance, calling
     *              CopyClientMemoryForType() with a given type, should return the same IOMemoryDescriptor instance.
     * @param       type Type parameter IOConnectMapMemory()/UnmapMemory().
     * @param       options Set kIOUserClientMemoryReadOnly for memory to be mapped read only in the client.
     * @param       memory An instance of IOMemoryDescriptor on success. One reference will be consumed by the caller
     *              of this method.
     * @return      kIOReturnSuccess on success. See IOReturn.h for error codes.
     */
	virtual kern_return_t
	CopyClientMemoryForType(
		uint64_t                              type,
	    uint64_t                            * options,
	    IOMemoryDescriptor                 ** memory) = 0;

    /*!
     * @brief       Create a memory descriptor that describes a set of virtual ranges in
     *              the client task of the user client.
     * @param       memoryDescriptorCreateOptions
	 *              kIOMemoryDirectionIn memory described will be writable
	 *              kIOMemoryDirectionOut memory described will be readable
	 * @param       segmentsCount Number of valid address ranges being passed
	 *              in the segments array.
	 * @param       segments Array of address ranges.
	 * @param       memory Returned IOMemoryDescriptor object with +1 retain count.
     * @return      kIOReturnSuccess on success. See IOReturn.h for error codes.
     */
	virtual kern_return_t
	CreateMemoryDescriptorFromClient(
		uint64_t memoryDescriptorCreateOptions,
		uint32_t segmentsCount,
		const IOAddressSegment segments[32],
		IOMemoryDescriptor ** memory) __attribute__((availability(driverkit,introduced=20.0)));

   /*!
    * @function CopyClientEntitlements
    * @abstract Return owning task's entitlements dictionary.
    * @param    entitlements Dictionary of entitlements given to the owning task. To be released by caller.
    * @return   kIOReturnSuccess on success. See IOReturn.h for error codes.
	*/
	virtual kern_return_t
	CopyClientEntitlements(OSDictionary ** entitlements) LOCAL;


private:
	virtual kern_return_t
	_ExternalMethod(
		uint64_t                              selector,
		const IOUserClientScalarArray		  scalarInput,
		uint32_t							  scalarInputCount,
		OSData 							    * structureInput,
		IOMemoryDescriptor                  * structureInputDescriptor,
		IOUserClientScalarArray               scalarOutput,
		uint32_t                            * scalarOutputCount,
		uint64_t                              structureOutputMaximumSize,
		OSData                             ** structureOutput,
		IOMemoryDescriptor                  * structureOutputDescriptor,
        OSAction                            * completion TYPE(IOUserClient::AsyncCompletion)) LOCAL
	QUEUENAME(IOUserClientQueueExternalMethod);

    virtual void
    KernelCompletion(
        OSAction                            * action TARGET,
        IOReturn                              status,
        const IOUserClientAsyncArgumentsArray asyncData,
		uint32_t                              asyncDataCount)
        KERNEL
        TYPE(IOUserClient::AsyncCompletion);
};

#endif /* ! _IOKIT_UIOUSERCLIENT_H */