Skip to content
Snippets Groups Projects
tpm-common.c 3.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • // SPDX-License-Identifier: GPL-2.0+
    /*
     * Copyright (c) 2013 The Chromium OS Authors.
     * Coypright (c) 2013 Guntermann & Drunck GmbH
     */
    
    #include <common.h>
    #include <dm.h>
    #include <asm/unaligned.h>
    #include <tpm-common.h>
    #include "tpm-utils.h"
    
    int pack_byte_string(u8 *str, size_t size, const char *format, ...)
    {
    	va_list args;
    	size_t offset = 0, length = 0;
    	u8 *data = NULL;
    	u32 value = 0;
    
    	va_start(args, format);
    	for (; *format; format++) {
    		switch (*format) {
    		case 'b':
    			offset = va_arg(args, size_t);
    			value = va_arg(args, int);
    			length = 1;
    			break;
    		case 'w':
    			offset = va_arg(args, size_t);
    			value = va_arg(args, int);
    			length = 2;
    			break;
    		case 'd':
    			offset = va_arg(args, size_t);
    			value = va_arg(args, u32);
    			length = 4;
    			break;
    		case 's':
    			offset = va_arg(args, size_t);
    			data = va_arg(args, u8 *);
    			length = va_arg(args, u32);
    			break;
    		default:
    			debug("Couldn't recognize format string\n");
    			va_end(args);
    			return -1;
    		}
    
    		if (offset + length > size) {
    			va_end(args);
    			return -1;
    		}
    
    		switch (*format) {
    		case 'b':
    			str[offset] = value;
    			break;
    		case 'w':
    			put_unaligned_be16(value, str + offset);
    			break;
    		case 'd':
    			put_unaligned_be32(value, str + offset);
    			break;
    		case 's':
    			memcpy(str + offset, data, length);
    			break;
    		}
    	}
    	va_end(args);
    
    	return 0;
    }
    
    int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
    {
    	va_list args;
    	size_t offset = 0, length = 0;
    	u8 *ptr8 = NULL;
    	u16 *ptr16 = NULL;
    	u32 *ptr32 = NULL;
    
    	va_start(args, format);
    	for (; *format; format++) {
    		switch (*format) {
    		case 'b':
    			offset = va_arg(args, size_t);
    			ptr8 = va_arg(args, u8 *);
    			length = 1;
    			break;
    		case 'w':
    			offset = va_arg(args, size_t);
    			ptr16 = va_arg(args, u16 *);
    			length = 2;
    			break;
    		case 'd':
    			offset = va_arg(args, size_t);
    			ptr32 = va_arg(args, u32 *);
    			length = 4;
    			break;
    		case 's':
    			offset = va_arg(args, size_t);
    			ptr8 = va_arg(args, u8 *);
    			length = va_arg(args, u32);
    			break;
    		default:
    			va_end(args);
    			debug("Couldn't recognize format string\n");
    			return -1;
    		}
    
    		if (offset + length > size) {
    			va_end(args);
    			return -1;
    		}
    
    		switch (*format) {
    		case 'b':
    			*ptr8 = str[offset];
    			break;
    		case 'w':
    			*ptr16 = get_unaligned_be16(str + offset);
    			break;
    		case 'd':
    			*ptr32 = get_unaligned_be32(str + offset);
    			break;
    		case 's':
    			memcpy(ptr8, str + offset, length);
    			break;
    		}
    	}
    	va_end(args);
    
    	return 0;
    }
    
    u32 tpm_command_size(const void *command)
    {
    	const size_t command_size_offset = 2;
    
    	return get_unaligned_be32(command + command_size_offset);
    }
    
    u32 tpm_return_code(const void *response)
    {
    	const size_t return_code_offset = 6;
    
    	return get_unaligned_be32(response + return_code_offset);
    }
    
    u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr)
    {
    	struct udevice *dev;
    	int err, ret;
    	u8 response_buffer[COMMAND_BUFFER_SIZE];
    	size_t response_length;
    
    
    	if (response) {
    		response_length = *size_ptr;
    	} else {
    		response = response_buffer;
    		response_length = sizeof(response_buffer);
    	}
    
    	ret = uclass_first_device_err(UCLASS_TPM, &dev);
    	if (ret)
    		return ret;
    	err = tpm_xfer(dev, command, tpm_command_size(command),
    		       response, &response_length);
    
    	if (err < 0)
    		return TPM_LIB_ERROR;
    	if (size_ptr)
    		*size_ptr = response_length;
    
    
    	ret = tpm_return_code(response);
    
    	log(LOGC_NONE, LOGL_DEBUG, "TPM response [ret:%d]: ", ret);
    	for (i = 0; i < response_length; i++)
    		log(LOGC_NONE, LOGL_DEBUG, "%02x ", ((u8 *)response)[i]);
    	log(LOGC_NONE, LOGL_DEBUG, "\n");
    
    	return ret;
    
    }
    
    int tpm_init(void)
    {
    	struct udevice *dev;
    	int err;
    
    	err = uclass_first_device_err(UCLASS_TPM, &dev);
    	if (err)
    		return err;
    
    	return tpm_open(dev);
    }