1 /* 2 * Copyright (c) 2025, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 #include <lib/libc/endian.h> 7 8 #include <drivers/delay_timer.h> 9 #include <drivers/tpm/tpm2.h> 10 #include <drivers/tpm/tpm2_chip.h> 11 #include <drivers/tpm/tpm2_interface.h> 12 13 #define CMD_SIZE_OFFSET 6 14 15 #define SINGLE_BYTE 1 16 #define TWO_BYTES 2 17 #define FOUR_BYTES 4 18 19 static struct interface_ops *interface; 20 21 static int tpm_xfer(struct tpm_chip_data *chip_data, const tpm_cmd *send, tpm_cmd *receive) 22 { 23 int ret; 24 25 ret = interface->send(chip_data, send); 26 if (ret < 0) { 27 return ret; 28 } 29 30 ret = interface->receive(chip_data, receive); 31 if (ret < 0) { 32 return ret; 33 } 34 35 return TPM_SUCCESS; 36 } 37 38 int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality) 39 { 40 int err; 41 42 interface = tpm_interface_getops(chip_data, locality); 43 44 err = interface->request_access(chip_data, locality); 45 if (err != 0) { 46 return err; 47 } 48 49 return interface->get_info(chip_data, locality); 50 } 51 52 int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality) 53 { 54 return interface->release_locality(chip_data, locality); 55 } 56 57 static int tpm_update_buffer(tpm_cmd *buf, uint32_t new_data, size_t new_len) 58 { 59 int i, j, start; 60 uint32_t command_size; 61 62 union { 63 uint8_t var8; 64 uint16_t var16; 65 uint32_t var32; 66 uint8_t array[4]; 67 } tpm_new_data; 68 69 command_size = be32toh(buf->header.cmd_size); 70 71 if (command_size + new_len > MAX_SIZE_CMDBUF) { 72 ERROR("%s: buf size exceeded, increase MAX_SIZE_CMDBUF\n", 73 __func__); 74 return TPM_INVALID_PARAM; 75 } 76 /* 77 * Subtract the cmd header size from the current command size 78 * so the data buffer is written to starting at index 0. 79 */ 80 start = command_size - TPM_HEADER_SIZE; 81 82 /* 83 * The TPM, according to the TCG spec, processes data in BE byte order, 84 * in the case where the Host is LE, htobe correctly handles the byte order. 85 * When updating the buffer, keep in mind to only pass sizeof(new_data) or 86 * the variable type size for the new_len function parameter. This ensures 87 * there is only the possiblility of writing 1, 2, or 4 bytes to the buffer, 88 * and that the correct number of bytes are written to data[i]. 89 */ 90 if (new_len == SINGLE_BYTE) { 91 tpm_new_data.var8 = new_data & 0xFF; 92 } else if (new_len == TWO_BYTES) { 93 tpm_new_data.var16 = htobe16(new_data & 0xFFFF); 94 } else if (new_len == FOUR_BYTES) { 95 tpm_new_data.var32 = htobe32(new_data); 96 } else { 97 ERROR("%s: Invalid data length\n", __func__); 98 return TPM_INVALID_PARAM; 99 } 100 101 for (i = start, j = 0; i < start + new_len; i++, j++) { 102 buf->data[i] = tpm_new_data.array[j]; 103 } 104 buf->header.cmd_size = htobe32(command_size + new_len); 105 106 return TPM_SUCCESS; 107 } 108 109 110 int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode) 111 { 112 tpm_cmd startup_cmd, startup_response; 113 uint32_t tpm_rc; 114 int ret; 115 116 memset(&startup_cmd, 0, sizeof(startup_cmd)); 117 memset(&startup_response, 0, sizeof(startup_response)); 118 119 startup_cmd.header.tag = htobe16(TPM_ST_NO_SESSIONS); 120 startup_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr)); 121 startup_cmd.header.cmd_code = htobe32(TPM_CMD_STARTUP); 122 123 ret = tpm_update_buffer(&startup_cmd, mode, sizeof(mode)); 124 if (ret < 0) { 125 return ret; 126 } 127 128 ret = tpm_xfer(chip_data, &startup_cmd, &startup_response); 129 if (ret < 0) { 130 return ret; 131 } 132 133 tpm_rc = be32toh(startup_response.header.cmd_code); 134 if (tpm_rc != TPM_RESPONSE_SUCCESS) { 135 ERROR("%s: response code contains error = %X\n", __func__, tpm_rc); 136 return TPM_ERR_RESPONSE; 137 } 138 139 return TPM_SUCCESS; 140 } 141 142 int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index, 143 uint16_t algorithm, const uint8_t *digest, 144 uint32_t digest_len) 145 { 146 tpm_cmd pcr_extend_cmd, pcr_extend_response; 147 uint32_t tpm_rc; 148 int ret; 149 150 memset(&pcr_extend_cmd, 0, sizeof(pcr_extend_cmd)); 151 memset(&pcr_extend_response, 0, sizeof(pcr_extend_response)); 152 153 if (digest == NULL) { 154 return TPM_INVALID_PARAM; 155 } 156 pcr_extend_cmd.header.tag = htobe16(TPM_ST_SESSIONS); 157 pcr_extend_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr)); 158 pcr_extend_cmd.header.cmd_code = htobe32(TPM_CMD_PCR_EXTEND); 159 160 /* handle (PCR Index)*/ 161 ret = tpm_update_buffer(&pcr_extend_cmd, index, sizeof(index)); 162 if (ret < 0) { 163 return ret; 164 } 165 166 /* authorization size , session handle, nonce size, attributes*/ 167 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_MIN_AUTH_SIZE, sizeof(uint32_t)); 168 if (ret < 0) { 169 return ret; 170 } 171 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_RS_PW, sizeof(uint32_t)); 172 if (ret < 0) { 173 return ret; 174 } 175 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_NONCE_SIZE, sizeof(uint16_t)); 176 if (ret < 0) { 177 return ret; 178 } 179 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ATTRIBUTES_DISABLE, sizeof(uint8_t)); 180 if (ret < 0) { 181 return ret; 182 } 183 184 /* hmac/password size */ 185 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_HMAC_SIZE, sizeof(uint16_t)); 186 if (ret < 0) { 187 return ret; 188 } 189 190 /* hashes count */ 191 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_SINGLE_HASH_COUNT, sizeof(uint32_t)); 192 if (ret < 0) { 193 return ret; 194 } 195 196 /* hash algorithm */ 197 ret = tpm_update_buffer(&pcr_extend_cmd, algorithm, sizeof(algorithm)); 198 if (ret < 0) { 199 return ret; 200 } 201 202 /* digest */ 203 for (int i = 0; i < digest_len; i++) { 204 ret = tpm_update_buffer(&pcr_extend_cmd, digest[i], sizeof(uint8_t)); 205 if (ret < 0) { 206 return ret; 207 } 208 } 209 210 ret = tpm_xfer(chip_data, &pcr_extend_cmd, &pcr_extend_response); 211 if (ret < 0) { 212 return ret; 213 } 214 215 tpm_rc = be32toh(pcr_extend_response.header.cmd_code); 216 if (tpm_rc != TPM_RESPONSE_SUCCESS) { 217 ERROR("%s: response code contains error = %X\n", __func__, tpm_rc); 218 return TPM_ERR_RESPONSE; 219 } 220 221 return TPM_SUCCESS; 222 } 223