/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
//** Index Type Definitions

// These definitions allow the same code to be used pre and post 1.21. The main
// action is to redefine the index type values from the bit values.
// Use TPM_NT_ORDINARY to indicate if the TPM_NT type is defined

#ifndef _NV_H_
#define _NV_H_

#ifdef TPM_NT_ORDINARY
// If TPM_NT_ORDINARY is defined, then the TPM_NT field is present in a TPMA_NV
#  define GET_TPM_NT(attributes) GET_ATTRIBUTE(attributes, TPMA_NV, TPM_NT)
#else
// If TPM_NT_ORDINARY is not defined, then need to synthesize it from the
// attributes
#  define GetNv_TPM_NV(attributes)                    \
    (IS_ATTRIBUTE(attributes, TPMA_NV, COUNTER)       \
     + (IS_ATTRIBUTE(attributes, TPMA_NV, BITS) << 1) \
     + (IS_ATTRIBUTE(attributes, TPMA_NV, EXTEND) << 2))
#  define TPM_NT_ORDINARY (0)
#  define TPM_NT_COUNTER  (1)
#  define TPM_NT_BITS     (2)
#  define TPM_NT_EXTEND   (4)
#endif

//** Attribute Macros
// These macros are used to isolate the differences in the way that the index type
// changed in version 1.21 of the specification
#define IsNvOrdinaryIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_ORDINARY)

#define IsNvCounterIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_COUNTER)

#define IsNvBitsIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_BITS)

#define IsNvExtendIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_EXTEND)

#ifdef TPM_NT_PIN_PASS
#  define IsNvPinPassIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_PIN_PASS)
#endif

#ifdef TPM_NT_PIN_FAIL
#  define IsNvPinFailIndex(attributes) (GET_TPM_NT(attributes) == TPM_NT_PIN_FAIL)
#endif

typedef struct
{
    UINT32     size;
    TPM_HANDLE handle;
} NV_ENTRY_HEADER;

#define NV_EVICT_OBJECT_SIZE (sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(OBJECT))

#define NV_INDEX_COUNTER_SIZE (sizeof(UINT32) + sizeof(NV_INDEX) + sizeof(UINT64))

#define NV_RAM_INDEX_COUNTER_SIZE (sizeof(NV_RAM_HEADER) + sizeof(UINT64))

typedef struct
{
    UINT32     size;
    TPM_HANDLE handle;
    TPMA_NV    attributes;
} NV_RAM_HEADER;

// Defines the end-of-list marker for NV. The list terminator is
// a UINT32 of zero, followed by the current value of s_maxCounter which is a
// 64-bit value. The structure is defined as an array of 3 UINT32 values so that
// there is no padding between the  UINT32 list end marker and the UINT64 maxCounter
// value.
typedef UINT32 NV_LIST_TERMINATOR[3];

//** Orderly RAM Values
// The following defines are for accessing orderly RAM values.

// This is the initialize for the RAM reference iterator.
#define NV_RAM_REF_INIT 0
// This is the starting address of the RAM space used for orderly data
#define RAM_ORDERLY_START (&s_indexOrderlyRam[0])
// This is the offset within NV that is used to save the orderly data on an
// orderly shutdown.
#define NV_ORDERLY_START (NV_INDEX_RAM_DATA)
// This is the end of the orderly RAM space. It is actually the first byte after the
// last byte of orderly RAM data
#define RAM_ORDERLY_END (RAM_ORDERLY_START + sizeof(s_indexOrderlyRam))
// This is the end of the orderly space in NV memory. As with RAM_ORDERLY_END, it is
// actually the offset of the first byte after the end of the NV orderly data.
#define NV_ORDERLY_END (NV_ORDERLY_START + sizeof(s_indexOrderlyRam))

// Macro to check that an orderly RAM address is with range.
#define ORDERLY_RAM_ADDRESS_OK(start, offset) \
  ((start >= RAM_ORDERLY_START) && ((start + offset - 1) < RAM_ORDERLY_END))

#define RETURN_IF_NV_IS_NOT_AVAILABLE \
  {                                   \
    if(g_NvStatus != TPM_RC_SUCCESS)  \
      return g_NvStatus;              \
  }

// Routinely have to clear the orderly flag and fail if the
// NV is not available so that it can be cleared.
#define RETURN_IF_ORDERLY                  \
  {                                        \
    if(NvClearOrderly() != TPM_RC_SUCCESS) \
      return g_NvStatus;                   \
  }

#define NV_IS_AVAILABLE (g_NvStatus == TPM_RC_SUCCESS)

#define IS_ORDERLY(value) (value < SU_DA_USED_VALUE)

#define NV_IS_ORDERLY (IS_ORDERLY(gp.orderlyState))

// Macro to set the NV UPDATE_TYPE. This deals with the fact that the update is
// possibly a combination of UT_NV and UT_ORDERLY.
#define SET_NV_UPDATE(type) g_updateNV |= (type)

#endif  // _NV_H_