/** @file
  Header file for HECI2 Message functionality

 @copyright
  INTEL CONFIDENTIAL
  Copyright 2016 - 2017 Intel Corporation.

  The source code contained or described herein and all documents related to the
  source code ("Material") are owned by Intel Corporation or its suppliers or
  licensors. Title to the Material remains with Intel Corporation or its suppliers
  and licensors. The Material may contain trade secrets and proprietary and
  confidential information of Intel Corporation and its suppliers and licensors,
  and is protected by worldwide copyright and trade secret laws and treaty
  provisions. No part of the Material may be used, copied, reproduced, modified,
  published, uploaded, posted, transmitted, distributed, or disclosed in any way
  without Intel's prior express written permission.

  No license under any patent, copyright, trade secret or other intellectual
  property right is granted to or conferred upon you by disclosure or delivery
  of the Materials, either expressly, by implication, inducement, estoppel or
  otherwise. Any license under such intellectual property rights must be
  express and approved by Intel in writing.

  Unless otherwise agreed by Intel in writing, you may not remove or alter
  this notice or any other notice embedded in Materials by Intel or
  Intel's suppliers or licensors in any way.

  This file contains an 'Intel Peripheral Driver' and is uniquely identified as
  "Intel Reference Module" and is licensed for Intel CPUs and chipsets under
  the terms of your license agreement with Intel or your vendor. This file may
  be modified by the user, subject to additional terms of the license agreement.

@par Specification
**/

#ifndef _HECI2_MESSAGE_LIB_H_
#define _HECI2_MESSAGE_LIB_H_

#include <Library/CircularBufferLib.h>
#include <Protocol/Heci.h>

#include <SecChipset.h>
#include <TrustedChannel.h>

/*
 ***********************************************
 * HECI2 Basic Message Size Definitions
 ************************************************
 */
#define HECI2_BIOS_MAX_WRITE_MSG_SIZE 2048  // Max supported HECI2 transaction size
#define HECI2_BIOS_MAX_READ_MSG_SIZE  512   // Size of the HECI HW circular buffer
#define HECI2_BIOS_MCA_FIXED_ADDR     14    // TODO - check this value

/*
 ***********************************************
 * HECI2 Global Definitions
 ************************************************
 */
#define MAX_DIR_NAME                      12
#define MAX_FILE_NAME                     25
#define HECI2_MAX_DATA_SIZE_READ_REQ      (HECI2_BIOS_MAX_READ_MSG_SIZE - (sizeof(HECI2_TRUSTED_CHANNEL_BIOS_HEADER) + sizeof(HECI2_READ_DATA_RESP)))
#define HECI2_MAX_DATA_SIZE_WRITE_REQ     (HECI2_BIOS_MAX_WRITE_MSG_SIZE - (sizeof(HECI2_TRUSTED_CHANNEL_BIOS_HEADER) + sizeof(HECI2_WRITE_DATA_REQ)))
#define MAX_HECI2_WRITE_DATA_SIZE         (ALIGN_VALUE (HECI2_MAX_DATA_SIZE_WRITE_REQ, sizeof (UINT32)) - sizeof (UINT32))
#define MAX_HECI2_READ_DATA_SIZE          (ALIGN_VALUE (HECI2_MAX_DATA_SIZE_READ_REQ, sizeof (UINT32)) - sizeof (UINT32))

/*
 ***********************************************
 * HECI2 Command Definitions
 ************************************************
 */
#define HECI2_READ_DATA_CMD_ID       0x1
#define HECI2_WRITE_DATA_CMD_ID      0x2
#define HECI2_FILE_SIZE_CMD_ID       0x3
#define HECI2_LOCK_DIR_CMD_ID        0x4
#define HECI2_GET_PROXY_STATE_CMD_ID 0x5
#define HECI2_GENERAL_ERR_ID         0xF     ///< Response for unknown command-id request

#define HECI2_BIOS_TO_CSE            0x0
#define HECI2_CSE_TO_BIOS            0x1

/*
 ***********************************************
 * HECI2 DATA Read/Write response status Definitions
 ************************************************
 */

#define BIOS_HECI2_STATUS_OK                  0x00
#define	BIOS_HECI2_STATUS_INVALID_PARAM       0x01
#define	BIOS_HECI2_STATUS_FILE_NOT_FOUND      0x02
#define	BIOS_HECI2_STATUS_AFTER_EOS           0x03 
#define	BIOS_HECI2_STATUS_DIR_LOCKED          0x04
#define	BIOS_HECI2_STATUS_NVM_INACCESSIBLE    0x05
#define	BIOS_HECI2_STATUS_TOO_MANY_DIR        0x06
#define	BIOS_HECI2_STATUS_COUNTER_INVALID     0x07
#define	BIOS_HECI2_STATUS_SIGN_INVALID        0x08
#define	BIOS_HECI2_STATUS_POST_EOP            0x09
#define	BIOS_HECI2_STATUS_POST_CORE_BIOS_DONE 0x0A
#define	BIOS_HECI2_STATUS_NO_QUOTA            0x0B
#define	BIOS_HECI2_STATUS_ERROR               0x0F
#define	BIOS_HECI2_STATUS_GEN_ERROR           0xFF 


#pragma pack(push, 1)
/*
 ***********************************************
 * HECI2 Request & Response
 ************************************************
 */
typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_GETPROXYSTATE_MSG {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              Status;                ///< Response status
} HECI2_TRUSTED_CHANNEL_BIOS_GETPROXYSTATE_MSG;

/*
 ***********************************************
 * HECI2 Requests
 ************************************************
 */
typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_READ_REQ {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              FileName [MAX_FILE_NAME];  ///< File Name in the BIOS directory
  UINT32                             Offset;                    ///< Offset within the file
  UINT16                             DataSize;                  ///< Number of bytes to read
} HECI2_TRUSTED_CHANNEL_BIOS_READ_REQ;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_WRITE_REQ {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              FileName [MAX_FILE_NAME];  ///< File Name in the BIOS directory
  UINT32                             Offset;                    ///< Offset within the file
  UINT16                             DataSize;                  ///< Number of bytes to write
  UINT8                              Truncate;                  ///< If set, the file will be truncated
} HECI2_TRUSTED_CHANNEL_BIOS_WRITE_REQ;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_NVMSIZE_REQ {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              FileName [MAX_FILE_NAME];  ///< File Name in the BIOS directory
} HECI2_TRUSTED_CHANNEL_BIOS_NVMSIZE_REQ;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_LOCKDIR_REQ {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              FileName [MAX_DIR_NAME];  ///< File Name in the BIOS directory
} HECI2_TRUSTED_CHANNEL_BIOS_LOCKDIR_REQ;

typedef struct _HECI2_READ_DATA_REQ
{
  UINT8          FileName [MAX_FILE_NAME];  ///< File Name in the BIOS directory
  UINT32         Offset;                    ///< Offset within the file
  UINT16         DataSize;                  ///< number of bytes to read/write
} HECI2_READ_DATA_REQ;

typedef struct _HECI2_WRITE_DATA_REQ
{
  UINT8          FileName [MAX_FILE_NAME];  /// File Name in the BIOS directory
  UINT32         Offset;                    ///< Offset within the file
  UINT16         DataSize;                  ///< number of bytes to read/write
  UINT8          Ttruncate;                 ///< If set the file will be truncated to length 0 before writing
} HECI2_WRITE_DATA_REQ;

typedef struct _HECI2_FILE_SIZE_REQ
{
  UINT8          FileName [MAX_FILE_NAME];  ///< File Name in the BIOS directory
} HECI2_FILE_SIZE_REQ;

typedef struct _HECI2_LOCK_DIR_REQ
{
  UINT8          DirName [MAX_DIR_NAME];    ///< Dir Name in the BIOS directory
} HECI2_LOCK_DIR_REQ;

/*
 ***********************************************
 * HECI2 Responses
 ************************************************
 */
typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_READ_RESP {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              Status;                ///< Status of the read operation
  UINT16                             DataSize;              ///< Number of bytes read
} HECI2_TRUSTED_CHANNEL_BIOS_READ_RESP;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_WRITE_RESP {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              Status;                ///< Response status
} HECI2_TRUSTED_CHANNEL_BIOS_WRITE_RESP;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_NVMSIZE_RESP {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              Status;                ///< Status of the file size operation
  UINT32                             DataSize;              ///< File size in bytes
} HECI2_TRUSTED_CHANNEL_BIOS_NVMSIZE_RESP;

typedef struct _HECI2_TRUSTED_CHANNEL_BIOS_LOCKDIR_RESP {
  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  TrustedChannelHeader;
  UINT8                              Status;                ///< Response status
} HECI2_TRUSTED_CHANNEL_BIOS_LOCKDIR_RESP;

typedef struct _HECI2_READ_DATA_RESP
{
  UINT8           Status;               ///< Status - see error list defined above
  UINT16          DataSize;             ///< number of bytes read
} HECI2_READ_DATA_RESP;

typedef struct _HECI2_WRITE_DATA_RESP
{
  UINT8           Status;               ///< Status - see error list defined above
} HECI2_WRITE_DATA_RESP;

typedef struct _HECI2_FILE_SIZE_RESP
{
  UINT8           Status;               ///< Status - see error list defined above
  UINT32          FileSize;             ///< File size in bytes
} HECI2_FILE_SIZE_RESP;

typedef struct _HECI2_LOCK_DIR_RESP
{
  UINT8           Status;               ///< Status - see error list defined above
} HECI2_LOCK_DIR_RESP;

/*
 ***********************************************
 * HECI2 BIOS Message Definitions
 ************************************************
 */
typedef struct _HECI2_BIOS_HEADER
{
  UINT8  req_resp       : 1;  ///< request = 0, response = 1  (HECI2_MSG_TYPE_XXX)
  UINT8  cmd_id         : 7;  ///< Command ID (XXX_CMD_ID)
} HECI2_BIOS_HEADER;

typedef struct _HECI2_BIOS_MESSAGE
{
  HECI2_BIOS_HEADER header;

  union
  {
    HECI2_READ_DATA_REQ     readReq;
    HECI2_WRITE_DATA_REQ    writeReq;
    HECI2_FILE_SIZE_REQ     fileSizeReq;
    HECI2_LOCK_DIR_REQ      lockDirReq;
    HECI2_READ_DATA_RESP    readResp;
    HECI2_WRITE_DATA_RESP   writeResp;
    HECI2_FILE_SIZE_RESP    fileSizeResp;
    HECI2_LOCK_DIR_RESP     lockDirResp;
    UINT8                   Status;
  } Body;
} HECI2_BIOS_MESSAGE;

//
//
typedef HECI2_BIOS_MESSAGE HECI2_BIOS_MASSAGE;

typedef struct _WRITE_TO_BIOS_DATA_CMD_REQ_DATA
{
  HECI2_BIOS_HEADER HECIHeader;
  UINT8             FileName [25];
  UINT32            Offset;
  UINT16            Size;
  UINT8             Truncate;
} WRITE_TO_BIOS_DATA_CMD_REQ_DATA;

typedef struct _WRITE_TO_BIOS_DATA_CMD_CMD_RESP_DATA
{
  HECI2_BIOS_HEADER       HECIHeader;
  UINT8                   Status;
} WRITE_TO_BIOS_DATA_CMD_RESP_DATA;

typedef struct _READ_TO_BIOS_DATA_CMD_REQ_DATA
{
  HECI2_BIOS_HEADER  HECIHeader;
  UINT8              FileName [25];
  UINT32             Offset;
  UINT16             Size;
} READ_TO_BIOS_DATA_CMD_REQ_DATA;

typedef struct _READ_TO_BIOS_DATA_CMD_CMD_RESP_DATA
{
  HECI2_BIOS_HEADER       HECIHeader;
  UINT8                   Status;               ///< Status - see error list defined above
  UINT16                  DataSize;             ///< number of bytes read
} READ_TO_BIOS_DATA_CMD_RESP_DATA;

typedef struct _GET_FILE_SIZE_CMD_REQ_DATA
{
  HECI2_BIOS_HEADER  HECIHeader;
  UINT8              FileName [25];
} GET_FILE_SIZE_CMD_REQ_DATA;

typedef struct _GET_FILE_SIZE_CMD_CMD_RESP_DATA
{
  HECI2_BIOS_HEADER       HECIHeader;
  UINT8                   Status;               ///< Status - see error list defined above
  UINT32                  FileSize;             ///< number of bytes read
} GET_FILE_SIZE_CMD_RESP_DATA;

typedef struct _HECI2_GET_PROXY_STATE_REQ
{
  HECI2_BIOS_HEADER        Header;
} HECI2_GET_PROXY_STATE_REQ;

typedef struct _HECI2_GET_PROXY_STATE_RESP
{
  HECI2_BIOS_HEADER        Header;
  UINT8                    Status;
} HECI2_GET_PROXY_STATE_RESP;

#pragma pack(pop)

/**
  Get the HECI2 read buffer size.

  @param       None

  @retval      UINTN   The HECI2 read buffer size in bytes.
**/
UINTN
EFIAPI
HeciGetHeci2ReadBufferSize (
  VOID
  );

/**
  Get the HECI2 write buffer size.

  @param       None

  @retval      UINTN   The HECI2 write buffer size in bytes.
**/
UINTN
EFIAPI
HeciGetHeci2WriteBufferSize (
  VOID
  );

/**
  Get NVM file's size through HECI2.

  @param[in]  FileName       The file name.
  @param[out] FileSize       The file's size.
  @param[in]  Heci2Protocol  A pointer to a HECI2 protocol instance.

  @return     EFI_SUCCESS    Get NVM file size success.
  @return     Others         Get NVM file size failed.
**/
EFI_STATUS
EFIAPI
Heci2GetNVMFileSize (
  IN  CONST  UINT8              *FileName,
  OUT        UINTN              *FileSize,
  IN  CONST  EFI_HECI_PROTOCOL  *Heci2Protocol
  );

/**
  Populate the CSE variable storage command queue with HMAC CSE NVM read commands.

  @param[in]     FileName              The file name.
  @param[in]     Offset                The offset of data.
  @param[in]     DataSize              The data size in bytes.
  @param[in,out] CommandQueueBuffer    A pointer to a buffer of EFI_CIRCULAR_BUFFER that holds the command queue

  @return        EFI_SUCCESS           The command queue was populated successfully.
  @return        Others                The command queue could not be populated successfully.
**/
EFI_STATUS
EFIAPI
PopulateCseReadFileCommandQueue (
  IN     CONST  UINT8                *FileName,
  IN            UINT32               Offset,
  IN            UINTN                DataSize,
  IN OUT        EFI_CIRCULAR_BUFFER  *CommandQueueBuffer
  );

/**
  Populate the CSE variable storage command queue with HMAC CSE NVM write commands.

  @param[in]     FileName              The file name.
  @param[in]     Offset                The offset of data in the file.
  @param[in]     Data                  The data buffer.
  @param[in]     DataSize              The data size in bytes.
  @param[in]     Truncate              Indicates if the file should be truncated.
  @param[in,out] CommandQueueBuffer    A pointer to a buffer of EFI_CIRCULAR_BUFFER that holds the command queue

  @return        EFI_SUCCESS           The command queue was populated successfully.
  @return        Others                The command queue could not be populated successfully.
**/
EFI_STATUS
EFIAPI
PopulateCseWriteFileCommandQueue (
  IN      CONST CHAR8                *FileName,
  IN            UINT32               Offset,
  IN      CONST UINT8                *Data,
  IN            UINTN                DataSize,
  IN            BOOLEAN              Truncate,
  IN OUT        EFI_CIRCULAR_BUFFER  *CommandQueueBuffer
  );

/**
  Lock Directory message through HECI2.

  @param[in] DirName   The Directory name.
  @param[in] Heci2Protocol The HECI protocol to send the message to HECI2 device.

  @return EFI_SUCCESS   Send EOP message success.
  @return Others              Send EOP message failed.
**/
EFI_STATUS
EFIAPI
Heci2LockDirectory (
  IN UINT8              *DirName,
  IN EFI_HECI_PROTOCOL  *Heci2Protocol
  );

/**
  Returns a signed HECI Trusted Channel Get Proxy State message header.

  @param[out] MessageRequestHeader  A pointer the buffer that contains the Get Proxy State header.

  @return     EFI_SUCCESS      Constructed and signed the Get Proxy State message header successfully.
  @return     Others           Failed to construct and sign the Get Proxy State message header.
**/
EFI_STATUS
EFIAPI
Heci2GetProxyStateMessageHeader (
  OUT  HECI2_TRUSTED_CHANNEL_BIOS_HEADER  *TrustedChannelHeader
  );

/**
  Start dispatch of commands in the given HECI2 NVM file command queue.

  @param[in]      CommandQueue                        A pointer to the command queue buffer.
  @param[in]      CommandQueueSize                    The command queue buffer size in bytes.
  @param[in]      CommandQueueVerificationBuffer      A pointer to the command queue verification buffer.
  @param[in]      CommandQueueVerificationBufferSize  The command queue verification buffer size in bytes.
  @param[in]      CommandQueueCount                   The number of items in the command queue.

  @retval         EFI_SUCCESS                         Command queue disptach was enabled successfully
  @retval         Others                              An error occurred starting command queue dispatch
**/
EFI_STATUS
EFIAPI
StartHeci2SmmCommandQueueDispatch (
  IN    UINT8     *CommandQueue,
  IN    UINTN     CommandQueueSize,
  IN    UINT8     *CommandQueueVerificationBuffer,
  IN    UINTN     CommandQueueVerificationBufferSize,
  IN    UINTN     CommandQueueCount
  );

/**
  Write data to NVM file through HECI2.

  @param[in] FileName          The file name.
  @param[in] Offset            The offset of data.
  @param[in] Data              The data content.
  @param[in] DataSize          Data's size.
  @param[in] Truncate          Truncate the file.
  @param[in] Heci2Protocol     A pointer to a valid instance of the EFI_HECI_PROTOCOL

  @return EFI_SUCCESS   Write NVM file success.
  @return Others        Write NVM file failed.
**/
EFI_STATUS
EFIAPI
Heci2WriteNVMFile (
  IN CONST CHAR8              *FileName,
  IN       UINT32             Offset,
  IN CONST UINT8              *Data,
  IN       UINTN              DataSize,
  IN       BOOLEAN            Truncate,
  IN CONST EFI_HECI_PROTOCOL  *Heci2Protocol
  );

/**
  Read NVM file data through HECI2.

  @param[in]     FileName       The file name.
  @param[in]     Offset         The offset of data.
  @param[out]    Data           The data buffer.
  @param[in,out] DataSize       Data's size.
  @param[in]     Heci2Protocol  Pointer to a HECI2 protocol instance.

  @return        EFI_SUCCESS    Read NVM file success.
  @return        Others         Read NVM file failed.
**/
EFI_STATUS
EFIAPI
Heci2ReadNVMFile (
  IN     CONST  UINT8               *FileName,
  IN            UINT32              Offset,
  OUT           UINT8               *Data,
  IN OUT        UINTN               *DataSize,
  IN     CONST  EFI_HECI_PROTOCOL   *Heci2Protocol
  );

EFI_STATUS
EFIAPI
Heci2ReadNVMFileNoResp (
  IN UINT8              *FileName,
  IN UINT32              Offset,
  IN UINT8              *Data,
  IN UINTN              *DataSize,
  IN EFI_HECI_PROTOCOL  *Heci2Protocol
  );

#endif
