/*
 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU Lesser General
 * Public License.  You may obtain a copy of the GNU Lesser General
 * Public License Version 2.1 or later at the following locations:
 *
 * http://www.opensource.org/licenses/lgpl-license.html
 * http://www.gnu.org/copyleft/lgpl.html
 */

#ifndef SHW_DRIVER_H
#define SHW_DRIVER_H

/* This is a Linux flag meaning 'compiling kernel code'...  */
#ifndef __KERNEL__
#include <inttypes.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <memory.h>
#include <stdio.h>
#else
#include "portable_os.h"
#endif				/* __KERNEL__ */

#include "fsl_platform.h"

/*! @file shw_driver.h
 *
 * @brief Header file to use the SHW driver.
 *
 * The SHW driver is used in two modes: By a user, from the FSL SHW API in user
 * space, which goes through /dev/fsl_shw to make open(), ioctl(), and close()
 * calls; and by other kernel modules/drivers, which use the FSL SHW API, parts
 * of which are supported directly by the SHW driver.
 *
 * Testing is performed by using the apitest and kernel api test routines
 * developed for the Sahara2 driver.
  */
/*#define DIAG_SECURITY_FUNC*/
/*! Perform a security function.  */
#define SHW_IOCTL_REQUEST 21

/* This definition may need a new name, and needs to go somewhere which
 * can determine platform, kernel vs. user, os, etc.
 */
#define copy_bytes(out, in, len) memcpy(out, in, len)


/*!
 * This is part of the IOCTL request type passed between kernel and user space.
 * It is added to #SHW_IOCTL_REQUEST to generate the actual value.
 */
typedef enum shw_user_request_t {
    SHW_USER_REQ_REGISTER_USER,    /*!< Initialize user-kernel discussion. */
    SHW_USER_REQ_DEREGISTER_USER,  /*!< Terminate user-kernel discussion. */
    SHW_USER_REQ_GET_RESULTS,      /*!< Get information on outstanding
                                      results. */
    SHW_USER_REQ_GET_CAPABILITIES, /*!< Get information on hardware support. */
    SHW_USER_REQ_GET_RANDOM,       /*!< Get random data from RNG. */
    SHW_USER_REQ_ADD_ENTROPY,      /*!< Add entropy to hardware RNG. */
    SHW_USER_REQ_DROP_PERMS,       /*!< Diminish the permissions of a block of
                                      secure memory */
    SHW_USER_REQ_SSTATUS,          /*!< Check the status of a block of secure 
                                      memory */
    SHW_USER_REQ_SFREE,            /*!< Free a block of secure memory */
    SHW_USER_REQ_SCC_ENCRYPT,      /*!< Encrypt a region of user-owned secure
                                     memory */
    SHW_USER_REQ_SCC_DECRYPT,     /*!< Decrypt a region of user-owned secure
                                     memory */
} shw_user_request_t;


/*!
 * @typedef scc_partition_status_t
 */
/** Partition status information. */
typedef enum fsl_shw_partition_status_t {
    FSL_PART_S_UNUSABLE,          /*!< Partition not implemented */
    FSL_PART_S_UNAVAILABLE,       /*!< Partition owned by other host */
    FSL_PART_S_AVAILABLE,         /*!< Partition available */
    FSL_PART_S_ALLOCATED,         /*!< Partition owned by host but not engaged
                                   */
    FSL_PART_S_ENGAGED,           /*!< Partition owned by host and engaged */
} fsl_shw_partition_status_t;


/*
 * Structure passed during user ioctl() calls to manage secure partitions.
 */
typedef struct scc_partition_info_t {
    uint32_t user_base;            /*!< Userspace pointer to base of partition */
    uint32_t permissions;          /*!< Permissions to give the partition (only
                                        used in call to _DROP_PERMS) */
    fsl_shw_partition_status_t status;  /*!< Status of the partition */
} scc_partition_info_t;


/******************************************************************************
 * Enumerations
 *****************************************************************************/
/*!
 * Flags for the state of the User Context Object (#fsl_shw_uco_t).
 */
typedef enum fsl_shw_user_ctx_flags_t
{
  /*!
     * API will block the caller until operation completes.  The result will be
     * available in the return code.  If this is not set, user will have to get
     * results using #fsl_shw_get_results().
     */
    FSL_UCO_BLOCKING_MODE = 0x01,
  /*!
     * User wants callback (at the function specified with
     * #fsl_shw_uco_set_callback()) when the operation completes.  This flag is
     * valid only if #FSL_UCO_BLOCKING_MODE is not set.
     */
    FSL_UCO_CALLBACK_MODE = 0x02,
    /*! Do not free descriptor chain after driver (adaptor) finishes */
    FSL_UCO_SAVE_DESC_CHAIN = 0x04,
  /*!
     * User has made at least one request with callbacks requested, so API is
     * ready to handle others.
     */
    FSL_UCO_CALLBACK_SETUP_COMPLETE = 0x08,
  /*!
     * (virtual) pointer to descriptor chain is completely linked with physical
     * (DMA) addresses, ready for the hardware.  This flag should not be used
     * by FSL SHW API programs.
     */
    FSL_UCO_CHAIN_PREPHYSICALIZED = 0x10,
  /*!
     * The user has changed the context but the changes have not been copied to
     * the kernel driver.
     */
    FSL_UCO_CONTEXT_CHANGED = 0x20,
    /*! Internal Use.  This context belongs to a user-mode API user. */
    FSL_UCO_USERMODE_USER = 0x40,
} fsl_shw_user_ctx_flags_t;


/*!
 * Return code for FSL_SHW library.
 *
 * These codes may be returned from a function call.  In non-blocking mode,
 * they will appear as the status in a Result Object.
 */
/* REQ-FSLSHW-ERR-001 */
typedef enum fsl_shw_return_t
{
  /*!
     * No error.  As a function return code in Non-blocking mode, this may
     * simply mean that the operation was accepted for eventual execution.
     */
    FSL_RETURN_OK_S = 0,
   	/*! Failure for non-specific reason. */
    FSL_RETURN_ERROR_S,
 /*!
    * Operation failed because some resource was not able to be allocated.
    */
    FSL_RETURN_NO_RESOURCE_S,
    /*! Crypto algorithm unrecognized or improper. */
    FSL_RETURN_BAD_ALGORITHM_S,
    /*! Crypto mode unrecognized or improper. */
    FSL_RETURN_BAD_MODE_S,
    /*! Flag setting unrecognized or inconsistent. */
    FSL_RETURN_BAD_FLAG_S,
    /*! Improper or unsupported key length for algorithm. */
    FSL_RETURN_BAD_KEY_LENGTH_S,
    /*! Improper parity in a (DES, TDES) key. */
    FSL_RETURN_BAD_KEY_PARITY_S,
  /*!
     * Improper or unsupported data length for algorithm or internal buffer.
     */
    FSL_RETURN_BAD_DATA_LENGTH_S,
    /*! Authentication / Integrity Check code check failed. */
    FSL_RETURN_AUTH_FAILED_S,
    /*! A memory error occurred. */
    FSL_RETURN_MEMORY_ERROR_S,
    /*! An error internal to the hardware occurred. */
    FSL_RETURN_INTERNAL_ERROR_S,
    /*! ECC detected Point at Infinity */
    FSL_RETURN_POINT_AT_INFINITY_S,
    /*! ECC detected No Point at Infinity */
    FSL_RETURN_POINT_NOT_AT_INFINITY_S,
    /*! GCD is One */
    FSL_RETURN_GCD_IS_ONE_S,
    /*! GCD is not One */
    FSL_RETURN_GCD_IS_NOT_ONE_S,
    /*! Candidate is Prime */
    FSL_RETURN_PRIME_S,
    /*! Candidate is not Prime */
    FSL_RETURN_NOT_PRIME_S,
    /*! N register loaded improperly with even value */
    FSL_RETURN_EVEN_MODULUS_ERROR_S,
    /*! Divisor is zero. */
    FSL_RETURN_DIVIDE_BY_ZERO_ERROR_S,
    /*! Bad Exponent or Scalar value for Point Multiply */
    FSL_RETURN_BAD_EXPONENT_ERROR_S,
    /*! RNG hardware problem. */
    FSL_RETURN_OSCILLATOR_ERROR_S,
    /*! RNG hardware problem. */
    FSL_RETURN_STATISTICS_ERROR_S,
} fsl_shw_return_t;


/*!
 * Algorithm Identifier.
 *
 * Selection of algorithm will determine how large the block size of the
 * algorithm is.   Context size is the same length unless otherwise specified.
 * Selection of algorithm also affects the allowable key length.
 */
typedef enum fsl_shw_key_alg_t
{
  /*!
     * Key will be used to perform an HMAC.  Key size is 1 to 64 octets.  Block
     * size is 64 octets.
     */
    FSL_KEY_ALG_HMAC,
  /*!
     * Advanced Encryption Standard (Rijndael).  Block size is 16 octets.  Key
     * size is 16 octets.  (The single choice of key size is a Sahara platform
     * limitation.)
     */
    FSL_KEY_ALG_AES,
  /*!
     * Data Encryption Standard.  Block size is 8 octets.  Key size is 8
     * octets.
     */
    FSL_KEY_ALG_DES,
  /*!
     * 2- or 3-key Triple DES.  Block size is 8 octets.  Key size is 16 octets
     * for 2-key Triple DES, and 24 octets for 3-key.
     */
    FSL_KEY_ALG_TDES,
  /*!
     * ARC4.  No block size.  Context size is 259 octets.  Allowed key size is
     * 1-16 octets.  (The choices for key size are a Sahara platform
     * limitation.)
     */
    FSL_KEY_ALG_ARC4,
} fsl_shw_key_alg_t;


/*!
 * Mode selector for Symmetric Ciphers.
 *
 * The selection of mode determines how a cryptographic algorithm will be
 * used to process the plaintext or ciphertext.
 *
 * For all modes which are run block-by-block (that is, all but
 * #FSL_SYM_MODE_STREAM), any partial operations must be performed on a text
 * length which is multiple of the block size.  Except for #FSL_SYM_MODE_CTR,
 * these block-by-block algorithms must also be passed a total number of octets
 * which is a multiple of the block size.
 *
 * In modes which require that the total number of octets of data be a multiple
 * of the block size (#FSL_SYM_MODE_ECB and #FSL_SYM_MODE_CBC), and the user
 * has a total number of octets which are not a multiple of the block size, the
 * user must perform any necessary padding to get to the correct data length.
 */
typedef enum fsl_shw_sym_mode_t
{
  /*!
     * Stream.  There is no associated block size.  Any request to process data
     * may be of any length.  This mode is only for ARC4 operations, and is
     * also the only mode used for ARC4.
     */
    FSL_SYM_MODE_STREAM,

  /*!
     * Electronic Codebook.  Each block of data is encrypted/decrypted.  The
     * length of the data stream must be a multiple of the block size.  This
     * mode may be used for DES, 3DES, and AES.  The block size is determined
     * by the algorithm.
     */
    FSL_SYM_MODE_ECB,
  /*!
     * Cipher-Block Chaining.  Each block of data is encrypted/decrypted and
     * then "chained" with the previous block by an XOR function.  Requires
     * context to start the XOR (previous block).  This mode may be used for
     * DES, 3DES, and AES.  The block size is determined by the algorithm.
     */
    FSL_SYM_MODE_CBC,
  /*!
     * Counter.  The counter is encrypted, then XORed with a block of data.
     * The counter is then incremented (using modulus arithmetic) for the next
     * block. The final operation may be non-multiple of block size.  This mode
     * may be used for AES.  The block size is determined by the algorithm.
     */
    FSL_SYM_MODE_CTR,
} fsl_shw_sym_mode_t;


/*!
 * Algorithm selector for Cryptographic Hash functions.
 *
 * Selection of algorithm determines how large the context and digest will be.
 * Context is the same size as the digest (resulting hash), unless otherwise
 * specified.
 */
typedef enum fsl_shw_hash_alg_t
{
    FSL_HASH_ALG_MD5,           /*!< MD5 algorithm.  Digest is 16 octets. */
    FSL_HASH_ALG_SHA1,          /*!< SHA-1 (aka SHA or SHA-160) algorithm.
                                   Digest is 20 octets. */
    FSL_HASH_ALG_SHA224,        /*!< SHA-224 algorithm.  Digest is 28 octets,
                                   though context is 32 octets. */
    FSL_HASH_ALG_SHA256         /*!< SHA-256 algorithm.  Digest is 32
                                   octets. */
} fsl_shw_hash_alg_t;


/*!
 * The type of Authentication-Cipher function which will be performed.
 */
typedef enum fsl_shw_acc_mode_t
{
  /*!
     * CBC-MAC for Counter.  Requires context and modulus.  Final operation may
     * be non-multiple of block size.  This mode may be used for AES.
     */
    FSL_ACC_MODE_CCM,
  /*!
     * SSL mode.  Not supported.  Combines HMAC and encrypt (or decrypt).
     * Needs one key object for encryption, another for the HMAC.  The usual
     * hashing and symmetric encryption algorithms are supported.
     */
    FSL_ACC_MODE_SSL
} fsl_shw_acc_mode_t;


/* REQ-FSLSHW-PINTFC-COA-HCO-001 */
/*!
 * Flags which control a Hash operation.
 */
typedef enum fsl_shw_hash_ctx_flags_t
{
    FSL_HASH_FLAGS_INIT = 0x01,     /*!< Context is empty.  Hash is started
                                       from scratch, with a message-processed
                                       count of zero. */
    FSL_HASH_FLAGS_SAVE = 0x02,     /*!< Retrieve context from hardware after
                                       hashing.  If used with the
                                       #FSL_HASH_FLAGS_FINALIZE flag, the final
                                       digest value will be saved in the
                                       object. */
    FSL_HASH_FLAGS_LOAD = 0x04,     /*!< Place context into hardware before
                                       hashing. */
    FSL_HASH_FLAGS_FINALIZE = 0x08, /*!< PAD message and perform final digest
                                       operation.  If user message is
                                       pre-padded, this flag should not be
                                       used. */
} fsl_shw_hash_ctx_flags_t;


/*!
 * Flags which control an HMAC operation.
 *
 * These may be combined by ORing them together.  See #fsl_shw_hmco_set_flags()
 * and #fsl_shw_hmco_clear_flags().
 */
typedef enum fsl_shw_hmac_ctx_flags_t
{
    FSL_HMAC_FLAGS_INIT = 1,        /**< Message context is empty.  HMAC is
                                       started from scratch (with key) or from
                                       precompute of inner hash, depending on
                                       whether
                                       #FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT is
                                       set. */
    FSL_HMAC_FLAGS_SAVE = 2,        /**< Retrieve ongoing context from hardware
                                       after hashing.  If used with the
                                       #FSL_HMAC_FLAGS_FINALIZE flag, the final
                                       digest value (HMAC) will be saved in the
                                       object. */
    FSL_HMAC_FLAGS_LOAD = 4,        /**< Place ongoing context into hardware
                                       before hashing. */
    FSL_HMAC_FLAGS_FINALIZE = 8,    /**< PAD message and perform final HMAC
                                       operations of inner and outer hashes. */
    FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT = 16 /**< This means that the context
                                        contains precomputed inner and outer
                                        hash values. */
} fsl_shw_hmac_ctx_flags_t;


/**
 * Flags to control use of the #fsl_shw_scco_t.
 *
 * These may be ORed together to get the desired effect.
 * See #fsl_shw_scco_set_flags() and #fsl_shw_scco_clear_flags()
 */
typedef enum fsl_shw_sym_ctx_flags_t
{
    /**
     * Context is empty.  In ARC4, this means that the S-Box needs to be
     * generated from the key.  In #FSL_SYM_MODE_CBC mode, this allows an IV of
     * zero to be specified.  In #FSL_SYM_MODE_CTR mode, it means that an
     * initial CTR value of zero is desired.
     */
    FSL_SYM_CTX_INIT = 1,
    /**
     * Load context from object into hardware before running cipher.  In
     * #FSL_SYM_MODE_CTR mode, this would refer to the Counter Value.
     */
    FSL_SYM_CTX_LOAD = 2,
    /**
     * Save context from hardware into object after running cipher.  In
     * #FSL_SYM_MODE_CTR mode, this would refer to the Counter Value.
     */
    FSL_SYM_CTX_SAVE = 4,
    /**
     * Context (SBox) is to be unwrapped and wrapped on each use.
     * This flag is unsupported.
     * */
    FSL_SYM_CTX_PROTECT = 8,
} fsl_shw_sym_ctx_flags_t;


/**
 * Flags which describe the state of the #fsl_shw_sko_t.
 *
 * These may be ORed together to get the desired effect.
 * See #fsl_shw_sko_set_flags() and #fsl_shw_sko_clear_flags()
 */
typedef enum fsl_shw_key_flags_t
{
    FSL_SKO_KEY_IGNORE_PARITY = 1, /*!< If algorithm is DES or 3DES, do not
                                      validate the key parity bits. */
    FSL_SKO_KEY_PRESENT = 2,       /*!< Clear key is present in the object. */
    FSL_SKO_KEY_ESTABLISHED = 4,   /*!< Key has been established for use.  This
                                       feature is not available for all
                                       platforms, nor for all algorithms and
                                       modes.*/
    FSL_SKO_USE_SECRET_KEY = 8,    /*!< Use device-unique key.  Not always
                                       available. */
    FSL_SKO_KEY_SW_KEY = 16,	/*!< Clear key can be provided to the user */
	FSL_SKO_KEY_SELECT_PF_KEY = 32,	/*!< Internal flag to show that this key
					   references one of the hardware keys, and
					   its value is in pf_key. */
} fsl_shw_key_flags_t;


/**
 * Type of value which is associated with an established key.
 */
typedef uint64_t key_userid_t;


/**
 * Flags which describe the state of the #fsl_shw_acco_t.
 *
 * The @a FSL_ACCO_CTX_INIT and @a FSL_ACCO_CTX_FINALIZE flags, when used
 * together, provide for a one-shot operation.
 */
typedef enum fsl_shw_auth_ctx_flags_t
{
    FSL_ACCO_CTX_INIT = 1,      /**< Initialize Context(s) */
    FSL_ACCO_CTX_LOAD = 2,      /**< Load intermediate context(s).
                                   This flag is unsupported. */
    FSL_ACCO_CTX_SAVE = 4,      /**< Save intermediate context(s).
                                   This flag is unsupported. */
    FSL_ACCO_CTX_FINALIZE = 8,  /**< Create MAC during this operation. */
    FSL_ACCO_NIST_CCM = 0x10,   /**< Formatting of CCM input data is
                                    performed by calls to
                                    #fsl_shw_ccm_nist_format_ctr_and_iv() and
                                    #fsl_shw_ccm_nist_update_ctr_and_iv().  */
}  fsl_shw_auth_ctx_flags_t;


/**
 * The operation which controls the behavior of #fsl_shw_establish_key().
 *
 * These values are passed to #fsl_shw_establish_key().
 */
typedef enum fsl_shw_key_wrap_t
{
    FSL_KEY_WRAP_CREATE,        /**< Generate a key from random values. */
    FSL_KEY_WRAP_ACCEPT,        /**< Use the provided clear key. */
    FSL_KEY_WRAP_UNWRAP         /**< Unwrap a previously wrapped key. */
} fsl_shw_key_wrap_t;


/**
 *  Modulus Selector for CTR modes.
 *
 * The incrementing of the Counter value may be modified by a modulus.  If no
 * modulus is needed or desired for AES, use #FSL_CTR_MOD_128.
 */
typedef enum fsl_shw_ctr_mod_t
{
    FSL_CTR_MOD_8,              /**< Run counter with modulus of 2^8. */
    FSL_CTR_MOD_16,             /**< Run counter with modulus of 2^16. */
    FSL_CTR_MOD_24,             /**< Run counter with modulus of 2^24. */
    FSL_CTR_MOD_32,             /**< Run counter with modulus of 2^32. */
    FSL_CTR_MOD_40,             /**< Run counter with modulus of 2^40. */
    FSL_CTR_MOD_48,             /**< Run counter with modulus of 2^48. */
    FSL_CTR_MOD_56,             /**< Run counter with modulus of 2^56. */
    FSL_CTR_MOD_64,             /**< Run counter with modulus of 2^64. */
    FSL_CTR_MOD_72,             /**< Run counter with modulus of 2^72. */
    FSL_CTR_MOD_80,             /**< Run counter with modulus of 2^80. */
    FSL_CTR_MOD_88,             /**< Run counter with modulus of 2^88. */
    FSL_CTR_MOD_96,             /**< Run counter with modulus of 2^96. */
    FSL_CTR_MOD_104,            /**< Run counter with modulus of 2^104. */
    FSL_CTR_MOD_112,            /**< Run counter with modulus of 2^112. */
    FSL_CTR_MOD_120,            /**< Run counter with modulus of 2^120. */
    FSL_CTR_MOD_128             /**< Run counter with modulus of 2^128. */
} fsl_shw_ctr_mod_t;


/**
 * A work type associated with a work/result queue request.
 */
typedef enum shw_work_type_t
{
    SHW_WORK_GET_RANDOM = 1,    /**< fsl_shw_get_random() request.  */
    SHW_WORK_ADD_RANDOM,        /**< fsl_shw_add_entropy() request.  */
} shw_work_type_t;


/**
 * Permissions flags for Secure Partitions
 */
typedef enum fsl_shw_permission_t
{
/** SCM Access Permission: Do not zeroize/deallocate partition on SMN Fail state */
    FSL_PERM_NO_ZEROIZE =       0x80000000,
/** SCM Access Permission: Enforce trusted key read in  */
    FSL_PERM_TRUSTED_KEY_READ = 0x40000000,
/** SCM Access Permission: Ignore Supervisor/User mode in permission determination */
    FSL_PERM_HD_S =             0x00000800,
/** SCM Access Permission: Allow Read Access to  Host Domain */
    FSL_PERM_HD_R =             0x00000400,
/** SCM Access Permission: Allow Write Access to  Host Domain */
    FSL_PERM_HD_W =             0x00000200,
/** SCM Access Permission: Allow Execute Access to  Host Domain */
    FSL_PERM_HD_X =             0x00000100,
/** SCM Access Permission: Allow Read Access to Trusted Host Domain */
    FSL_PERM_TH_R =             0x00000040,
/** SCM Access Permission: Allow Write Access to Trusted Host Domain */
    FSL_PERM_TH_W =             0x00000020,
/** SCM Access Permission: Allow Read Access to Other/World Domain */
    FSL_PERM_OT_R =             0x00000004,
/** SCM Access Permission: Allow Write Access to Other/World Domain */
    FSL_PERM_OT_W =             0x00000002,
/** SCM Access Permission: Allow Execute Access to Other/World Domain */
    FSL_PERM_OT_X =             0x00000001,
} fsl_shw_permission_t;

/*!
 * Select the cypher mode to use for partition cover/uncover operations.
 *
 * They currently map directly to the values used in the SCC2 driver, but this
 * is not guarinteed behavior.
 */
typedef enum fsl_shw_cypher_mode_t
{
    FSL_SHW_CYPHER_MODE_ECB = 1,       /*!< ECB mode */
    FSL_SHW_CYPHER_MODE_CBC = 2,       /*!< CBC mode */
} fsl_shw_cypher_mode_t;

/*!
 * Which platform key should be presented for cryptographic use.
 */
typedef enum fsl_shw_pf_key_t {
	FSL_SHW_PF_KEY_IIM,	/*!< Present fused IIM key */
	FSL_SHW_PF_KEY_PRG,	/*!< Present Program key */
	FSL_SHW_PF_KEY_IIM_PRG,	/*!< Present IIM ^ Program key */
	FSL_SHW_PF_KEY_IIM_RND,	/*!< Present Random key */
	FSL_SHW_PF_KEY_RND,	/*!< Present IIM ^ Random key */
} fsl_shw_pf_key_t;

/*!
 * The various security tamper events
 */
typedef enum fsl_shw_tamper_t {
	FSL_SHW_TAMPER_NONE,	/*!< No error detected */
	FSL_SHW_TAMPER_WTD,	/*!< wire-mesh tampering det */
	FSL_SHW_TAMPER_ETBD,	/*!< ext tampering det: input B */
	FSL_SHW_TAMPER_ETAD,	/*!< ext tampering det: input A */
	FSL_SHW_TAMPER_EBD,	/*!< external boot detected */
	FSL_SHW_TAMPER_SAD,	/*!< security alarm detected */
	FSL_SHW_TAMPER_TTD,	/*!< temperature tampering det */
	FSL_SHW_TAMPER_CTD,	/*!< clock tampering det */
	FSL_SHW_TAMPER_VTD,	/*!< voltage tampering det */
	FSL_SHW_TAMPER_MCO,	/*!< monotonic counter overflow */
	FSL_SHW_TAMPER_TCO,	/*!< time counter overflow */
} fsl_shw_tamper_t;

/*
 * Structure passed during user ioctl() calls to manage data stored in secure
 * partitions.
 */

typedef struct scc_region_t {
	uint32_t partition_base;	/*!< Base address of partition */
	uint32_t offset;	/*!< Byte offset into partition */
	uint32_t length;	/*!< Number of bytes in request */
	uint8_t *black_data;	/*!< Address of cipher text */
	uint64_t owner_id;	/*!< user's secret */
	fsl_shw_cypher_mode_t cypher_mode;	/*!< ECB or CBC */
	uint32_t IV[4];		/*!< IV for CBC mode */
} scc_region_t;

/******************************************************************************
 * Data Structures
 *****************************************************************************/

/**
 * Initialization Object
 */
typedef struct fsl_sho_ibo
{
} fsl_sho_ibo_t;


/**
 * Common Entry structure for work queues, results queues.
 */
typedef struct shw_queue_entry_t {
    struct shw_queue_entry_t* next; /**< Next entry in queue. */
    struct fsl_shw_uco_t*  user_ctx; /**< Associated user context. */
    uint32_t         flags;     /**< User context flags at time of request. */
    void (*callback)(struct fsl_shw_uco_t* uco); /**< Any callback request. */
    uint32_t         user_ref;  /**< User's reference for this request. */
    fsl_shw_return_t code;      /**< FSL SHW result of this operation. */
    uint32_t         detail1;   /**< Any extra error info.  */
    uint32_t         detail2;   /**< More any extra error info.  */
    void*            user_mode_req; /**<  Pointer into user space.  */
    uint32_t (*postprocess)(struct shw_queue_entry_t* q); /**< (internal)
                                                           function to call
                                                           when this operation
                                                           completes.
  */
} shw_queue_entry_t;


/**
 * A queue.  Fields must be initialized to NULL before use.
 */
typedef struct shw_queue_t
{
    struct shw_queue_entry_t* head; /**< First entry in queue. */
    struct shw_queue_entry_t* tail; /**< Last entry. */
} shw_queue_t;


/**
 * Secure Partition information
 */
typedef struct fsl_shw_spo_t
{
    uint32_t                user_base;
    void*                   kernel_base;
    struct fsl_shw_spo_t*   next;
} fsl_shw_spo_t;


/* REQ-FSLSHW-PINTFC-COA-UCO-001 */
/**
 * User Context Object
 */
typedef struct fsl_shw_uco_t
{
    int           openfd;       /**< user-mode file descriptor */
    uint32_t      user_ref;     /**< User's reference */
    void (*callback)(struct fsl_shw_uco_t* uco); /**< User's callback fn  */
    uint32_t      flags;             /**< from fsl_shw_user_ctx_flags_t */
    unsigned      pool_size;    /**< maximum size of user result pool */
#ifdef __KERNEL__
    shw_queue_t   result_pool;  /**< where non-blocking results go */
    os_process_handle_t  process; /**< remember for signalling User mode */
    fsl_shw_spo_t* partition;    /**< chain of secure partitions owned by
                                          the user */
#endif
    struct fsl_shw_uco_t* next; /**< To allow user-mode chaining of contexts,
                                 for signalling and in kernel, to link user
                                 contexts.  */
    fsl_shw_pf_key_t wrap_key;	/*!< What key for ciphering T */
} fsl_shw_uco_t;


/* REQ-FSLSHW-PINTFC-API-GEN-006  ??  */
/**
 * Result object
 */
typedef struct fsl_shw_result_t
{
    uint32_t         user_ref;  /**< User's reference at time of request. */
    fsl_shw_return_t code;      /**< Return code from request. */
    uint32_t         detail1;   /**< Extra error info. Unused in SHW driver. */
    uint32_t         detail2;   /**< Extra error info. Unused in SHW driver. */
    void*            user_req;  /**< Pointer to original user request. */
} fsl_shw_result_t;


/**
 * Keystore Object
 */
typedef struct fsl_shw_kso_t
{
#ifdef __KERNEL__
    os_lock_t       lock;           /**< Pointer to lock that controls access to
                                      the keystore. */
#endif
    void*           user_data;      /**< Pointer to user structure that handles
                                      the internals of the keystore. */
    fsl_shw_return_t (*data_init)        (fsl_shw_uco_t* user_ctx,
                                          void** user_data);
    void             (*data_cleanup)     (fsl_shw_uco_t* user_ctx,
                                          void** user_data);
    fsl_shw_return_t (*slot_verify_access)(void* user_data, uint64_t owner_id,
                                          uint32_t slot);
    fsl_shw_return_t (*slot_alloc)       (void* user_data, uint32_t size_bytes,
                                          uint64_t owner_id, uint32_t* slot);
    fsl_shw_return_t (*slot_dealloc)     (void* user_data,
                                          uint64_t owner_id, uint32_t slot);
    void*            (*slot_get_address) (void* user_data, uint32_t slot);
    uint32_t         (*slot_get_base)    (void* user_data, uint32_t slot);
    uint32_t         (*slot_get_offset)  (void* user_data, uint32_t slot);
    uint32_t         (*slot_get_slot_size)  (void* user_data, uint32_t slot);
} fsl_shw_kso_t;


/* REQ-FSLSHW-PINTFC-COA-SKO-001 */
/**
 * Secret Key Context Object
 */
typedef struct fsl_shw_sko_t
{
    uint32_t          flags;    /**<  Flags from #fsl_shw_sym_ctx_flags_t. */
    fsl_shw_key_alg_t algorithm; /**< Algorithm for this key. */
    key_userid_t      userid;   /**< User's identifying value for Black key. */
    uint32_t          handle;   /**< Reference in SCC driver for Red key. */
    uint16_t          key_length;  /**< Length of stored key, in bytes. */
    uint8_t           key[64];  /**< Bytes of stored key. */
    struct fsl_shw_kso_t*   keystore;   /**< If present, key is in keystore */
	fsl_shw_pf_key_t pf_key;	/*!< What key to select for use when this key
					   is doing ciphering.  If FSL_SHW_PF_KEY_PRG
					   or FSL_SHW_PF_KEY_PRG_IIM is the value, then
					   a 'present' or 'established' key will be
					   programed into the PK. */
} fsl_shw_sko_t;


/* REQ-FSLSHW-PINTFC-COA-CO-001 */
/**
 * Platform Capability Object
 *
 * Pointer to this structure is returned by fsl_shw_get_capabilities() and
 * queried with the various fsl_shw_pco_() functions.
 */
typedef struct fsl_shw_pco_t
{
    int api_major;              /**< Major version number for API. */
    int api_minor;              /**< Minor version number for API. */
    int driver_major;           /**< Major version of some driver. */
    int driver_minor;           /**< Minor version of some driver. */
    unsigned sym_algorithm_count;           /**< Number of sym_algorithms. */
    fsl_shw_key_alg_t*  sym_algorithms; /**< Pointer to array. */
    unsigned sym_mode_count;    /**< Number of sym_modes. */
    fsl_shw_sym_mode_t* sym_modes; /**< Pointer to array. */
    unsigned hash_algorithm_count; /**< Number of hash_algorithms. */
    fsl_shw_hash_alg_t* hash_algorithms; /**< Pointer to array */
    uint8_t sym_support[5][4];  /**< indexed by key alg then mode */

    int scc_driver_major;
    int scc_driver_minor;
    int scm_version;            /**< Version from SCM Configuration register */
    int smn_version;            /**< Version from SMN Status register */
    int block_size_bytes;       /**< Number of bytes per block of RAM; also
                                   block size of the crypto algorithm. */
    union {
        struct scc_info {
            int black_ram_size_blocks;  /**< Number of blocks of Black RAM */
            int red_ram_size_blocks;    /**< Number of blocks of Red RAM */
        } scc_info;
        struct scc2_info {
            int partition_size_bytes;   /**< Number of bytes in each partition */
            int partition_count;        /**< Number of partitions on this platform */
        } scc2_info;
    } u;
} fsl_shw_pco_t;


/* REQ-FSLSHW-PINTFC-COA-HCO-001 */
/**
 * Hash Context Object
 */
typedef struct fsl_shw_hco_t /* fsl_shw_hash_context_object */
{
    fsl_shw_hash_alg_t       algorithm; /**< Algorithm for this context. */
    uint32_t                 flags; /**< Flags from
                                       #fsl_shw_hash_ctx_flags_t. */
    uint8_t                  digest_length; /**< hash result length in bytes */
    uint8_t                  context_length; /**< Context length in bytes */
    uint8_t                  context_register_length; /**< in bytes */
    uint32_t                 context[9]; /**< largest digest + msg size */
} fsl_shw_hco_t;


/* REQ-FSLSHW-PINTFC-COA-HCO-001 */
/**
 * HMAC Context Object
 */
typedef struct fsl_shw_hmco_t /* fsl_shw_hmac_context_object */
{
    fsl_shw_hash_alg_t       algorithm; /**< Hash algorithm for the HMAC. */
    uint32_t                 flags; /**< Flags from
                                       #fsl_shw_hmac_ctx_flags_t. */
    uint8_t                  digest_length; /**< in bytes */
    uint8_t                  context_length; /**< in bytes */
    uint8_t                  context_register_length; /**< in bytes */
    uint32_t                 ongoing_context[9]; /**< largest digest + msg
                                                    size */
    uint32_t                 inner_precompute[9]; /**< largest digest + msg
                                                      size */
    uint32_t                 outer_precompute[9]; /**< largest digest + msg
                                                      size */
} fsl_shw_hmco_t;


/* REQ-FSLSHW-PINTFC-COA-SCCO-001 */
/**
 * Symmetric Crypto Context Object Context Object
 */
typedef struct fsl_shw_scco_t
{
    uint32_t                flags; /**< Flags from #fsl_shw_sym_ctx_flags_t. */
    unsigned                block_size_bytes; /**< Both block and ctx size */
    fsl_shw_sym_mode_t      mode; /**< Symmetric mode for this context. */
    /* Could put modulus plus 16-octet context in union with arc4
       sbox+ptrs... */
    fsl_shw_ctr_mod_t       modulus_exp; /**< Exponent value for CTR modulus */
    uint8_t                 context[8]; /**< Stored context.  Large enough
                                             for 3DES.  */
} fsl_shw_scco_t;


/**
 * Authenticate-Cipher Context Object

 * An object for controlling the function of, and holding information about,
 * data for the authenticate-cipher functions, #fsl_shw_gen_encrypt() and
 * #fsl_shw_auth_decrypt().
 */
typedef struct fsl_shw_acco_t
{
    uint32_t                 flags; /**< See #fsl_shw_auth_ctx_flags_t for
                                       meanings */
    fsl_shw_acc_mode_t       mode; /**< CCM only */
    uint8_t                  mac_length; /**< User's value for length  */
    unsigned                 q_length; /**< NIST parameter - */
    fsl_shw_scco_t           cipher_ctx_info; /**< For running
                                                 encrypt/decrypt. */
    union {
        fsl_shw_scco_t       CCM_ctx_info; /**< For running the CBC in
                                              AES-CCM.  */
        fsl_shw_hco_t        hash_ctx_info; /**< For running the hash */
    } auth_info;                /**< "auth" info struct  */
    uint8_t                  unencrypted_mac[16]; /**< max block size... */
} fsl_shw_acco_t;


/**
 * Common header in request structures between User-mode API and SHW driver.
 */
struct shw_req_header {
    uint32_t           flags;   /**< Flags - from user-mode context. */
    uint32_t           user_ref; /**< Reference - from user-mode context. */
    fsl_shw_return_t   code;    /**< Result code for operation. */
};

/**
 *  Used by user-mode API to retrieve completed non-blocking results in
 *  SHW_USER_REQ_GET_RESULTS ioctl().
 */
struct results_req {
    struct shw_req_header hdr;  /**< Boilerplate. */
    unsigned         requested; /**< number of results requested, */
    unsigned         actual;    /**< number of results obtained. */
    fsl_shw_result_t *results;  /**< pointer to memory to hold results. */
};


/**
 * Used by user-mode API to retrieve hardware capabilities in
 * SHW_USER_REQ_GET_CAPABILITIES ioctl().
 */
struct capabilities_req {
    struct shw_req_header hdr;  /**< Boilerplate. */
    unsigned         size;      /**< Size, in bytes, capabilities. */
    fsl_shw_pco_t*   capabilities; /**< Place to copy out the info. */
};


/**
 * Used by user-mode API to get a random number
 */
struct get_random_req {
    struct shw_req_header hdr;  /**< Boilerplate. */
    unsigned         size;      /**< Size, in bytes, of random. */
    uint8_t*         random;    /**< Place to copy out the random number. */
};


/**
 * Used by API to add entropy to a random number generator
 */
struct add_entropy_req {
    struct shw_req_header hdr;  /**< Boilerplate. */
    unsigned         size;      /**< Size, in bytes, of entropy. */
    uint8_t*         entropy;   /**< Location of the entropy to be added. */
};


/******************************************************************************
 * External variables
 *****************************************************************************/
#ifdef __KERNEL__
extern os_lock_t shw_queue_lock;

extern fsl_shw_uco_t* user_list;
#endif


/******************************************************************************
 * Access Macros for Objects
 *****************************************************************************/
/**
 * Get FSL SHW API version
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @param[out] pcmajor   A pointer to where the major version
 *                       of the API is to be stored.
 * @param[out] pcminor   A pointer to where the minor version
 *                       of the API is to be stored.
 */
#define fsl_shw_pco_get_version(pcobject, pcmajor, pcminor)                   \
do {                                                                          \
    *(pcmajor) = (pcobject)->api_major;                                       \
    *(pcminor) = (pcobject)->api_minor;                                       \
} while (0)


/**
 * Get underlying driver version.
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @param[out] pcmajor   A pointer to where the major version
 *                       of the driver is to be stored.
 * @param[out] pcminor   A pointer to where the minor version
 *                       of the driver is to be stored.
 */
#define fsl_shw_pco_get_driver_version(pcobject, pcmajor, pcminor)            \
do {                                                                          \
    *(pcmajor) = (pcobject)->driver_major;                                    \
    *(pcminor) = (pcobject)->driver_minor;                                    \
} while (0)


/**
 * Get list of symmetric algorithms supported.
 *
 * @param pcobject           The Platform Capababilities Object to query.
 * @param[out] pcalgorithms  A pointer to where to store the location of
 *                           the list of algorithms.
 * @param[out] pcacount      A pointer to where to store the number of
 *                           algorithms in the list at @a algorithms.
 */
#define fsl_shw_pco_get_sym_algorithms(pcobject, pcalgorithms, pcacount)      \
do {                                                                          \
    *(pcalgorithms) = (pcobject)->sym_algorithms;                             \
    *(pcacount) = (pcobject)->sym_algorithm_count;                            \
} while (0)


/**
 * Get list of symmetric modes supported.
 *
 * @param pcobject        The Platform Capababilities Object to query.
 * @param[out] gsmodes    A pointer to where to store the location of
 *                        the list of modes.
 * @param[out] gsacount   A pointer to where to store the number of
 *                        algorithms in the list at @a modes.
 */
#define fsl_shw_pco_get_sym_modes(pcobject, gsmodes, gsacount)                \
do {                                                                          \
    *(gsmodes) = (pcobject)->sym_modes;                                       \
    *(gsacount) = (pcobject)->sym_mode_count;                                 \
} while (0)


/**
 * Get list of hash algorithms supported.
 *
 * @param pcobject           The Platform Capababilities Object to query.
 * @param[out] gsalgorithms  A pointer which will be set to the list of
 *                           algorithms.
 * @param[out] gsacount      The number of algorithms in the list at @a
 *                           algorithms.
 */
#define fsl_shw_pco_get_hash_algorithms(pcobject, gsalgorithms, gsacount)     \
do {                                                                          \
    *(gsalgorithms) = (pcobject)->hash_algorithms;                            \
    *(gsacount) = (pcobject)->hash_algorithm_count;                           \
} while (0)


/**
 * Determine whether the combination of a given symmetric algorithm and a given
 * mode is supported.
 *
 * @param pcobject   The Platform Capababilities Object to query.
 * @param pcalg      A Symmetric Cipher algorithm.
 * @param pcmode     A Symmetric Cipher mode.
 *
 * @return 0 if combination is not supported, non-zero if supported.
 */
#if defined(FSL_HAVE_DRYICE) && defined(__KERNEL__)
#define fsl_shw_pco_check_sym_supported(pcobject, pcalg, pcmode)              \
    ((pcobject)->sym_support[pcalg][pcmode])
#else
#define fsl_shw_pco_check_sym_supported(pcobject, pcalg, pcmode)              \
    0
#endif

/**
 * Determine whether a given Encryption-Authentication mode is supported.
 *
 * @param pcobject  The Platform Capababilities Object to query.
 * @param pcmode    The Authentication mode.
 *
 * @return 0 if mode is not supported, non-zero if supported.
 */
#define fsl_shw_pco_check_auth_supported(pcobject, pcmode)                    \
    0


/**
 * Determine whether Black Keys (key establishment / wrapping) is supported.
 *
 * @param pcobject  The Platform Capababilities Object to query.
 *
 * @return 0 if wrapping is not supported, non-zero if supported.
 */
#if defined(FSL_HAVE_DRYICE) && defined(__KERNEL__)
#define fsl_shw_pco_check_black_key_supported(pcobject)                       \
    1
#else
#define fsl_shw_pco_check_black_key_supported(pcobject)                       \
    0

#endif

/*!
 * Determine whether Programmed Key features are available
 *
 * @param pcobject          The Platform Capabilities Object to query.
 *
 * @return  1 if Programmed Key features are available, otherwise zero.
 */
#if defined(FSL_HAVE_DRYICE) && defined(__KERNEL__)
#define fsl_shw_pco_check_pk_supported(pcobject)        \
    1
#else
#define fsl_shw_pco_check_pk_supported(pcobject)        \
    0
#endif

/*!
 * Determine whether Software Key features are available
 *
 * @param pc_info          The Platform Capabilities Object to query.
 *
 * @return  1 if Software key features are available, otherwise zero.
 */
#if defined(FSL_HAVE_DRYICE) && defined(__KERNEL__)
#define fsl_shw_pco_check_sw_keys_supported(pcobject)        \
    1
#else
#define fsl_shw_pco_check_sw_keys_supported(pcobject)        \
    0
#endif

/*!
 * Get FSL SHW SCC driver version
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @param[out] pcmajor   A pointer to where the major version
 *                       of the SCC driver is to be stored.
 * @param[out] pcminor   A pointer to where the minor version
 *                       of the SCC driver is to be stored.
 */
#define fsl_shw_pco_get_scc_driver_version(pcobject, pcmajor, pcminor)        \
{                                                                             \
    *(pcmajor) = (pcobject)->scc_driver_major;                                \
    *(pcminor) = (pcobject)->scc_driver_minor;                                \
}


/**
 * Get SCM hardware version
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @return               The SCM hardware version
 */
#define fsl_shw_pco_get_scm_version(pcobject)                                 \
    ((pcobject)->scm_version)


/**
 * Get SMN hardware version
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @return               The SMN hardware version
 */
#define fsl_shw_pco_get_smn_version(pcobject)                                 \
    ((pcobject)->smn_version)


/**
 * Get the size of an SCM block, in bytes
 *
 * @param      pcobject  The Platform Capababilities Object to query.
 * @return               The size of an SCM block, in bytes.
 */
#define fsl_shw_pco_get_scm_block_size(pcobject)                              \
    ((pcobject)->block_size_bytes)


/**
 * Get size of Black and Red RAM memory
 *
 * @param      pcobject    The Platform Capababilities Object to query.
 * @param[out] black_size  A pointer to where the size of the Black RAM, in
 *                         blocks, is to be placed.
 * @param[out] red_size    A pointer to where the size of the Red RAM, in 
 *                         blocks, is to be placed.
 */
#define fsl_shw_pco_get_smn_size(pcobject, black_size, red_size)              \
{                                                                             \
    if ((pcobject)->scm_version == 1) {                                       \
        *(black_size) = (pcobject)->u.scc_info.black_ram_size_blocks;           \
        *(red_size)   = (pcobject)->u.scc_info.red_ram_size_blocks;             \
    } else {                                                                  \
        *(black_size) = 0;                                                    \
        *(red_size)   = 0;                                                    \
    }                                                                         \
}


/**
 * Determine whether Secure Partitions are supported
 *
 * @param pcobject   The Platform Capababilities Object to query.
 *
 * @return 0 if secure partitions are not supported, non-zero if supported.
 */
#define fsl_shw_pco_check_spo_supported(pcobject)                           \
    ((pcobject)->scm_version == 2)


/**
 * Get the size of a Secure Partitions
 *
 * @param pcobject   The Platform Capababilities Object to query.
 * 
 * @return Partition size, in bytes.  0 if Secure Partitions not supported.
 */
#define fsl_shw_pco_get_spo_size_bytes(pcobject)                            \
    (((pcobject)->scm_version == 2) ?                                       \
        ((pcobject)->u.scc2_info.partition_size_bytes) : 0 )                  \


/**
 * Get the number of Secure Partitions on this platform
 *
 * @param pcobject   The Platform Capababilities Object to query.
 * 
 * @return Number of partitions. 0 if Secure Paritions not supported.  Note
 *         that this returns the total number of partitions, not all may be
 *         available to the user.
 */
#define fsl_shw_pco_get_spo_count(pcobject)                                 \
    (((pcobject)->scm_version == 2) ?                                       \
        ((pcobject)->u.scc2_info.partition_count) : 0 )                       \


/*!
 * Initialize a Secret Key Object.
 *
 * This function must be called before performing any other operation with
 * the Object.
 *
 * @param skobject     The Secret Key Object to be initialized.
 * @param skalgorithm  DES, AES, etc.
 *
 */
#define fsl_shw_sko_init(skobject,skalgorithm)                          \
{                                                                       \
    fsl_shw_sko_t* skop = skobject;                                     \
                                                                        \
    skop->algorithm = skalgorithm;                                      \
    skop->flags = 0;                                                    \
    skop->keystore = NULL;                                              \
    skop->pf_key = FSL_SHW_PF_KEY_PRG;                                  \
}

/*!
 * Initialize a Secret Key Object to use a Platform Key register.
 *
 * This function must be called before performing any other operation with
 * the Object.
 *
 * @param skobject     The Secret Key Object to be initialized.
 * @param skalgorithm  DES, AES, etc.
 * @param skhwkey      one of the fsl_shw_pf_key_t values.
 *
 */
#define fsl_shw_sko_init_pf_key(skobject,skalgorithm,skhwkey)           \
{                                                                       \
    fsl_shw_sko_t* skop = skobject;                                     \
    fsl_shw_key_alg_t alg = skalgorithm;                                \
    fsl_shw_pf_key_t key = skhwkey;                                     \
                                                                        \
    skop->algorithm = alg;                                              \
    if (alg == FSL_KEY_ALG_TDES) {                                      \
        skop->key_length = 21;                                          \
    }                                                                   \
    skop->keystore = NULL;                                              \
    skop->flags = FSL_SKO_KEY_SELECT_PF_KEY;                            \
    skop->pf_key = key;                                                 \
    if ((key == FSL_SHW_PF_KEY_IIM) || (key == FSL_SHW_PF_KEY_PRG)      \
        || (key == FSL_SHW_PF_KEY_IIM_PRG)                              \
        || (key == FSL_SHW_PF_KEY_IIM_RND)                              \
        || (key == FSL_SHW_PF_KEY_RND)) {                               \
        skop->flags |= FSL_SKO_KEY_ESTABLISHED;                         \
    }                                                                   \
}

/*!
 * Store a cleartext key in the key object.
 *
 * This has the side effect of setting the #FSL_SKO_KEY_PRESENT flag and
 * resetting the #FSL_SKO_KEY_ESTABLISHED flag.
 *
 * @param skobject     A variable of type #fsl_shw_sko_t.
 * @param skkey        A pointer to the beginning of the key.
 * @param skkeylen     The length, in octets, of the key.  The value should be
 *                     appropriate to the key size supported by the algorithm.
 *                     64 octets is the absolute maximum value allowed for this
 *                     call.
 */
#define fsl_shw_sko_set_key(skobject, skkey, skkeylen)                       \
{                                                                            \
       (skobject)->key_length = skkeylen;                                    \
       copy_bytes((skobject)->key, skkey, skkeylen);                         \
       (skobject)->flags |= FSL_SKO_KEY_PRESENT;                             \
       (skobject)->flags &= ~FSL_SKO_KEY_ESTABLISHED;                        \
}

/**
 * Set a size for the key.
 *
 * This function would normally be used when the user wants the key to be
 * generated from a random source.
 *
 * @param skobject   A variable of type #fsl_shw_sko_t.
 * @param skkeylen   The length, in octets, of the key.  The value should be
 *                   appropriate to the key size supported by the algorithm.
 *                   64 octets is the absolute maximum value allowed for this
 *                   call.
 */
#define fsl_shw_sko_set_key_length(skobject, skkeylen)                       \
       (skobject)->key_length = skkeylen;


/**
 * Set the User ID associated with the key.
 *
 * @param skobject   A variable of type #fsl_shw_sko_t.
 * @param skuserid   The User ID to identify authorized users of the key.
 */
#define fsl_shw_sko_set_user_id(skobject, skuserid)                           \
       (skobject)->userid = (skuserid)

/**
 * Establish a user Keystore to hold the key.
 */
#define fsl_shw_sko_set_keystore(skobject, user_keystore)                     \
       (skobject)->keystore = (user_keystore)



/**
 * Set the establish key handle into a key object.
 *
 * The @a userid field will be used to validate the access to the unwrapped
 * key.  This feature is not available for all platforms, nor for all
 * algorithms and modes.
 *
 * The #FSL_SKO_KEY_ESTABLISHED will be set (and the #FSL_SKO_KEY_PRESENT flag
 * will be cleared).
 *
 * @param skobject   A variable of type #fsl_shw_sko_t.
 * @param skuserid   The User ID to verify this user is an authorized user of
 *                   the key.
 * @param skhandle   A @a handle from #fsl_shw_sko_get_established_info.
 */
#define fsl_shw_sko_set_established_info(skobject, skuserid, skhandle)        \
{                                                                             \
       (skobject)->userid = (skuserid);                                       \
       (skobject)->handle = (skhandle);                                       \
       (skobject)->flags |= FSL_SKO_KEY_ESTABLISHED;                          \
       (skobject)->flags &=                                                   \
                       ~(FSL_SKO_KEY_PRESENT);   \
}


/**
 * Retrieve the established-key handle from a key object.
 *
 * @param skobject   A variable of type #fsl_shw_sko_t.
 * @param skhandle   The location to store the @a handle of the unwrapped
 *                   key.
 */
#define fsl_shw_sko_get_established_info(skobject, skhandle)                  \
       *(skhandle) = (skobject)->handle


/**
 * Extract the algorithm from a key object.
 *
 * @param      skobject     The Key Object to be queried.
 * @param[out] skalgorithm  A pointer to the location to store the algorithm.
 */
#define fsl_shw_sko_get_algorithm(skobject, skalgorithm)                      \
       *(skalgorithm) = (skobject)->algorithm


/**
 * Retrieve the cleartext key from a key object that is stored in a user
 * keystore.
 *
 * @param      skobject     The Key Object to be queried.
 * @param[out] skkey        A pointer to the location to store the key.  NULL
 *                          if the key is not stored in a user keystore.
 */
#define fsl_shw_sko_get_key(skobject, skkey)                                  \
{                                                                             \
    fsl_shw_kso_t* keystore = (skobject)->keystore;                           \
    if (keystore != NULL) {                                                   \
        *(skkey) = keystore->slot_get_address(keystore->user_data,            \
                                              (skobject)->handle);            \
    } else {                                                                  \
        *(skkey) = NULL;                                                      \
    }                                                                         \
}


/*!
 * Determine the size of a wrapped key based upon the cleartext key's length.
 *
 * This function can be used to calculate the number of octets that
 * #fsl_shw_extract_key() will write into the location at @a covered_key.
 *
 * If zero is returned at @a length, this means that the key length in
 * @a key_info is not supported.
 *
 * @param      wkeyinfo         Information about a key to be wrapped.
 * @param      wkeylen          Location to store the length of a wrapped
 *                              version of the key in @a key_info.
 */
#define fsl_shw_sko_calculate_wrapped_size(wkeyinfo, wkeylen)           \
{                                                                       \
    register fsl_shw_sko_t* kp = wkeyinfo;                              \
    register uint32_t kl = kp->key_length;                              \
    int key_blocks;                                                     \
    int base_size = 35; /* ICV + T' + ALG + LEN + FLAGS */              \
                                                                        \
    if (kp->flags & FSL_SKO_KEY_SELECT_PF_KEY) {                        \
        kl = 21;  /* 168-bit 3DES key */                                \
    }                                                                   \
    key_blocks = (kl + 7) / 8;                                          \
    /* Round length up to 3DES block size for CBC mode */               \
    *(wkeylen) = base_size + 8 * key_blocks;                            \
}

/*!
 * Set some flags in the key object.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param skobject     A variable of type #fsl_shw_sko_t.
 * @param skflags      (One or more) ORed members of #fsl_shw_key_flags_t which
 *                     are to be set.
 */
#define fsl_shw_sko_set_flags(skobject, skflags)                              \
      (skobject)->flags |= (skflags)


/**
 * Clear some flags in the key object.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param skobject      A variable of type #fsl_shw_sko_t.
 * @param skflags       (One or more) ORed members of #fsl_shw_key_flags_t
 *                      which are to be reset.
 */
#define fsl_shw_sko_clear_flags(skobject, skflags)                            \
      (skobject)->flags &= ~(skflags)

/**
 * Initialize a User Context Object.
 *
 * This function must be called before performing any other operation with the
 * Object.  It sets the User Context Object to initial values, and set the size
 * of the results pool.  The mode will be set to a default of
 * #FSL_UCO_BLOCKING_MODE.
 *
 * When using non-blocking operations, this sets the maximum number of
 * operations which can be outstanding.  This number includes the counts of
 * operations waiting to start, operation(s) being performed, and results which
 * have not been retrieved.
 *
 * Changes to this value are ignored once user registration has completed.  It
 * should be set to 1 if only blocking operations will ever be performed.
 *
 * @param ucontext     The User Context object to operate on.
 * @param usize        The maximum number of operations which can be
 *                     outstanding.
 */
#ifdef __KERNEL__

#define fsl_shw_uco_init(ucontext, usize)                                     \
do {                                                                          \
    fsl_shw_uco_t* uco = ucontext;                                            \
                                                                              \
    (uco)->pool_size = usize;                                                 \
    (uco)->flags = FSL_UCO_BLOCKING_MODE | FSL_UCO_CONTEXT_CHANGED;           \
    (uco)->openfd = -1;                                                       \
    (uco)->callback = NULL;                                                   \
    (uco)->partition = NULL;                                                  \
    (uco)->wrap_key = FSL_SHW_PF_KEY_IIM;                                     \
} while (0)

#else /* __KERNEL__ */

#define fsl_shw_uco_init(ucontext, usize)                                     \
do {                                                                          \
    fsl_shw_uco_t* uco = ucontext;                                            \
                                                                              \
    (uco)->pool_size = usize;                                                 \
    (uco)->flags = FSL_UCO_BLOCKING_MODE | FSL_UCO_CONTEXT_CHANGED;           \
    (uco)->openfd = -1;                                                       \
    (uco)->callback = NULL;                                                   \
    (uco)->wrap_key = FSL_SHW_PF_KEY_IIM;                                     \
} while (0)

#endif /* __KERNEL__ */


/**
 * Set the User Reference for the User Context.
 *
 * @param ucontext     The User Context object to operate on.
 * @param uref         A value which will be passed back with a result.
 */
#define fsl_shw_uco_set_reference(ucontext, uref)                             \
do {                                                                          \
    fsl_shw_uco_t* uco = ucontext;                                            \
                                                                              \
    (uco)->user_ref = uref;                                                   \
    (uco)->flags |= FSL_UCO_CONTEXT_CHANGED;                                  \
} while (0)


/**
 * Set the User Reference for the User Context.
 *
 * @param ucontext     The User Context object to operate on.
 * @param ucallback    The function the API will invoke when an operation
 *                     completes.
 */
#define fsl_shw_uco_set_callback(ucontext, ucallback)                         \
do {                                                                          \
    fsl_shw_uco_t* uco = ucontext;                                            \
                                                                              \
    (uco)->callback = ucallback;                                              \
    (uco)->flags |= FSL_UCO_CONTEXT_CHANGED;                                  \
} while (0)

/**
 * Set flags in the User Context.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param ucontext     The User Context object to operate on.
 * @param uflags       ORed values from #fsl_shw_user_ctx_flags_t.
 */
#define fsl_shw_uco_set_flags(ucontext, uflags)                               \
      (ucontext)->flags |= (uflags) | FSL_UCO_CONTEXT_CHANGED


/**
 * Clear flags in the User Context.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param ucontext     The User Context object to operate on.
 * @param uflags       ORed values from #fsl_shw_user_ctx_flags_t.
 */
#define fsl_shw_uco_clear_flags(ucontext, uflags)                             \
do {                                                                          \
    fsl_shw_uco_t* uco = ucontext;                                            \
                                                                              \
    (uco)->flags &= ~(uflags);                                                \
    (uco)->flags |= FSL_UCO_CONTEXT_CHANGED;                                  \
} while (0)


/**
 * Retrieve the reference value from a Result Object.
 *
 * @param robject  The result object to query.
 *
 * @return The reference associated with the request.
 */
#define fsl_shw_ro_get_reference(robject)                                    \
       (robject)->user_ref


/**
 * Retrieve the status code from a Result Object.
 *
 * @param robject  The result object to query.
 *
 * @return The status of the request.
 */
#define fsl_shw_ro_get_status(robject)                                       \
       (robject)->code



/* REQ-FSL-SHW-PINTFC-API-BASIC-HASH-004 */
/**
 * Initialize a Hash Context Object.
 *
 * This function must be called before performing any other operation with the
 * Object.  It sets the current message length and hash algorithm in the hash
 * context object.
 *
 * @param      hcobject    The hash context to operate upon.
 * @param      hcalgorithm The hash algorithm to be used (#FSL_HASH_ALG_MD5,
 *                         #FSL_HASH_ALG_SHA256, etc).
 *
 */
#define fsl_shw_hco_init(hcobject, hcalgorithm)                               \
do {                                                                          \
     (hcobject)->algorithm = hcalgorithm;                                     \
     (hcobject)->flags = 0;                                                   \
     switch (hcalgorithm) {                                                   \
     case FSL_HASH_ALG_MD5:                                                   \
         (hcobject)->digest_length = 16;                                      \
         (hcobject)->context_length = 16;                                     \
         (hcobject)->context_register_length = 24;                            \
         break;                                                               \
     case FSL_HASH_ALG_SHA1:                                                  \
         (hcobject)->digest_length = 20;                                      \
         (hcobject)->context_length = 20;                                     \
         (hcobject)->context_register_length = 24;                            \
         break;                                                               \
     case FSL_HASH_ALG_SHA224:                                                \
         (hcobject)->digest_length = 28;                                      \
         (hcobject)->context_length = 32;                                     \
         (hcobject)->context_register_length = 36;                            \
         break;                                                               \
     case FSL_HASH_ALG_SHA256:                                                \
         (hcobject)->digest_length = 32;                                      \
         (hcobject)->context_length = 32;                                     \
         (hcobject)->context_register_length = 36;                            \
         break;                                                               \
     default:                                                                 \
         /* error ! */                                                        \
         (hcobject)->digest_length = 1;                                       \
         (hcobject)->context_length = 1;                                      \
         (hcobject)->context_register_length = 1;                             \
         break;                                                               \
     }                                                                        \
} while (0)


/* REQ-FSL-SHW-PINTFC-API-BASIC-HASH-001 */
/**
 * Get the current hash value and message length from the hash context object.
 *
 * The algorithm must have already been specified.  See #fsl_shw_hco_init().
 *
 * @param      hcobject   The hash context to query.
 * @param[out] hccontext  Pointer to the location of @a length octets where to
 *                        store a copy of the current value of the digest.
 * @param      hcclength  Number of octets of hash value to copy.
 * @param[out] hcmsglen   Pointer to the location to store the number of octets
 *                        already hashed.
 */
#define fsl_shw_hco_get_digest(hcobject, hccontext, hcclength, hcmsglen)      \
do {                                                                          \
     memcpy(hccontext, (hcobject)->context, hcclength);                       \
         if ((hcobject)->algorithm == FSL_HASH_ALG_SHA224                     \
             || (hcobject)->algorithm == FSL_HASH_ALG_SHA256) {               \
             *(hcmsglen) = (hcobject)->context[8];                            \
         } else {                                                             \
             *(hcmsglen) = (hcobject)->context[5];                            \
         }                                                                    \
} while (0)


/* REQ-FSL-SHW-PINTFC-API-BASIC-HASH-002 */
/**
 * Get the hash algorithm from the hash context object.
 *
 * @param      hcobject    The hash context to query.
 * @param[out] hcalgorithm Pointer to where the algorithm is to be stored.
 */
#define fsl_shw_hco_get_info(hcobject, hcalgorithm)                           \
do {                                                                          \
     *(hcalgorithm) = (hcobject)->algorithm;                                  \
} while (0)


/* REQ-FSL-SHW-PINTFC-API-BASIC-HASH-003 */
/* REQ-FSL-SHW-PINTFC-API-BASIC-HASH-004 */
/**
 * Set the current hash value and message length in the hash context object.
 *
 * The algorithm must have already been specified.  See #fsl_shw_hco_init().
 *
 * @param      hcobject  The hash context to operate upon.
 * @param      hccontext Pointer to buffer of appropriate length to copy into
 *                       the hash context object.
 * @param      hcmsglen  The number of octets of the message which have
 *                        already been hashed.
 *
 */
#define fsl_shw_hco_set_digest(hcobject, hccontext, hcmsglen)                 \
do {                                                                          \
     memcpy((hcobject)->context, hccontext, (hcobject)->context_length);      \
     if (((hcobject)->algorithm == FSL_HASH_ALG_SHA224)                       \
         || ((hcobject)->algorithm == FSL_HASH_ALG_SHA256)) {                 \
         (hcobject)->context[8] = hcmsglen;                                   \
     } else {                                                                 \
         (hcobject)->context[5] = hcmsglen;                                   \
     }                                                                        \
} while (0)


/**
 * Set flags in a Hash Context Object.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param hcobject   The hash context to be operated on.
 * @param hcflags    The flags to be set in the context.  These can be ORed
 *                   members of #fsl_shw_hash_ctx_flags_t.
 */
#define fsl_shw_hco_set_flags(hcobject, hcflags)                              \
      (hcobject)->flags |= (hcflags)


/**
 * Clear flags in a Hash Context Object.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param hcobject   The hash context to be operated on.
 * @param hcflags    The flags to be reset in the context.  These can be ORed
 *                   members of #fsl_shw_hash_ctx_flags_t.
 */
#define fsl_shw_hco_clear_flags(hcobject, hcflags)                            \
      (hcobject)->flags &= ~(hcflags)


/**
 * Initialize an HMAC Context Object.
 *
 * This function must be called before performing any other operation with the
 * Object.  It sets the current message length and hash algorithm in the HMAC
 * context object.
 *
 * @param      hcobject    The HMAC context to operate upon.
 * @param      hcalgorithm The hash algorithm to be used (#FSL_HASH_ALG_MD5,
 *                         #FSL_HASH_ALG_SHA256, etc).
 *
 */
#define fsl_shw_hmco_init(hcobject, hcalgorithm)                              \
    fsl_shw_hco_init(hcobject, hcalgorithm)


/**
 * Set flags in an HMAC Context Object.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param hcobject   The HMAC context to be operated on.
 * @param hcflags    The flags to be set in the context.  These can be ORed
 *                   members of #fsl_shw_hmac_ctx_flags_t.
 */
#define fsl_shw_hmco_set_flags(hcobject, hcflags)                             \
      (hcobject)->flags |= (hcflags)


/**
 * Clear flags in an HMAC Context Object.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param hcobject   The HMAC context to be operated on.
 * @param hcflags    The flags to be reset in the context.  These can be ORed
 *                   members of #fsl_shw_hmac_ctx_flags_t.
 */
#define fsl_shw_hmco_clear_flags(hcobject, hcflags)                           \
      (hcobject)->flags &= ~(hcflags)


/**
 * Initialize a Symmetric Cipher Context Object.
 *
 * This function must be called before performing any other operation with the
 * Object.  This will set the @a mode and @a algorithm and initialize the
 * Object.
 *
 * @param scobject  The context object to operate on.
 * @param scalg     The cipher algorithm this context will be used with.
 * @param scmode    #FSL_SYM_MODE_CBC, #FSL_SYM_MODE_ECB, etc.
 *
 */
#define fsl_shw_scco_init(scobject, scalg, scmode)                            \
do {                                                                          \
      register uint32_t bsb;   /* block-size bytes */                         \
                                                                              \
      switch (scalg) {                                                        \
      case FSL_KEY_ALG_AES:                                                   \
          bsb = 16;                                                           \
          break;                                                              \
      case FSL_KEY_ALG_DES:                                                   \
          /* fall through */                                                  \
      case FSL_KEY_ALG_TDES:                                                  \
          bsb = 8;                                                            \
          break;                                                              \
      case FSL_KEY_ALG_ARC4:                                                  \
          bsb = 259;                                                          \
          break;                                                              \
      case FSL_KEY_ALG_HMAC:                                                  \
          bsb = 1;  /* meaningless */                                         \
          break;                                                              \
      default:                                                                \
          bsb = 00;                                                           \
      }                                                                       \
      (scobject)->block_size_bytes = bsb;                                     \
      (scobject)->mode = scmode;                                              \
      (scobject)->flags = 0;                                                  \
} while (0)


/**
 * Set the flags for a Symmetric Cipher Context.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param scobject The context object to operate on.
 * @param scflags  The flags to reset (one or more values from
 *                 #fsl_shw_sym_ctx_flags_t ORed together).
 *
 */
#define fsl_shw_scco_set_flags(scobject, scflags)                             \
       (scobject)->flags |= (scflags)


/**
 * Clear some flags in a Symmetric Cipher Context Object.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param scobject The context object to operate on.
 * @param scflags  The flags to reset (one or more values from
 *                 #fsl_shw_sym_ctx_flags_t ORed together).
 *
 */
#define fsl_shw_scco_clear_flags(scobject, scflags)                           \
       (scobject)->flags &= ~(scflags)


/**
 * Set the Context (IV) for a Symmetric Cipher Context.
 *
 * This is to set the context/IV for #FSL_SYM_MODE_CBC mode, or to set the
 * context (the S-Box and pointers) for ARC4.  The full context size will
 * be copied.
 *
 * @param scobject  The context object to operate on.
 * @param sccontext A pointer to the buffer which contains the context.
 *
 */
#define fsl_shw_scco_set_context(scobject, sccontext)                         \
       memcpy((scobject)->context, sccontext,                                 \
                  (scobject)->block_size_bytes)


/**
 * Get the Context for a Symmetric Cipher Context.
 *
 * This is to retrieve the context/IV for #FSL_SYM_MODE_CBC mode, or to
 * retrieve context (the S-Box and pointers) for ARC4.  The full context
 * will be copied.
 *
 * @param      scobject  The context object to operate on.
 * @param[out] sccontext Pointer to location where context will be stored.
 */
#define fsl_shw_scco_get_context(scobject, sccontext)                         \
       memcpy(sccontext, (scobject)->context, (scobject)->block_size_bytes)


/**
 * Set the Counter Value for a Symmetric Cipher Context.
 *
 * This will set the Counter Value for CTR mode.
 *
 * @param scobject  The context object to operate on.
 * @param sccounter The starting counter value.  The number of octets.
 *                  copied will be the block size for the algorithm.
 * @param scmodulus The modulus for controlling the incrementing of the
 *                  counter.
 *
 */
#define fsl_shw_scco_set_counter_info(scobject, sccounter, scmodulus)        \
do {                                                                         \
           if ((sccounter) != NULL) {                                        \
               memcpy((scobject)->context, sccounter,                        \
                          (scobject)->block_size_bytes);                     \
           }                                                                 \
           (scobject)->modulus_exp = scmodulus;                              \
} while (0)


/**
 * Get the Counter Value for a Symmetric Cipher Context.
 *
 * This will retrieve the Counter Value is for CTR mode.
 *
 * @param     scobject    The context object to query.
 * @param[out] sccounter  Pointer to location to store the current counter
 *                        value.  The number of octets copied will be the
 *                        block size for the algorithm.
 * @param[out] scmodulus  Pointer to location to store the modulus.
 *
 */
#define fsl_shw_scco_get_counter_info(scobject, sccounter, scmodulus)        \
do {                                                                         \
           if ((sccounter) != NULL) {                                        \
               memcpy(sccounter, (scobject)->context,                        \
                          (scobject)->block_size_bytes);                     \
           }                                                                 \
           if ((scmodulus) != NULL) {                                        \
               *(scmodulus) = (scobject)->modulus_exp;                       \
           }                                                                 \
} while (0)


/**
 * Initialize a Authentication-Cipher Context.
 *
 * @param acobject  Pointer to object to operate on.
 * @param acmode    The mode for this object (only #FSL_ACC_MODE_CCM
 *                  supported).
 */
#define fsl_shw_acco_init(acobject, acmode)                                   \
do {                                                                          \
       (acobject)->flags = 0;                                                 \
       (acobject)->mode = (acmode);                                           \
} while (0)


/**
 * Set the flags for a Authentication-Cipher Context.
 *
 * Turns on the flags specified in @a flags.  Other flags are untouched.
 *
 * @param acobject  Pointer to object to operate on.
 * @param acflags   The flags to set (one or more from
 *                  #fsl_shw_auth_ctx_flags_t ORed together).
 *
 */
#define fsl_shw_acco_set_flags(acobject, acflags)                             \
       (acobject)->flags |= (acflags)


/**
 * Clear some flags in a Authentication-Cipher Context Object.
 *
 * Turns off the flags specified in @a flags.  Other flags are untouched.
 *
 * @param acobject  Pointer to object to operate on.
 * @param acflags   The flags to reset (one or more from
 *                  #fsl_shw_auth_ctx_flags_t ORed together).
 *
 */
#define fsl_shw_acco_clear_flags(acobject, acflags)                           \
       (acobject)->flags &= ~(acflags)


/**
 * Set up the Authentication-Cipher Object for CCM mode.
 *
 * This will set the @a auth_object for CCM mode and save the @a ctr,
 * and @a mac_length.  This function can be called instead of
 * #fsl_shw_acco_init().
 *
 * The paramater @a ctr is Counter Block 0, (counter value 0), which is for the
 * MAC.
 *
 * @param acobject  Pointer to object to operate on.
 * @param acalg     Cipher algorithm.  Only AES is supported.
 * @param accounter The initial counter value.
 * @param acmaclen  The number of octets used for the MAC.  Valid values are
 *                  4, 6, 8, 10, 12, 14, and 16.
 */
/* Do we need to stash the +1 value of the CTR somewhere? */
#define fsl_shw_acco_set_ccm(acobject, acalg, accounter, acmaclen)            \
 do {                                                                         \
      (acobject)->flags = 0;                                                  \
      (acobject)->mode = FSL_ACC_MODE_CCM;                                    \
      (acobject)->auth_info.CCM_ctx_info.block_size_bytes = 16;               \
      (acobject)->cipher_ctx_info.block_size_bytes = 16;                      \
      (acobject)->mac_length = acmaclen;                                      \
      fsl_shw_scco_set_counter_info(&(acobject)->cipher_ctx_info, accounter,  \
            FSL_CTR_MOD_128);                                                 \
} while (0)


/**
 * Format the First Block (IV) & Initial Counter Value per NIST CCM.
 *
 * This function will also set the IV and CTR values per Appendix A of NIST
 * Special Publication 800-38C (May 2004).  It will also perform the
 * #fsl_shw_acco_set_ccm() operation with information derived from this set of
 * parameters.
 *
 * Note this function assumes the algorithm is AES.  It initializes the
 * @a auth_object by setting the mode to #FSL_ACC_MODE_CCM and setting the
 * flags to be #FSL_ACCO_NIST_CCM.
 *
 * @param acobject  Pointer to object to operate on.
 * @param act       The number of octets used for the MAC.  Valid values are
 *                  4, 6, 8, 10, 12, 14, and 16.
 * @param acad      Number of octets of Associated Data (may be zero).
 * @param acq       A value for the size of the length of @a q field.  Valid
 *                  values are 1-8.
 * @param acN       The Nonce (packet number or other changing value). Must
 *                  be (15 - @a q_length) octets long.
 * @param acQ       The value of Q (size of the payload in octets).
 *
 */
#define fsl_shw_ccm_nist_format_ctr_and_iv(acobject, act, acad, acq, acN, acQ)\
 do {                                                                         \
        uint64_t Q = acQ;                                                     \
        uint8_t bflag = ((acad)?0x40:0) | ((((act)-2)/2)<<3) | ((acq)-1);     \
        unsigned i;                                                           \
        uint8_t* qptr = (acobject)->auth_info.CCM_ctx_info.context + 15;      \
        (acobject)->auth_info.CCM_ctx_info.block_size_bytes = 16;             \
        (acobject)->cipher_ctx_info.block_size_bytes = 16;                    \
        (acobject)->mode = FSL_ACC_MODE_CCM;                                  \
        (acobject)->flags  = FSL_ACCO_NIST_CCM;                               \
                                                                              \
        /* Store away the MAC length (after calculating actual value */       \
        (acobject)->mac_length = (act);                                       \
        /* Set Flag field in Block 0 */                                       \
        *((acobject)->auth_info.CCM_ctx_info.context) = bflag;                \
        /* Set Nonce field in Block 0 */                                      \
        memcpy((acobject)->auth_info.CCM_ctx_info.context+1, acN,             \
                   15-(acq));                                                 \
        /* Set Flag field in ctr */                                           \
        *((acobject)->cipher_ctx_info.context) = (acq)-1;                     \
        /* Update the Q (payload length) field of Block0 */                   \
        (acobject)->q_length = acq;                                           \
        for (i = 0; i < (acq); i++) {                                         \
            *qptr-- = Q & 0xFF;                                               \
            Q >>= 8;                                                          \
        }                                                                     \
        /* Set the Nonce field of the ctr */                                  \
        memcpy((acobject)->cipher_ctx_info.context+1, acN, 15-(acq));         \
        /* Clear the block counter field of the ctr */                        \
        memset((acobject)->cipher_ctx_info.context+16-(acq), 0, (acq)+1);     \
   } while (0)


/**
 * Update the First Block (IV) & Initial Counter Value per NIST CCM.
 *
 * This function will set the IV and CTR values per Appendix A of NIST Special
 * Publication 800-38C (May 2004).
 *
 * Note this function assumes that #fsl_shw_ccm_nist_format_ctr_and_iv() has
 * previously been called on the @a auth_object.
 *
 * @param acobject  Pointer to object to operate on.
 * @param acN       The Nonce (packet number or other changing value). Must
 *                  be (15 - @a q_length) octets long.
 * @param acQ       The value of Q (size of the payload in octets).
 *
 */
/* Do we need to stash the +1 value of the CTR somewhere? */
#define fsl_shw_ccm_nist_update_ctr_and_iv(acobject, acN, acQ)                \
  do {                                                                        \
        uint64_t Q = acQ;                                                     \
        unsigned i;                                                           \
        uint8_t* qptr = (acobject)->auth_info.CCM_ctx_info.context + 15;      \
                                                                              \
        /* Update the Nonce field field of Block0 */                          \
        memcpy((acobject)->auth_info.CCM_ctx_info.context+1, acN,             \
               15 - (acobject)->q_length);                                    \
        /* Update the Q (payload length) field of Block0 */                   \
        for (i = 0; i < (acobject)->q_length; i++) {                          \
            *qptr-- = Q & 0xFF;                                               \
            Q >>= 8;                                                          \
        }                                                                     \
        /* Update the Nonce field of the ctr */                               \
        memcpy((acobject)->cipher_ctx_info.context+1, acN,                    \
               15 - (acobject)->q_length);                                    \
   } while (0)


/******************************************************************************
 * Library functions
 *****************************************************************************/
/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-GEN-003 */
/**
 * Determine the hardware security capabilities of this platform.
 *
 * Though a user context object is passed into this function, it will always
 * act in a non-blocking manner.
 *
 * @param  user_ctx   The user context which will be used for the query.
 *
 * @return  A pointer to the capabilities object.
 */
extern fsl_shw_pco_t* fsl_shw_get_capabilities(fsl_shw_uco_t* user_ctx);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-GEN-004 */
/**
 * Create an association between the the user and the provider of the API.
 *
 * @param  user_ctx   The user context which will be used for this association.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_register_user(fsl_shw_uco_t* user_ctx);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-GEN-005 */
/**
 * Destroy the association between the the user and the provider of the API.
 *
 * @param  user_ctx   The user context which is no longer needed.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_deregister_user(fsl_shw_uco_t* user_ctx);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-GEN-006 */
/**
 * Retrieve results from earlier operations.
 *
 * @param         user_ctx     The user's context.
 * @param         result_size  The number of array elements of @a results.
 * @param[in,out] results      Pointer to first of the (array of) locations to
 *                             store results.
 * @param[out]    result_count Pointer to store the number of results which
 *                             were returned.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_get_results(fsl_shw_uco_t* user_ctx,
                                            unsigned result_size,
                                            fsl_shw_result_t results[],
                                            unsigned* result_count);

/**
 * Place a key into a protected location for use only by cryptographic
 * algorithms.
 *
 * This only needs to be used to a) unwrap a key, or b) set up a key which
 * could be wrapped with a later call to #fsl_shw_extract_key().  Normal
 * cleartext keys can simply be placed into #fsl_shw_sko_t key objects with
 * #fsl_shw_sko_set_key() and used directly.
 *
 * The maximum key size supported for wrapped/unwrapped keys is 32 octets.
 * (This is the maximum reasonable key length on Sahara - 32 octets for an HMAC
 * key based on SHA-256.)  The key size is determined by the @a key_info.  The
 * expected length of @a key can be determined by
 * #fsl_shw_sko_calculate_wrapped_size()
 *
 * The protected key will not be available for use until this operation
 * successfully completes.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param[in,out] key_info      The information about the key to be which will
 *                              be established.  In the create case, the key
 *                              length must be set.
 * @param      establish_type   How @a key will be interpreted to establish a
 *                              key for use.
 * @param key                   If @a establish_type is #FSL_KEY_WRAP_UNWRAP,
 *                              this is the location of a wrapped key.  If
 *                              @a establish_type is #FSL_KEY_WRAP_CREATE, this
 *                              parameter can be @a NULL.  If @a establish_type
 *                              is #FSL_KEY_WRAP_ACCEPT, this is the location
 *                              of a plaintext key.
 */
extern fsl_shw_return_t fsl_shw_establish_key(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_key_wrap_t establish_type,
                                const uint8_t* key);


/**
 * Wrap a key and retrieve the wrapped value.
 *
 * A wrapped key is a key that has been cryptographically obscured.  It is
 * only able to be used with #fsl_shw_establish_key().
 *
 * This function will also release the key (see #fsl_shw_release_key()) so
 * that it must be re-established before reuse.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      key_info         The information about the key to be deleted.
 * @param[out] covered_key      The location to store the wrapped key.
 *                              (This size is based upon the maximum key size
 *                              of 32 octets).
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_extract_key(fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                uint8_t* covered_key);

/*!
 * Read the key value from a key object.
 *
 * Only a key marked as a software key (#FSL_SKO_KEY_SW_KEY) can be read with
 * this call.  It has no effect on the status of the key store.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      key_info         The referenced key.
 * @param[out] key              The location to store the key value.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_read_key(fsl_shw_uco_t * user_ctx,
					 fsl_shw_sko_t * key_info,
					 uint8_t * key);

/**
 * De-establish a key so that it can no longer be accessed.
 *
 * The key will need to be re-established before it can again be used.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      key_info         The information about the key to be deleted.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_release_key(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info);


/*
 * In userspace, partition assignments will be tracked using the user context.
 * In kernel mode, partition assignments are based on address only.
 */

/**
 * Allocate a block of secure memory
 *
 * @param       user_ctx        User context
 * @param       size            Memory size (octets).  Note: currently only
 *                              supports only single-partition sized blocks.
 * @param       UMID            User Mode ID to use when registering the
 *                              partition.
 * @param       permissions     Permissions to initialize the partition with.
 *                              Can be made by ORing flags from the
 *                              #fsl_shw_permission_t.
 *
 * @return                      Address of the allocated memory.  NULL if the
 *                              call was not successful.
 */
extern void *fsl_shw_smalloc(fsl_shw_uco_t* user_ctx,
                             uint32_t size,
                             const uint8_t* UMID,
                             uint32_t permissions);


/** 
 * Free a block of secure memory that was allocated with #fsl_shw_smalloc
 *
 * @param       user_ctx        User context
 * @param       address         Address of the block of secure memory to be
 *                              released.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_sfree(
                                fsl_shw_uco_t* user_ctx,
                                void* address);


/** 
 * Check the status of a block of a secure memory that was allocated with
 * #fsl_shw_smalloc
 *
 * @param       user_ctx        User context
 * @param       address         Address of the block of secure memory to be
 *                              released.
 * @param       status          Status of the partition, of type
 *                              #fsl_partition_status_t
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_sstatus(fsl_shw_uco_t* user_ctx,
                                        void* address,
                                        fsl_shw_partition_status_t* status);


/**
 * Diminish the permissions of a block of secure memory.  Note that permissions
 * can only be revoked.
 *
 * @param       user_ctx        User context
 * @param       address         Base address of the secure memory to work with
 * @param       permissions     Permissions to initialize the partition with.
 *                              Can be made by ORing flags from the
 *                              #fsl_shw_permission_t.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_diminish_perms(
        fsl_shw_uco_t* user_ctx,
        void* address,
        uint32_t permissions);

extern fsl_shw_return_t do_scc_engage_partition(
        fsl_shw_uco_t* user_ctx,
        void* address,
        const uint8_t* UMID,
        uint32_t permissions);

extern fsl_shw_return_t do_system_keystore_slot_alloc(
        fsl_shw_uco_t* user_ctx,
        uint32_t key_lenth,
        uint64_t ownerid,
        uint32_t *slot);

extern fsl_shw_return_t do_system_keystore_slot_dealloc(
        fsl_shw_uco_t* user_ctx,
        uint64_t ownerid,
        uint32_t slot);

extern fsl_shw_return_t do_system_keystore_slot_load(
        fsl_shw_uco_t* user_ctx,
        uint64_t ownerid,
        uint32_t slot,
        const uint8_t *key,
        uint32_t key_length);

extern fsl_shw_return_t do_system_keystore_slot_encrypt(
        fsl_shw_uco_t* user_ctx,
        uint64_t ownerid,
        uint32_t slot,
        uint32_t key_length,
        uint8_t* black_data);

extern fsl_shw_return_t do_system_keystore_slot_decrypt(
        fsl_shw_uco_t* user_ctx,
        uint64_t ownerid,
        uint32_t slot,
        uint32_t key_length,
        const uint8_t* black_data);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-COA-SKO */
/* REQ-FSL-SHW-PINTFC-COA-SCCO */
/* REQ-FSLSHW-PINTFC-API-BASIC-SYM-001 */
/* PINTFC-API-BASIC-SYM-ARC4-001 */
/* PINTFC-API-BASIC-SYM-ARC4-002 */
/**
 * Encrypt a stream of data with a symmetric-key algorithm.
 *
 * In ARC4, and also in #FSL_SYM_MODE_CBC and #FSL_SYM_MODE_CTR modes, the
 * flags of the @a sym_ctx object will control part of the operation of this
 * function.  The #FSL_SYM_CTX_INIT flag means that there is no context info in
 * the object.  The #FSL_SYM_CTX_LOAD means to use information in the
 * @a sym_ctx at the start of the operation, and the #FSL_SYM_CTX_SAVE flag
 * means to update the object's context information after the operation has
 * been performed.
 *
 * All of the data for an operation can be run through at once using the
 * #FSL_SYM_CTX_INIT or #FSL_SYM_CTX_LOAD flags, as appropriate, and then using
 * a @a length for the whole of the data.
 *
 * If a #FSL_SYM_CTX_SAVE flag were added, an additional call to the function
 * would "pick up" where the previous call left off, allowing the user to
 * perform the larger function in smaller steps.
 *
 * In #FSL_SYM_MODE_CBC and #FSL_SYM_MODE_ECB modes, the @a length must always
 * be a multiple of the block size for the algorithm being used.  For proper
 * operation in #FSL_SYM_MODE_CTR mode, the @a length must be a multiple of the
 * block size until the last operation on the total octet stream.
 *
 * Some users of ARC4 may want to compute the context (S-Box and pointers) from
 * the key before any data is available.  This may be done by running this
 * function with a @a length of zero, with the init & save flags flags on in
 * the @a sym_ctx.  Subsequent operations would then run as normal with the
 * load and save flags.  Note that they key object is still required.
 *
 * @param         user_ctx  A user context from #fsl_shw_register_user().
 * @param         key_info  Key and algorithm  being used for this operation.
 * @param[in,out] sym_ctx   Info on cipher mode, state of the cipher.
 * @param         length   Length, in octets, of the pt (and ct).
 * @param         pt       pointer to plaintext to be encrypted.
 * @param[out]    ct       pointer to where to store the resulting ciphertext.
 *
 * @return    A return code of type #fsl_shw_return_t.
 *
 */
extern fsl_shw_return_t fsl_shw_symmetric_encrypt(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_scco_t* sym_ctx,
                                uint32_t length,
                                const uint8_t* pt,
                                uint8_t* ct);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-COA-SKO */
/* REQ-FSL-SHW-PINTFC-COA-SCCO */
/* PINTFC-API-BASIC-SYM-002 */
/* PINTFC-API-BASIC-SYM-ARC4-001 */
/* PINTFC-API-BASIC-SYM-ARC4-002 */
/**
 * Decrypt a stream of data with a symmetric-key algorithm.
 *
 * In ARC4, and also in #FSL_SYM_MODE_CBC and #FSL_SYM_MODE_CTR modes, the
 * flags of the @a sym_ctx object will control part of the operation of this
 * function.  The #FSL_SYM_CTX_INIT flag means that there is no context info in
 * the object.  The #FSL_SYM_CTX_LOAD means to use information in the
 * @a sym_ctx at the start of the operation, and the #FSL_SYM_CTX_SAVE flag
 * means to update the object's context information after the operation has
 * been performed.
 *
 * All of the data for an operation can be run through at once using the
 * #FSL_SYM_CTX_INIT or #FSL_SYM_CTX_LOAD flags, as appropriate, and then using
 * a @a length for the whole of the data.
 *
 * If a #FSL_SYM_CTX_SAVE flag were added, an additional call to the function
 * would "pick up" where the previous call left off, allowing the user to
 * perform the larger function in smaller steps.
 *
 * In #FSL_SYM_MODE_CBC and #FSL_SYM_MODE_ECB modes, the @a length must always
 * be a multiple of the block size for the algorithm being used.  For proper
 * operation in #FSL_SYM_MODE_CTR mode, the @a length must be a multiple of the
 * block size until the last operation on the total octet stream.
 *
 * Some users of ARC4 may want to compute the context (S-Box and pointers) from
 * the key before any data is available.  This may be done by running this
 * function with a @a length of zero, with the #FSL_SYM_CTX_INIT &
 * #FSL_SYM_CTX_SAVE flags on in the @a sym_ctx.  Subsequent operations would
 * then run as normal with the load & save flags.  Note that they key object is
 * still required.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param      key_info The key and algorithm being used in this operation.
 * @param[in,out] sym_ctx Info on cipher mode, state of the cipher.
 * @param      length   Length, in octets, of the ct (and pt).
 * @param      ct       pointer to ciphertext to be decrypted.
 * @param[out] pt       pointer to where to store the resulting plaintext.
 *
 * @return    A return code of type #fsl_shw_return_t
 *
 */
extern fsl_shw_return_t fsl_shw_symmetric_decrypt(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_scco_t* sym_ctx,
                                uint32_t length,
                                const uint8_t* ct,
                                uint8_t* pt);

/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-COA-HCO */
/* REQ-FSLSHW-PINTFC-API-BASIC-HASH-005 */
/**
 * Hash a stream of data with a cryptographic hash algorithm.
 *
 * The flags in the @a hash_ctx control the operation of this function.
 *
 * Hashing functions work on 64 octets of message at a time.  Therefore, when
 * any partial hashing of a long message is performed, the message @a length of
 * each segment must be a multiple of 64.  When ready to
 * #FSL_HASH_FLAGS_FINALIZE the hash, the @a length may be any value.
 *
 * With the #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_FINALIZE flags on, a
 * one-shot complete hash, including padding, will be performed.  The @a length
 * may be any value.
 *
 * The first octets of a data stream can be hashed by setting the
 * #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_SAVE flags.  The @a length must be
 * a multiple of 64.
 *
 * The flag #FSL_HASH_FLAGS_LOAD is used to load a context previously saved by
 * #FSL_HASH_FLAGS_SAVE.  The two in combination will allow a (multiple-of-64
 * octets) 'middle sequence' of the data stream to be hashed with the
 * beginning.  The @a length must again be a multiple of 64.
 *
 * Since the flag #FSL_HASH_FLAGS_LOAD is used to load a context previously
 * saved by #FSL_HASH_FLAGS_SAVE, the #FSL_HASH_FLAGS_LOAD and
 * #FSL_HASH_FLAGS_FINALIZE flags, used together, can be used to finish the
 * stream.  The @a length may be any value.
 *
 * If the user program wants to do the padding for the hash, it can leave off
 * the #FSL_HASH_FLAGS_FINALIZE flag.  The @a length must then be a multiple of
 * 64 octets.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param[in,out] hash_ctx Hashing algorithm and state of the cipher.
 * @param      msg       Pointer to the data to be hashed.
 * @param      length    Length, in octets, of the @a msg.
 * @param[out] result    If not null, pointer to where to store the hash
 *                       digest.
 * @param      result_len Number of octets to store in @a result.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_hash(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_hco_t* hash_ctx,
                                const uint8_t* msg,
                                uint32_t length,
                                uint8_t* result,
                                uint32_t result_len);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-API-BASIC-HMAC-001 */
/**
 * Precompute the Key hashes for an HMAC operation.
 *
 * This function may be used to calculate the inner and outer precomputes,
 * which are the hash contexts resulting from hashing the XORed key for the
 * 'inner hash' and the 'outer hash', respectively, of the HMAC function.
 *
 * After execution of this function, the @a hmac_ctx will contain the
 * precomputed inner and outer contexts, so that they may be used by
 * #fsl_shw_hmac().  The flags of @a hmac_ctx will be updated with
 * #FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT to mark their presence.  In addtion, the
 * #FSL_HMAC_FLAGS_INIT flag will be set.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param      key_info  The key being used in this operation.  Key must be
 *                       1 to 64 octets long.
 * @param[in,out] hmac_ctx The context which controls, by its flags and
 *                         algorithm, the operation of this function.
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_hmac_precompute(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_hmco_t* hmac_ctx);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-BASIC-HMAC-002 */
/**
 * Continue, finalize, or one-shot an HMAC operation.
 *
 * There are a number of ways to use this function.  The flags in the
 * @a hmac_ctx object will determine what operations occur.
 *
 * If #FSL_HMAC_FLAGS_INIT is set, then the hash will be started either from
 * the @a key_info, or from the precomputed inner hash value in the
 * @a hmac_ctx, depending on the value of #FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT.
 *
 * If, instead, #FSL_HMAC_FLAGS_LOAD is set, then the hash will be continued
 * from the ongoing inner hash computation in the @a hmac_ctx.
 *
 * If #FSL_HMAC_FLAGS_FINALIZE are set, then the @a msg will be padded, hashed,
 * the outer hash will be performed, and the @a result will be generated.
 *
 * If the #FSL_HMAC_FLAGS_SAVE flag is set, then the (ongoing or final) digest
 * value will be stored in the ongoing inner hash computation field of the @a
 * hmac_ctx.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param key_info       If #FSL_HMAC_FLAGS_INIT is set in the @a hmac_ctx,
 *                       this is the key being used in this operation, and the
 *                       IPAD.  If #FSL_HMAC_FLAGS_INIT is set in the @a
 *                       hmac_ctx and @a key_info is NULL, then
 *                       #fsl_shw_hmac_precompute() has been used to populate
 *                       the @a inner_precompute and @a outer_precompute
 *                       contexts.  If #FSL_HMAC_FLAGS_INIT is not set, this
 *                       parameter is ignored.

 * @param[in,out] hmac_ctx The context which controls, by its flags and
 *                       algorithm, the operation of this function.
 * @param      msg               Pointer to the message to be hashed.
 * @param      length            Length, in octets, of the @a msg.
 * @param[out] result            Pointer, of @a result_len octets, to where to
 *                               store the HMAC.
 * @param      result_len        Length of @a result buffer.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_hmac(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_hmco_t* hmac_ctx,
                                const uint8_t* msg,
                                uint32_t length,
                                uint8_t* result,
                                uint32_t result_len);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-BASIC-RNG-002 */
/**
 * Get random data.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param      length    The number of octets of @a data being requested.
 * @param[out] data      A pointer to a location of @a length octets to where
 *                       random data will be returned.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_get_random(
                                fsl_shw_uco_t* user_ctx,
                                uint32_t length,
                                uint8_t* data);


/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSLSHW-PINTFC-API-BASIC-RNG-003 */
/**
 * Add entropy to random number generator.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param      length    Number of bytes at @a data.
 * @param      data      Entropy to add to random number generator.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_add_entropy(
                                fsl_shw_uco_t* user_ctx,
                                uint32_t length,
                                uint8_t* data);

/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-COA-SKO */
/**
 * Perform Generation-Encryption by doing a Cipher and a Hash.
 *
 * Generate the authentication value @a auth_value as well as encrypt the @a
 * payload into @a ct (the ciphertext).  This is a one-shot function, so all of
 * the @a auth_data and the total message @a payload must passed in one call.
 * This also means that the flags in the @a auth_ctx must be #FSL_ACCO_CTX_INIT
 * and #FSL_ACCO_CTX_FINALIZE.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      auth_ctx         Controlling object for Authenticate-decrypt.
 * @param      cipher_key_info  The key being used for the cipher part of this
 *                              operation.  In CCM mode, this key is used for
 *                              both parts.
 * @param      auth_key_info    The key being used for the authentication part
 *                              of this operation.  In CCM mode, this key is
 *                              ignored and may be NULL.
 * @param      auth_data_length Length, in octets, of @a auth_data.
 * @param      auth_data        Data to be authenticated but not encrypted.
 * @param      payload_length   Length, in octets, of @a payload.
 * @param      payload          Pointer to the plaintext to be encrypted.
 * @param[out] ct               Pointer to the where the encrypted @a payload
 *                              will be stored.  Must be @a payload_length
 *                              octets long.
 * @param[out] auth_value       Pointer to where the generated authentication
 *                              field will be stored. Must be as many octets as
 *                              indicated by MAC length in the @a function_ctx.
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_gen_encrypt(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_acco_t* auth_ctx,
                                fsl_shw_sko_t* cipher_key_info,
                                fsl_shw_sko_t* auth_key_info,
                                uint32_t auth_data_length,
                                const uint8_t* auth_data,
                                uint32_t payload_length,
                                const uint8_t* payload,
                                uint8_t* ct,
                                uint8_t* auth_value);

/* REQ-FSL-SHW-PINTFC-COA-UCO */
/* REQ-FSL-SHW-PINTFC-COA-SKO */
/**
 * Perform Authentication-Decryption in Cipher + Hash.
 *
 * This function will perform a one-shot decryption of a data stream as well as
 * authenticate the authentication value.  This is a one-shot function, so all
 * of the @a auth_data and the total message @a payload must passed in one
 * call.  This also means that the flags in the @a auth_ctx must be
 * #FSL_ACCO_CTX_INIT and #FSL_ACCO_CTX_FINALIZE.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      auth_ctx         Controlling object for Authenticate-decrypt.
 * @param      cipher_key_info  The key being used for the cipher part of this
 *                              operation.  In CCM mode, this key is used for
 *                              both parts.
 * @param      auth_key_info    The key being used for the authentication part
 *                              of this operation.  In CCM mode, this key is
 *                              ignored and may be NULL.
 * @param      auth_data_length Length, in octets, of @a auth_data.
 * @param      auth_data        Data to be authenticated but not decrypted.
 * @param      payload_length   Length, in octets, of @a ct and @a pt.
 * @param      ct               Pointer to the encrypted input stream.
 * @param      auth_value       The (encrypted) authentication value which will
 *                              be authenticated.  This is the same data as the
 *                              (output) @a auth_value argument to
 *                              #fsl_shw_gen_encrypt().
 * @param[out] payload          Pointer to where the plaintext resulting from
 *                              the decryption will be stored.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
extern fsl_shw_return_t fsl_shw_auth_decrypt(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_acco_t* auth_ctx,
                                fsl_shw_sko_t* cipher_key_info,
                                fsl_shw_sko_t* auth_key_info,
                                uint32_t auth_data_length,
                                const uint8_t* auth_data,
                                uint32_t payload_length,
                                const uint8_t* ct,
                                const uint8_t* auth_value,
                                uint8_t* payload);

/*!
 * Cause the hardware to create a new random key for secure memory use.
 *
 * Have the hardware use the secure hardware random number generator to load a
 * new secret key into the hardware random key register.  It will not be made
 * active without a call to #fsl_shw_select_pf_key().
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
#ifdef __KERNEL__

extern fsl_shw_return_t fsl_shw_gen_random_pf_key(fsl_shw_uco_t * user_ctx);

#else

#define fsl_shw_gen_random_pf_key(user_ctx) FSL_RETURN_NO_RESOURCE_S

#endif				/* __KERNEL__ */

/*!
 * Retrieve the detected tamper event.
 *
 * Note that if more than one event was detected, this routine will only ever
 * return one of them.
 *
 * @param[in]  user_ctx         A user context from #fsl_shw_register_user().
 * @param[out] tamperp          Location to store the tamper information.
 * @param[out] timestampp       Locate to store timestamp from hardwhare when
 *                              an event was detected.
 *
 *
 * @return    A return code of type #fsl_shw_return_t (for instance, if the platform
 *            is not in a fail state.
 */
#ifdef __KERNEL__

extern fsl_shw_return_t fsl_shw_read_tamper_event(fsl_shw_uco_t * user_ctx,
						  fsl_shw_tamper_t * tamperp,
						  uint64_t * timestampp);
#else

#define fsl_shw_read_tamper_event(user_ctx,tamperp,timestampp)         \
    FSL_RETURN_NO_RESOURCE_S

#endif				/* __KERNEL__ */

/*****************************************************************************
 *
 * Functions internal to SHW driver.
 *
*****************************************************************************/

fsl_shw_return_t 
do_scc_encrypt_region(fsl_shw_uco_t* user_ctx,
                      void* partition_base, uint32_t offset_bytes,
                      uint32_t byte_count, uint8_t* black_data,
                      uint32_t* IV, fsl_shw_cypher_mode_t cypher_mode);

fsl_shw_return_t 
do_scc_decrypt_region(fsl_shw_uco_t* user_ctx,
                      void* partition_base, uint32_t offset_bytes,
                      uint32_t byte_count, const uint8_t* black_data,
                      uint32_t* IV, fsl_shw_cypher_mode_t cypher_mode);


/*****************************************************************************
 *
 * Functions available to other SHW-family drivers.
 *
*****************************************************************************/

#ifdef __KERNEL__
/**
 * Add an entry to a work/result queue.
 *
 * @param pool  Pointer to list structure
 * @param entry Entry to place at tail of list
 *
 * @return void
 */
inline static void SHW_ADD_QUEUE_ENTRY(shw_queue_t* pool,
                                       shw_queue_entry_t* entry)
{
    os_lock_context_t lock_context;

    entry->next = NULL;
    os_lock_save_context(shw_queue_lock, lock_context);

    if (pool->tail != NULL) {
        pool->tail->next = entry;
    } else {
        /* Queue was empty, so this is also the head. */
        pool->head = entry;
    }
    pool->tail = entry;

    os_unlock_restore_context(shw_queue_lock, lock_context);

    return;


}


/**
 * Get first entry on the queue and remove it from the queue.
 *
 * @return Pointer to first entry, or NULL if none.
 */
inline static shw_queue_entry_t* SHW_POP_FIRST_ENTRY(shw_queue_t* queue)
{
    shw_queue_entry_t* entry;
    os_lock_context_t lock_context;

    os_lock_save_context(shw_queue_lock, lock_context);

    entry = queue->head;

    if (entry != NULL) {
        queue->head = entry->next;
        entry->next = NULL;
        /* If this was only entry, clear the tail. */
        if (queue->tail == entry) {
            queue->tail = NULL;
        }
    }

    os_unlock_restore_context(shw_queue_lock, lock_context);

    return entry;
}



/**
 * Remove an entry from the list.
 *
 * If the entry not on the queue, no error will be returned.
 *
 * @param pool Pointer to work queue
 * @param entry Entry to remove from queue
 *
 * @return void
 *
 */
inline static void SHW_QUEUE_REMOVE_ENTRY(shw_queue_t* pool,
                                   shw_queue_entry_t* entry)
{
    os_lock_context_t lock_context;

    os_lock_save_context(shw_queue_lock, lock_context);

    /* Check for quick case.*/
    if (pool->head == entry) {
        pool->head = entry->next;
        entry->next = NULL;
        if (pool->tail == entry) {
            pool->tail = NULL;
        }
    } else {
        register shw_queue_entry_t* prev = pool->head;

        /* We know it is not the head, so start looking at entry after head. */
        while (prev->next) {
            if (prev->next != entry) {
                prev = prev->next; /* Try another */
                continue;
            } else {
                /* Unlink from chain. */
                prev->next = entry->next;
                entry->next = NULL;
                /* If last in chain, update tail. */
                if (pool->tail == entry) {
                    pool->tail = prev;
                }
                break;
            }
        } /* while */
    }

    os_unlock_restore_context(shw_queue_lock, lock_context);

    return;
}
#endif /* __KERNEL__ */


/*****************************************************************************
 *
 * Functions available to User-Mode API functions
 *
 ****************************************************************************/
#ifndef __KERNEL__


 /**
 * Sanity checks the user context object fields to ensure that they make some
 * sense before passing the uco as a parameter.
 *
 * @brief Verify the user context object
 *
 * @param  uco  user context object
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t validate_uco(fsl_shw_uco_t *uco);


/**
 * Initialize a request block to go to the driver.
 *
 * @param hdr      Pointer to request block header
 * @param user_ctx Pointer to user's context
 *
 * @return void
 */
inline static void init_req(struct shw_req_header* hdr,
                            fsl_shw_uco_t* user_ctx)
{
    hdr->flags = user_ctx->flags;
    hdr->user_ref = user_ctx->user_ref;
    hdr->code = FSL_RETURN_ERROR_S;

    return;
}


/**
 * Send a request block off to the driver.
 *
 * If this is a non-blocking request, then req will be freed.
 *
 * @param type  The type of request being sent
 * @param req   Pointer to the request block
 * @param ctx   Pointer to user's context
 *
 * @return code from driver if ioctl() succeeded, otherwise
 *              FSL_RETURN_INTERNAL_ERROR_S.
 */
inline static fsl_shw_return_t send_req(shw_user_request_t type,
                                        struct shw_req_header* req,
                                        fsl_shw_uco_t* ctx)
{
    fsl_shw_return_t ret = FSL_RETURN_INTERNAL_ERROR_S;
    unsigned blocking = ctx->flags & FSL_UCO_BLOCKING_MODE;
    int code;

    code = ioctl(ctx->openfd, SHW_IOCTL_REQUEST + type, req);

    if (code == 0) {
        if (blocking) {
            ret = req->code;
        } else {
            ret = FSL_RETURN_OK_S;
        }
    } else {
#ifdef FSL_DEBUG
        fprintf(stderr, "SHW: send_req failed with (%d), %s\n", errno,
                strerror(errno));
#endif
    }

    if (blocking) {
        free(req);
    }

    return ret;
}


#endif				/* no __KERNEL__ */

#if defined(FSL_HAVE_DRYICE)
/* Some kernel functions */
void fsl_shw_permute1_bytes(const uint8_t * key, uint8_t * permuted_key,
			    int key_count);
void fsl_shw_permute1_bytes_to_words(const uint8_t * key,
				     uint32_t * permuted_key, int key_count);

#define PFKEY_TO_STR(key_in)                                    \
({                                                              \
    di_key_t key = key_in;                                      \
                                                                \
    ((key == DI_KEY_FK) ? "IIM" :                               \
     ((key == DI_KEY_PK) ? "PRG" :                              \
      ((key == DI_KEY_RK) ? "RND" :                             \
       ((key == DI_KEY_FPK) ? "IIM_PRG" :                       \
        ((key == DI_KEY_FRK) ? "IIM_RND" : "unk")))));          \
})

#ifdef DIAG_SECURITY_FUNC
extern const char *di_error_string(int code);
#endif

#endif				/* HAVE DRYICE */

#endif				/* SHW_DRIVER_H */
