/*
* Copyright (c) 2015-2016 Apple Computer, 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@
*/
/*
* File: kern/mach_node_link.h
* Author: Dean Reece
* Date: 2016
*
* This header provides definitions required by Mach Node Link (MNL) drivers.
* MNL drivers pass messages between nodes within a host.
*
* The constructs available at the node link level are very basic:
* Node IDs (mach_node_id_t) uniquely identify nodes within a host.
* MNL Info (mnl_node_info) describe the static characteristics of a node.
* MNL Names (mnl_name_t) uniquely identify abjects across all nodes.
* MNL Messages (mnl_msg) are passed between nodes (kernels) within a host.
*/
#ifndef _KERN_MACH_NODE_LINK_H_
#define _KERN_MACH_NODE_LINK_H_
#if KERNEL_PRIVATE
#include <sys/cdefs.h>
__BEGIN_DECLS
/*** Node Info Section ***/
typedef int mach_node_id_t; // Used to uniquely identify a node
extern mach_node_id_t localnode_id; // This node's unique id.
/* An mnl_node struct describes static characteristcs of a node. The link
* driver requests this structure from the mach_node layer and fills out
* the fields. All fields must be filled in (non-zero) before both rx and tx
* links are brought up.
*/
typedef struct mnl_node_info {
mach_node_id_t node_id; // The node ID of this node
uint8_t datamodel; // 1==ILP32, 2==LP64 (matches dtrace)
uint8_t byteorder; // See libkern/OSByteOrder.h
uint32_t proto_vers_min;// Oldest MNL protocol vers node can accept
uint32_t proto_vers_max;// Newest MNL protocol vers node can accept
} __attribute__ ((aligned(8))) * mnl_node_info_t;
#define MNL_NODE_NULL ((mnl_node_info_t) 0UL)
#define MNL_NODE_VALID(n) ((n) != MNL_NODE_NULL)
#define MNL_PROTOCOL_V1 (1UL) // Current Node Link Protocol Version
/*** Mach Node Link Name Section
*
* A node link name (mnl_name_t) is an oqaque value guaranteed unique across
* kernel instances on all nodes.
*/
typedef uint64_t mnl_name_t;
/*** Mach Node Link Message Section ***/
/* This structure is the header for an MNL Message buffer; the actual buffer
* is normally larger, and holds this header followed by the body of the
* message to be transmitted over the link.
*
* Note: The <node_id> and <size> fields are in host-native byte order when
* passed to mnl_msg_from_node() and from mnl_msg_to_node().
* The byte order of these fields as sent over the link is left to the link
* specification. The link drivers on both sides must translate these fields
* between the link's byte order and host-native byte order.
*
* The body of the message, however, is treated as a byte-stream and passed
* to/from the mach_node layer without any introspection or byte reordering.
*/
typedef struct mnl_msg {
uint8_t sub; // 8b subsystem code
uint8_t cmd; // 8b command code
uint8_t qos; // 8b TODO: Doesn't do anything yet
uint8_t flags; // 8b Command-specific flag byte
uint32_t node_id;// 32b id of node that originated message
mnl_name_t object; // 64b object ref (use is determined by sub & cmd)
uint32_t options;// 32b Currently unused
uint32_t size; // 32b Number of bytes that follow mnl_msg header
} __attribute__((__packed__)) * mnl_msg_t;
/* Allocate a mnl_msg struct plus additional payload. Link drivers are not
* required to use this to allocate messages; any wired and mapped kernel
* memory is acceptable.
*
* Arguments:
* payload Number of additional bytes to allocate for message payload
* flags Currently unused; 0 should be passed
*
* Return values:
* MNL_MSG_NULL: Allocation failed
* *: Pointer to new mnl_msg struct of requested size
*/
mnl_msg_t mnl_msg_alloc(int payload, uint32_t flags);
/* Free a mnl_msg struct allocated by mnl_msg_alloc().
*
* Arguments:
* msg Pointer to the message buffer to be freed
* flags Currently unused; 0 should be passed
*/
void mnl_msg_free(mnl_msg_t msg, uint32_t flags);
#define MNL_MSG_NULL ((mnl_msg_t) 0UL)
#define MNL_MSG_VALID(msg) ((msg) != MNL_MSG_NULL)
#define MNL_MSG_SIZE ((vm_offset_t)sizeof(struct mnl_msg))
#define MNL_MSG_PAYLOAD(msg) ((vm_offset_t)(msg) + MNL_MSG_SIZE)
/*** Mach Node Link Driver Interface Section ***/
/* The link driver calls this to setup a new (or restarted) node, and to get
* an mnl_node_info struct for use as a parameter to other mnl functions.
* If MNL_NODE_NULL is returned, the operation failed. Otherwise, a pointer
* to a new mnl_node struct is returned. The caller should set all fields
* in the structure, then call mnl_register() to complete node registration.
*
* Arguments:
* nid The id of the node to be instantiated
* flags Currently unused; 0 should be passed
*
* Return values:
* MNL_NODE_NULL: Operation failed
* *: Pointer to a new mnl_node struct
*/
mnl_node_info_t mnl_instantiate(mach_node_id_t nid,
uint32_t flags);
/* The link driver calls mnl_register() to complete the node registration
* process. KERN_SUCCESS is returned if registration succeeded, otherwise
* an error is returned.
*
* Arguments:
* node Pointer to the node's mnl_node structure
* flags Currently unused; 0 should be passed
*
* Return values:
* KERN_SUCCESS: Registration succeeded
* KERN_INVALID_ARGUMENT: Field(s) in <node> contained unacceptable values
* KERN_*: Values returned from underlying functions
*/
kern_return_t mnl_register(mnl_node_info_t node,
uint32_t flags);
/* The link driver calls this to report that the link has been raised in one
* or both directions. If the link is two uni-directional channels, each link
* driver will independently call this function, each only raising the link
* they are responsible for. The mach_node layer will not communicate with
* the remote node until both rx and tx links are up.
*
* Arguments:
* node Pointer to the node's mnl_node structure
* link Indicates which link(s) are up (see MNL_LINK_* defines)
* flags Currently unused; 0 should be passed
*
* Return values:
* KERN_SUCCESS: Link state changed successfully.
* KERN_INVALID_ARGUMENT: An argument value was not allowed.
* KERN_*: Values returned from underlying functions.
*/
kern_return_t mnl_set_link_state(mnl_node_info_t node,
int link,
uint32_t flags);
#define MNL_LINK_DOWN (0UL)
#define MNL_LINK_RX (1UL)
#define MNL_LINK_TX (2UL)
#define MNL_LINK_UP (MNL_LINK_RX|MNL_LINK_TX)
/* The link driver calls this to indicate a node has terminated and is no
* longer available for messaging. This may be due to a crash or an orderly
* shutdown, but either way the remote node no longer retains any state about
* the remaining nodes. References held on behalf of the terminated node
* will be cleaned up. After this is called, both the rx and tx links are
* marked as down. If the remote node restarts, the link driver can bring
* up the link using mnl_instantiate() again.
*
* Arguments:
* node Pointer to the node's mnl_node structure
* flags Currently unused; 0 should be passed
*
* Return values:
* KERN_SUCCESS: Node was terminated.
* KERN_INVALID_ARGUMENT: Node id was invalid or non-existant.
* KERN_*: Values returned from underlying functions.
*/
kern_return_t mnl_terminate(mnl_node_info_t node,
uint32_t flags);
/* The link driver calls this to deliver an incoming message. Note that the
* link driver must dispose of the memory pointed to by <msg> after the
* function call returns.
*
* Arguments:
* node Pointer to the node's mnl_node structure
* msg Pointer to the message buffer
* flags Currently unused; 0 should be passed
*/
void mnl_msg_from_node(mnl_node_info_t node,
mnl_msg_t msg,
uint32_t flags);
/* The link driver calls this to fetch the next message to transmit.
* This function will block until a message is available, or will return
* FLIPC_MSG_NULL if the link is to be terminated. After the caller has
* completed the transmission and no longer needs the msg buffer, it should
* call mnl_msg_complete().
*
* Arguments:
* node Pointer to the node's mnl_node structure
* flags Currently unused; 0 should be passed
*/
mnl_msg_t mnl_msg_to_node(mnl_node_info_t node,
uint32_t flags);
/* The link driver calls this to indicate that the specified msg buffer has
* been sent over the link and can be deallocated.
*
* Arguments:
* node Pointer to the node's mnl_node structure
* msg Pointer to the message buffer
* flags Currently unused; 0 should be passed
*/
void mnl_msg_complete(mnl_node_info_t node,
mnl_msg_t msg,
uint32_t flags);
__END_DECLS
#endif /* KERNEL_PRIVATE */
#endif /* _KERN_MACH_NODE_LINK_H_ */