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