return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
}
+u32 tpm2_auto_start(struct udevice *dev)
+{
+ u32 rc;
+
+ rc = tpm2_self_test(dev, TPMI_YES);
+
+ if (rc == TPM2_RC_INITIALIZE) {
+ rc = tpm2_startup(dev, TPM2_SU_CLEAR);
+ if (rc)
+ return rc;
+
+ rc = tpm2_self_test(dev, TPMI_YES);
+ }
+
+ return rc;
+}
+
u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
const ssize_t pw_sz)
{
* Calculate the offset of the nv_policy piece by adding each of the
* chunks below.
*/
- uint offset = 10 + 8 + 13 + 14;
+ const int platform_len = sizeof(u32);
+ const int session_hdr_len = 13;
+ const int message_len = 14;
+ uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
+ message_len;
u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* header 10 bytes */
tpm_u16(TPM2_ST_SESSIONS), /* TAG */
- tpm_u32(offset + nv_policy_size),/* Length */
+ tpm_u32(offset + nv_policy_size + 2),/* Length */
tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
- /* handles 8 bytes */
+ /* handles 4 bytes */
tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
/* session header 13 bytes */
tpm_u16(0), /* auth_size */
/* message 14 bytes + policy */
- tpm_u16(12 + nv_policy_size), /* size */
+ tpm_u16(message_len + nv_policy_size), /* size */
tpm_u32(space_index),
tpm_u16(TPM2_ALG_SHA256),
tpm_u32(nv_attributes),
tpm_u16(nv_policy_size),
- /* nv_policy */
+ /*
+ * nv_policy
+ * space_size
+ */
};
int ret;
* Fill the command structure starting from the first buffer:
* - the password (if any)
*/
- ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
- offset, nv_policy, nv_policy_size);
+ ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
+ offset, nv_policy, nv_policy_size,
+ offset + nv_policy_size, space_size);
if (ret)
return TPM_LIB_ERROR;
};
int ret;
+ if (!digest)
+ return -EINVAL;
/*
* Fill the command structure starting from the first buffer:
* - the digest
return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
}
+u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
+{
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_SESSIONS), /* TAG */
+ tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
+ tpm_u32(TPM2_CC_NV_READ), /* Command code */
+
+ /* handles 8 bytes */
+ tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
+ tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
+
+ /* AUTH_SESSION */
+ tpm_u32(9), /* Authorization size */
+ tpm_u32(TPM2_RS_PW), /* Session handle */
+ tpm_u16(0), /* Size of <nonce> */
+ /* <nonce> (if any) */
+ 0, /* Attributes: Cont/Excl/Rst */
+ tpm_u16(0), /* Size of <hmac/password> */
+ /* <hmac/password> (if any) */
+
+ tpm_u16(count), /* Number of bytes */
+ tpm_u16(0), /* Offset */
+ };
+ size_t response_len = COMMAND_BUFFER_SIZE;
+ u8 response[COMMAND_BUFFER_SIZE];
+ int ret;
+ u16 tag;
+ u32 size, code;
+
+ ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
+ if (ret)
+ return log_msg_ret("read", ret);
+ if (unpack_byte_string(response, response_len, "wdds",
+ 0, &tag, 2, &size, 6, &code,
+ 16, data, count))
+ return TPM_LIB_ERROR;
+
+ return 0;
+}
+
+u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
+ u32 count)
+{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ uint offset = 10 + 8 + 4 + 9 + 2;
+ uint len = offset + count + 2;
+ /* Use empty password auth if platform hierarchy is disabled */
+ u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
+ TPM2_RH_PLATFORM;
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_SESSIONS), /* TAG */
+ tpm_u32(len), /* Length */
+ tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
+
+ /* handles 8 bytes */
+ tpm_u32(auth), /* Primary platform seed */
+ tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
+
+ /* AUTH_SESSION */
+ tpm_u32(9), /* Authorization size */
+ tpm_u32(TPM2_RS_PW), /* Session handle */
+ tpm_u16(0), /* Size of <nonce> */
+ /* <nonce> (if any) */
+ 0, /* Attributes: Cont/Excl/Rst */
+ tpm_u16(0), /* Size of <hmac/password> */
+ /* <hmac/password> (if any) */
+
+ tpm_u16(count),
+ };
+ size_t response_len = COMMAND_BUFFER_SIZE;
+ u8 response[COMMAND_BUFFER_SIZE];
+ int ret;
+
+ ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
+ offset, data, count,
+ offset + count, 0);
+ if (ret)
+ return TPM_LIB_ERROR;
+
+ return tpm_sendrecv_command(dev, command_v2, response, &response_len);
+}
+
u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
- void *data, unsigned int *updates)
+ u16 algorithm, void *data, u32 digest_len,
+ unsigned int *updates)
{
u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* TPML_PCR_SELECTION */
tpm_u32(1), /* Number of selections */
- tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */
+ tpm_u16(algorithm), /* Algorithm of the hash */
idx_array_sz, /* Array size for selection */
/* bitmap(idx) Selected PCR bitmap */
};
if (ret)
return ret;
+ if (digest_len > response_len)
+ return TPM_LIB_ERROR;
+
if (unpack_byte_string(response, response_len, "ds",
10, &counter,
- response_len - TPM2_DIGEST_LEN, data,
- TPM2_DIGEST_LEN))
+ response_len - digest_len, data,
+ digest_len))
return TPM_LIB_ERROR;
if (updates)
return 0;
}
+
+u32 tpm2_write_lock(struct udevice *dev, u32 index)
+{
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_SESSIONS), /* TAG */
+ tpm_u32(10 + 8 + 13), /* Length */
+ tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
+
+ /* handles 8 bytes */
+ tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
+ tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
+
+ /* session header 9 bytes */
+ tpm_u32(9), /* Header size */
+ tpm_u32(TPM2_RS_PW), /* Password authorisation */
+ tpm_u16(0), /* nonce_size */
+ 0, /* session_attrs */
+ tpm_u16(0), /* auth_size */
+ };
+
+ return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
+
+u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
+{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_SESSIONS), /* TAG */
+ tpm_u32(10 + 4 + 13 + 5), /* Length */
+ tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
+
+ /* 4 bytes */
+ tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
+
+ /* session header 9 bytes */
+ tpm_u32(9), /* Header size */
+ tpm_u32(TPM2_RS_PW), /* Password authorisation */
+ tpm_u16(0), /* nonce_size */
+ 0, /* session_attrs */
+ tpm_u16(0), /* auth_size */
+
+ /* payload 5 bytes */
+ tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
+ 0, /* 0=disable */
+ };
+ int ret;
+
+ ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+ log_info("ret=%s, %x\n", dev->name, ret);
+ if (ret)
+ return ret;
+
+ priv->plat_hier_disabled = true;
+
+ return 0;
+}
+
+u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
+ u8 *recvbuf, size_t *recv_size)
+{
+ return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
+}
+
+u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
+ u8 *recvbuf, size_t *recv_size)
+{
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
+ tpm_u32(10 + 2), /* Length */
+ tpm_u32(vendor_cmd), /* Command code */
+
+ tpm_u16(vendor_subcmd),
+ };
+ int ret;
+
+ ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
+ log_debug("ret=%s, %x\n", dev->name, ret);
+ if (ret)
+ return ret;
+ if (*recv_size < 12)
+ return -ENODATA;
+ *recv_size -= 12;
+ memcpy(recvbuf, recvbuf + 12, *recv_size);
+
+ return 0;
+}
+
+u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
+ uint vendor_subcmd)
+{
+ u8 command_v2[COMMAND_BUFFER_SIZE] = {
+ /* header 10 bytes */
+ tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
+ tpm_u32(10 + 2), /* Length */
+ tpm_u32(vendor_cmd), /* Command code */
+
+ tpm_u16(vendor_subcmd),
+ };
+ int ret;
+
+ ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+ log_debug("ret=%s, %x\n", dev->name, ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}