uboot/lib/tpm-common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2013 The Chromium OS Authors.
   4 * Coypright (c) 2013 Guntermann & Drunck GmbH
   5 */
   6
   7#define LOG_CATEGORY UCLASS_TPM
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <log.h>
  12#include <asm/unaligned.h>
  13#include <tpm-common.h>
  14#include "tpm-utils.h"
  15
  16enum tpm_version tpm_get_version(struct udevice *dev)
  17{
  18        struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
  19
  20        return priv->version;
  21}
  22
  23int pack_byte_string(u8 *str, size_t size, const char *format, ...)
  24{
  25        va_list args;
  26        size_t offset = 0, length = 0;
  27        u8 *data = NULL;
  28        u32 value = 0;
  29
  30        va_start(args, format);
  31        for (; *format; format++) {
  32                switch (*format) {
  33                case 'b':
  34                        offset = va_arg(args, size_t);
  35                        value = va_arg(args, int);
  36                        length = 1;
  37                        break;
  38                case 'w':
  39                        offset = va_arg(args, size_t);
  40                        value = va_arg(args, int);
  41                        length = 2;
  42                        break;
  43                case 'd':
  44                        offset = va_arg(args, size_t);
  45                        value = va_arg(args, u32);
  46                        length = 4;
  47                        break;
  48                case 's':
  49                        offset = va_arg(args, size_t);
  50                        data = va_arg(args, u8 *);
  51                        length = va_arg(args, u32);
  52                        break;
  53                default:
  54                        debug("Couldn't recognize format string\n");
  55                        va_end(args);
  56                        return -1;
  57                }
  58
  59                if (offset + length > size) {
  60                        va_end(args);
  61                        return -1;
  62                }
  63
  64                switch (*format) {
  65                case 'b':
  66                        str[offset] = value;
  67                        break;
  68                case 'w':
  69                        put_unaligned_be16(value, str + offset);
  70                        break;
  71                case 'd':
  72                        put_unaligned_be32(value, str + offset);
  73                        break;
  74                case 's':
  75                        memcpy(str + offset, data, length);
  76                        break;
  77                }
  78        }
  79        va_end(args);
  80
  81        return 0;
  82}
  83
  84int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
  85{
  86        va_list args;
  87        size_t offset = 0, length = 0;
  88        u8 *ptr8 = NULL;
  89        u16 *ptr16 = NULL;
  90        u32 *ptr32 = NULL;
  91
  92        va_start(args, format);
  93        for (; *format; format++) {
  94                switch (*format) {
  95                case 'b':
  96                        offset = va_arg(args, size_t);
  97                        ptr8 = va_arg(args, u8 *);
  98                        length = 1;
  99                        break;
 100                case 'w':
 101                        offset = va_arg(args, size_t);
 102                        ptr16 = va_arg(args, u16 *);
 103                        length = 2;
 104                        break;
 105                case 'd':
 106                        offset = va_arg(args, size_t);
 107                        ptr32 = va_arg(args, u32 *);
 108                        length = 4;
 109                        break;
 110                case 's':
 111                        offset = va_arg(args, size_t);
 112                        ptr8 = va_arg(args, u8 *);
 113                        length = va_arg(args, u32);
 114                        break;
 115                default:
 116                        va_end(args);
 117                        debug("Couldn't recognize format string\n");
 118                        return -1;
 119                }
 120
 121                if (offset + length > size) {
 122                        va_end(args);
 123                        log_err("Failed to read: size=%zd, offset=%zx, len=%zx\n",
 124                                size, offset, length);
 125                        return -1;
 126                }
 127
 128                switch (*format) {
 129                case 'b':
 130                        *ptr8 = str[offset];
 131                        break;
 132                case 'w':
 133                        *ptr16 = get_unaligned_be16(str + offset);
 134                        break;
 135                case 'd':
 136                        *ptr32 = get_unaligned_be32(str + offset);
 137                        break;
 138                case 's':
 139                        memcpy(ptr8, str + offset, length);
 140                        break;
 141                }
 142        }
 143        va_end(args);
 144
 145        return 0;
 146}
 147
 148u32 tpm_command_size(const void *command)
 149{
 150        const size_t command_size_offset = 2;
 151
 152        return get_unaligned_be32(command + command_size_offset);
 153}
 154
 155u32 tpm_return_code(const void *response)
 156{
 157        const size_t return_code_offset = 6;
 158
 159        return get_unaligned_be32(response + return_code_offset);
 160}
 161
 162u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
 163                         void *response, size_t *size_ptr)
 164{
 165        int err, ret;
 166        u8 response_buffer[COMMAND_BUFFER_SIZE];
 167        size_t response_length;
 168        int i;
 169        uint size;
 170
 171        if (response) {
 172                response_length = *size_ptr;
 173        } else {
 174                response = response_buffer;
 175                response_length = sizeof(response_buffer);
 176        }
 177
 178        size = tpm_command_size(command);
 179
 180        /* sanity check, which also helps coverity */
 181        if (size > COMMAND_BUFFER_SIZE)
 182                return log_msg_ret("size", -E2BIG);
 183
 184        log_debug("TPM request [size:%d]: ", size);
 185        for (i = 0; i < size; i++)
 186                log_debug("%02x ", ((u8 *)command)[i]);
 187        log_debug("\n");
 188
 189        err = tpm_xfer(dev, command, size, response, &response_length);
 190
 191        if (err < 0)
 192                return err;
 193
 194        if (size_ptr)
 195                *size_ptr = response_length;
 196
 197        ret = tpm_return_code(response);
 198
 199        log_debug("TPM response [ret:%d]: ", ret);
 200        for (i = 0; i < response_length; i++)
 201                log_debug("%02x ", ((u8 *)response)[i]);
 202        log_debug("\n");
 203
 204        return ret;
 205}
 206
 207int tpm_init(struct udevice *dev)
 208{
 209        return tpm_open(dev);
 210}
 211