/*
 * Copyright 2016 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef __SRC_LIB_TPM2_TLCL_STRUCTURES_H
#define __SRC_LIB_TPM2_TLCL_STRUCTURES_H

/*
 * This file includes a subset of definitions of TPM protocol version 2.x
 * constants and structures needed for functions used in coreboot.
 */
#include <stdint.h>
#include <tpm_lite/tlcl.h>
#include <types.h>

/* This should be plenty for what firmware needs. */
#define TPM_BUFFER_SIZE 256

/* Basic TPM2 types. */
typedef uint16_t TPM_SU;
typedef uint16_t TPM_ALG_ID;
typedef uint32_t TPM_CC;
typedef uint32_t TPM_HANDLE;
typedef uint32_t TPM_RC;
typedef uint8_t TPMI_YES_NO;
typedef TPM_ALG_ID TPMI_ALG_HASH;
typedef TPM_HANDLE TPMI_DH_PCR;
typedef TPM_HANDLE TPMI_RH_NV_INDEX;
typedef TPM_HANDLE TPMI_RH_PROVISION;
typedef TPM_HANDLE TPMI_SH_AUTH_SESSION;
typedef TPM_HANDLE TPM_RH;

/* Some hardcoded algorithm values. */
#define TPM_ALG_HMAC   ((TPM_ALG_ID)0x0005)
#define TPM_ALG_NULL   ((TPM_ALG_ID)0x0010)
#define TPM_ALG_SHA1   ((TPM_ALG_ID)0x0004)
#define TPM_ALG_SHA256 ((TPM_ALG_ID)0x000b)

#define SHA256_DIGEST_SIZE 32

/* Some hardcoded hierarchies. */
#define TPM_RH_NULL         0x40000007
#define TPM_RS_PW           0x40000009
#define TPM_RH_PLATFORM     0x4000000C

typedef struct {
	uint16_t      size;
	uint8_t       *buffer;
} TPM2B;

/* Relevant TPM Command's structures. */
/* Common command/response header. */
struct tpm_header {
	uint16_t tpm_tag;
	uint32_t tpm_size;
	TPM_CC tpm_code;
} __attribute__((packed));

/* TPM command codes. */
#define TPM2_Clear          ((TPM_CC)0x00000126)
#define TPM2_NV_DefineSpace ((TPM_CC)0x0000012A)
#define TPM2_NV_Write       ((TPM_CC)0x00000137)
#define TPM2_NV_WriteLock   ((TPM_CC)0x00000138)
#define TPM2_SelfTest       ((TPM_CC)0x00000143)
#define TPM2_Startup        ((TPM_CC)0x00000144)
#define TPM2_NV_Read        ((TPM_CC)0x0000014E)
#define TPM2_GetCapability  ((TPM_CC)0x0000017A)
#define TPM2_PCR_Extend     ((TPM_CC)0x00000182)

/* Startup values. */
#define TPM_SU_CLEAR 0
#define TPM_SU_STATE 1

#define TPM_HT_PCR             0x00
#define TPM_HT_NV_INDEX        0x01
#define TPM_HT_HMAC_SESSION    0x02
#define TPM_HT_POLICY_SESSION  0x03

#define HR_SHIFT               24
#define HR_PCR                (TPM_HT_PCR <<  HR_SHIFT)
#define HR_HMAC_SESSION       (TPM_HT_HMAC_SESSION <<  HR_SHIFT)
#define HR_POLICY_SESSION     (TPM_HT_POLICY_SESSION <<  HR_SHIFT)
#define HR_TRANSIENT          (TPM_HT_TRANSIENT <<  HR_SHIFT)
#define HR_PERSISTENT         (TPM_HT_PERSISTENT <<  HR_SHIFT)
#define HR_NV_INDEX           (TPM_HT_NV_INDEX <<  HR_SHIFT)
#define HR_PERMANENT          (TPM_HT_PERMANENT <<  HR_SHIFT)
#define PCR_FIRST             (HR_PCR + 0)
#define PCR_LAST              (PCR_FIRST + IMPLEMENTATION_PCR-1)
#define HMAC_SESSION_FIRST    (HR_HMAC_SESSION + 0)
#define HMAC_SESSION_LAST     (HMAC_SESSION_FIRST+MAX_ACTIVE_SESSIONS-1)
#define LOADED_SESSION_FIRST  HMAC_SESSION_FIRST
#define LOADED_SESSION_LAST   HMAC_SESSION_LAST
#define POLICY_SESSION_FIRST  (HR_POLICY_SESSION + 0)
#define POLICY_SESSION_LAST   (POLICY_SESSION_FIRST + MAX_ACTIVE_SESSIONS-1)
#define TRANSIENT_FIRST       (HR_TRANSIENT + 0)
#define ACTIVE_SESSION_FIRST  POLICY_SESSION_FIRST
#define ACTIVE_SESSION_LAST   POLICY_SESSION_LAST
#define TRANSIENT_LAST        (TRANSIENT_FIRST+MAX_LOADED_OBJECTS-1)
#define PERSISTENT_FIRST      (HR_PERSISTENT + 0)
#define PERSISTENT_LAST       (PERSISTENT_FIRST + 0x00FFFFFF)
#define PLATFORM_PERSISTENT   (PERSISTENT_FIRST + 0x00800000)
#define NV_INDEX_FIRST        (HR_NV_INDEX + 0)
#define NV_INDEX_LAST         (NV_INDEX_FIRST + 0x00FFFFFF)
#define PERMANENT_FIRST       TPM_RH_FIRST
#define PERMANENT_LAST        TPM_RH_LAST

/* Tpm2 command tags. */
#define TPM_ST_NO_SESSIONS 0x8001
#define TPM_ST_SESSIONS    0x8002

#define RC_VER1                                         0x100
#define TPM_RC_INITIALIZE         ((TPM_RC)(RC_VER1 + 0x000))

/* TPM command structures. */

struct tpm2_startup {
	TPM_SU  startup_type;
};

/* Various TPM capability types to use when querying the device. */
typedef uint32_t TPM_CAP;
#define TPM_CAP_TPM_PROPERTIES   ((TPM_CAP)0x00000006)

typedef TPM_HANDLE TPMI_RH_NV_AUTH;
typedef TPM_HANDLE TPMI_RH_NV_INDEX;

/* TPM Property capability constants. */
typedef uint32_t TPM_PT;
#define PT_GROUP                                   0x00000100
#define PT_VAR                                 (PT_GROUP * 2)
#define TPM_PT_PERMANENT               ((TPM_PT)(PT_VAR + 0))

/* Structures of payloads of various TPM2 commands. */
struct tpm2_get_capability {
	TPM_CAP capability;
	uint32_t property;
	uint32_t propertyCount;
};

/* get_capability response when PT_PERMANENT is requested. */
typedef struct {
	uint32_t ownerAuthSet       : 1;
	uint32_t endorsementAuthSet : 1;
	uint32_t lockoutAuthSet     : 1;
	uint32_t reserved3_7        : 5;
	uint32_t disableClear       : 1;
	uint32_t inLockout          : 1;
	uint32_t tpmGeneratedEPS    : 1;
	uint32_t reserved11_31      : 21;
} TPMA_PERMANENT;

typedef struct {
	uint32_t TPMA_NV_PPWRITE        : 1;
	uint32_t TPMA_NV_OWNERWRITE     : 1;
	uint32_t TPMA_NV_AUTHWRITE      : 1;
	uint32_t TPMA_NV_POLICYWRITE    : 1;
	uint32_t TPMA_NV_COUNTER        : 1;
	uint32_t TPMA_NV_BITS           : 1;
	uint32_t TPMA_NV_EXTEND         : 1;
	uint32_t reserved7_9            : 3;
	uint32_t TPMA_NV_POLICY_DELETE  : 1;
	uint32_t TPMA_NV_WRITELOCKED    : 1;
	uint32_t TPMA_NV_WRITEALL       : 1;
	uint32_t TPMA_NV_WRITEDEFINE    : 1;
	uint32_t TPMA_NV_WRITE_STCLEAR  : 1;
	uint32_t TPMA_NV_GLOBALLOCK     : 1;
	uint32_t TPMA_NV_PPREAD         : 1;
	uint32_t TPMA_NV_OWNERREAD      : 1;
	uint32_t TPMA_NV_AUTHREAD       : 1;
	uint32_t TPMA_NV_POLICYREAD     : 1;
	uint32_t reserved20_24          : 5;
	uint32_t TPMA_NV_NO_DA          : 1;
	uint32_t TPMA_NV_ORDERLY        : 1;
	uint32_t TPMA_NV_CLEAR_STCLEAR  : 1;
	uint32_t TPMA_NV_READLOCKED     : 1;
	uint32_t TPMA_NV_WRITTEN        : 1;
	uint32_t TPMA_NV_PLATFORMCREATE : 1;
	uint32_t TPMA_NV_READ_STCLEAR   : 1;
} TPMA_NV;

typedef union {
	struct {
		uint16_t  size;
		const uint8_t   *buffer;
	} t;
	TPM2B b;
} TPM2B_DIGEST;

typedef TPM2B_DIGEST TPM2B_AUTH;
typedef TPM2B_DIGEST TPM2B_NONCE;

typedef struct {
	TPM_PT  property;
	uint32_t  value;
} TPMS_TAGGED_PROPERTY;

#define MAX_CAP_DATA (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - \
		      sizeof(TPMI_YES_NO) - sizeof(TPM_CAP) - sizeof(uint32_t))
#define MAX_TPM_PROPERTIES  (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))

/* Somewhat arbitrary, leave enough room for command wrappers. */
#define MAX_NV_BUFFER_SIZE (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - 50)

typedef struct {
	uint32_t              count;
	TPMS_TAGGED_PROPERTY  tpmProperty[MAX_TPM_PROPERTIES];
} TPML_TAGGED_TPM_PROPERTY;

typedef union {
	TPML_TAGGED_TPM_PROPERTY  tpmProperties;
} TPMU_CAPABILITIES;

typedef struct {
	TPM_CAP            capability;
	TPMU_CAPABILITIES  data;
} TPMS_CAPABILITY_DATA;

struct get_cap_response {
	TPMI_YES_NO more_data;
	TPMS_CAPABILITY_DATA cd;
};

typedef struct {
	TPMI_RH_NV_INDEX  nvIndex;
	TPMI_ALG_HASH     nameAlg;
	TPMA_NV           attributes;
	TPM2B_DIGEST      authPolicy;
	uint16_t          dataSize;
} TPMS_NV_PUBLIC;

typedef union {
	struct {
		uint16_t        size;
		TPMS_NV_PUBLIC  nvPublic;
	} t;
	TPM2B b;
} TPM2B_NV_PUBLIC;

typedef union {
	struct {
		uint16_t  size;
		const uint8_t   *buffer;
	} t;
	TPM2B b;
} TPM2B_MAX_NV_BUFFER;

/*
 * This is a union, but as of now we support just one digest - sha256, so
 * there is just one element.
 */
typedef union {
	uint8_t  sha256[SHA256_DIGEST_SIZE];
} TPMU_HA;

typedef struct {
	TPMI_ALG_HASH  hashAlg;
	TPMU_HA        digest;
} TPMT_HA;

typedef struct {
	uint32_t   count;
	TPMT_HA  digests[1];  /* Limit max number of hashes to 1. */
} TPML_DIGEST_VALUES;

struct nv_read_response {
	uint32_t params_size;
	TPM2B_MAX_NV_BUFFER buffer;
};

struct tpm2_session_attrs {
	uint8_t continueSession : 1;
	uint8_t auditExclusive  : 1;
	uint8_t auditReset      : 1;
	uint8_t reserved3_4     : 2;
	uint8_t decrypt         : 1;
	uint8_t encrypt         : 1;
	uint8_t audit           : 1;
};

/*
 * TPM session header for commands requiring session information. Also
 * included in the responses to those commands.
 */
struct tpm2_session_header {
	uint32_t session_handle;
	uint16_t nonce_size;
	uint8_t *nonce;
	union {
		struct tpm2_session_attrs session_attr_bits;
		uint8_t session_attrs;
	}  __attribute__((packed));
	uint16_t auth_size;
	uint8_t *auth;
};

struct tpm2_response {
	struct tpm_header hdr;
	union {
		struct get_cap_response gc;
		struct nv_read_response nvr;
		struct tpm2_session_header def_space;
	};
};

struct tpm2_nv_define_space_cmd {
	TPM2B_AUTH auth;
	TPMS_NV_PUBLIC publicInfo;
};

struct tpm2_nv_write_cmd {
	TPMI_RH_NV_INDEX nvIndex;
	TPM2B_MAX_NV_BUFFER data;
	uint16_t offset;
};

struct tpm2_self_test {
	TPMI_YES_NO yes_no;
};

struct tpm2_nv_read_cmd {
	TPMI_RH_NV_INDEX nvIndex;
	uint16_t size;
	uint16_t offset;
};

struct tpm2_nv_write_lock_cmd {
	TPMI_RH_NV_INDEX nvIndex;
};

struct tpm2_pcr_extend_cmd {
	TPMI_DH_PCR pcrHandle;
	TPML_DIGEST_VALUES digests;
};

#endif // __SRC_LIB_TPM2_TLCL_STRUCTURES_H