[SLOF] [PATCH 01/16] Add a TPM driver implementation

Nikunj A Dadhania nikunj at linux.vnet.ibm.com
Mon Nov 9 17:11:44 AEDT 2015


Stefan Berger <stefanb at linux.vnet.ibm.com> writes:

> This patch adds a TPM driver for the CRQ interface as used by
> the QEMU PAPR implementation.
>
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> ---
>  include/helpers.h        |   1 +
>  lib/libtpm/Makefile      |  51 ++++++
>  lib/libtpm/tpm_drivers.c | 456 +++++++++++++++++++++++++++++++++++++++++++++++
>  lib/libtpm/tpm_drivers.h |  93 ++++++++++
>  slof/helpers.c           |   6 +
>  5 files changed, 607 insertions(+)
>  create mode 100644 lib/libtpm/Makefile
>  create mode 100644 lib/libtpm/tpm_drivers.c
>  create mode 100644 lib/libtpm/tpm_drivers.h
>
> diff --git a/include/helpers.h b/include/helpers.h
> index fb10534..9e6bdf8 100644
> --- a/include/helpers.h
> +++ b/include/helpers.h
> @@ -33,6 +33,7 @@ extern long SLOF_pci_config_read16(long offset);
>  extern void SLOF_pci_config_write32(long offset, long value);
>  extern void SLOF_pci_config_write16(long offset, long value);
>  extern void *SLOF_translate_my_address(void *addr);
> +extern unsigned long SLOF_get_vtpm_unit(void);
>
>  #define offset_of(type, member) ((long) &((type *)0)->member)
>  #define container_of(ptr, type, member) ({                      \
> diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile
> new file mode 100644
> index 0000000..a174815
> --- /dev/null
> +++ b/lib/libtpm/Makefile
> @@ -0,0 +1,51 @@
> +# *****************************************************************************
> +# * Copyright (c) 2015 IBM Corporation
> +# * All rights reserved.
> +# * This program and the accompanying materials
> +# * are made available under the terms of the BSD License
> +# * which accompanies this distribution, and is available at
> +# * http://www.opensource.org/licenses/bsd-license.php
> +# *
> +# * Contributors:
> +# *     IBM Corporation - initial implementation
> +# ****************************************************************************/
> +
> +TOPCMNDIR ?= ../..
> +
> +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
> +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
> +	   -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR)
> +CPPFLAGS += -I../libhvcall
> +
> +LDFLAGS = -nostdlib
> +
> +TARGET = ../libtpm.a
> +
> +
> +all: $(TARGET)
> +
> +SRCS = tpm_drivers.c
> +
> +OBJS = $(SRCS:%.c=%.o)
> +
> +$(TARGET): $(OBJS)
> +	$(AR) -rc $@ $(OBJS)
> +	$(RANLIB) $@
> +
> +clean:
> +	$(RM) $(TARGET) $(OBJS)
> +
> +distclean: clean
> +	$(RM) Makefile.dep
> +
> +
> +# Rules for creating the dependency file:
> +depend:
> +	$(RM) Makefile.dep
> +	$(MAKE) Makefile.dep
> +
> +Makefile.dep: Makefile
> +	$(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
> +
> +# Include dependency file if available:
> +-include Makefile.dep
> diff --git a/lib/libtpm/tpm_drivers.c b/lib/libtpm/tpm_drivers.c
> new file mode 100644
> index 0000000..850da8c
> --- /dev/null
> +++ b/lib/libtpm/tpm_drivers.c
> @@ -0,0 +1,456 @@
> +/*****************************************************************************
> + * Copyright (c) 2015 IBM Corporation
> + * All rights reserved.
> + * This program and the accompanying materials
> + * are made available under the terms of the BSD License
> + * which accompanies this distribution, and is available at
> + * http://www.opensource.org/licenses/bsd-license.php
> + *
> + * Contributors:
> + *     IBM Corporation - initial implementation
> + *****************************************************************************/
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <stdbool.h>
> +
> +#include "string.h"
> +#include "helpers.h"
> +#include "byteorder.h"
> +#include "tpm_drivers.h"
> +#include "tcgbios.h"
> +#include "libhvcall.h"
> +#include "paflof.h"
> +
> +#define PAPR_VTPM_DEBUG   0
> +
> +#define dprintf(_x ...) \
> +	if (PAPR_VTPM_DEBUG) { \
> +		printf("VTPM CRQ: " _x); \
> +	}

Better one:

#ifdef PAPR_VTPM_DEBUG
#define dprintf(_x ...) do { printf(_x); } while(0)
#else
#define dprintf(_x ...)
#endif

> +
> +#define MIN(a, b) ((a) > (b) ? (b) : (a))
> +
> +#define TPM_DEFAULT_DURATION_SHORT     (2000)
> +#define TPM_DEFAULT_DURATION_MEDIUM    (20000)
> +#define TPM_DEFAULT_DURATION_LONG      (60000)

any reason you cant move this to tpm_drivers.h

> +
> +struct crq {
> +	uint8_t valid;
> +	uint8_t msg;
> +	uint16_t len;
> +	uint32_t data;
> +	uint64_t reserved;
> +} __attribute__((packed));
> +
> +#define PAPR_VTPM_INIT_CRQ_COMMAND      0xC0
> +#define PAPR_VTPM_VALID_COMMAND         0x80
> +#define PAPR_VTPM_MSG_RESULT            0x80
> +
> +/* msg types for valid = VALID_INIT_CRQ */

Comment is confusing, are these return codes for
PAPR_VTPM_INIT_CRQ_COMMAND ?

> +#define PAPR_VTPM_INIT_CRQ_RESULT       0x1
> +
> +/* msg types for valid = IBMVTPM_VALID_CMD */

same comment as above

> +#define PAPR_VTPM_GET_VERSION           0x1
> +#define PAPR_VTPM_TPM_COMMAND           0x2
> +#define PAPR_VTPM_GET_RTCE_BUFFER_SIZE  0x3
> +
> +static const uint32_t tpm_default_durations[TPM_NUM_DURATIONS] = {
> +	TPM_DEFAULT_DURATION_SHORT,
> +	TPM_DEFAULT_DURATION_MEDIUM,
> +	TPM_DEFAULT_DURATION_LONG,
> +};

Better to move it to where you have defined these.

> +
> +#define PAGE_SIZE 4096
> +
> +/* state of the PAPR CRQ VTPM driver */
> +static struct spapr_vtpm_driver_state {
> +        /* durations of short, medium, & long commands */
> +	uint32_t durations[TPM_NUM_DURATIONS];
> +	unsigned long vtpm_unit;

	unsigned long unit;
Should do, as its part of vtpm struct

spapr_vtpm->vtpm_unit  can be written as:

spapr_vtpm->unit


> +	unsigned char *qaddr;
> +	unsigned long qsize;
> +	/* current q_entry */
> +	unsigned int q_entry;
> +	/* current response CRQ */
> +	struct crq *response;
> +	pfw_drv_state driver_state;
> +	pfw_drv_error driver_error;

what is pfw here ?

> +	/* version of the TPM we talk to -- from CRQ message */
> +	uint32_t tpm_version;
> +	/* buffer offset in buffer for sending */
> +	unsigned int buffer_offset;
> +	/* actual size of the buffer being used */
> +	unsigned int buffer_size;
> +	/* the buffer; may be bigger than buffer_size */
> +	unsigned char buffer[PAPR_VTPM_MAX_BUFFER_SIZE];
> +}

Make the variable name self explanatory, for eg:

> +	/* current q_entry */
> +	unsigned int q_entry;

as

unsigned int curr_q_entry;
       OR
unsigned int q_pos;

So someone need not have to come to structure definition to figure out
that this is a current entry. The variable name itself will tell that.

Other Cosmetic:

struct foo {
     /* comment for block one */
     int var1;

     /* comment 2 */
     int var2;
     int var3;

     /* comment 3 */
     int var_foo;
}

will be more readable.

> + spapr_vtpm = {
> +	.qsize = PAGE_SIZE,
> +	.driver_state = PFW_DRV_STATE_INVALID,
> +	.driver_error = PFW_DRV_ERROR_NO_FAILURE,
> +	.buffer_size = sizeof(spapr_vtpm.buffer),
> +};

With spapr_vtpm global you are assuming that you will only have one vtpm
device added to the guest. Are you preventing adding more than one
device in QEMU? Can you have more than one vtpm device attached to a VM ?


Why PFW ? Please get rid of this suffix.

> +
> +static void pfw_drv_state_set(pfw_drv_state s, pfw_drv_error e)
> +{
> +	spapr_vtpm.driver_state = s;
> +	spapr_vtpm.driver_error = e;
> +}
> +
> +static pfw_drv_state pfw_drv_state_get(void)
> +{
> +	return spapr_vtpm.driver_state;
> +}
> +
> +static pfw_drv_state pfw_drv_error_get(void)
> +{
> +	return spapr_vtpm.driver_error;
> +}
> +
> +static void spapr_vtpm_set_durations(
> +                              const uint32_t durations[TPM_NUM_DURATIONS])
> +{
> +        memcpy(spapr_vtpm.durations, durations,
> +               TPM_NUM_DURATIONS * sizeof(durations[0]));
> +}
> +
> +/*
> + * Get the crq where the response will be found. This
> + * function will clear the CRQ's valid field and advance
> + * the entry counter to the next entry.
> + */
> +static struct crq *get_response_crq(void)
> +{
> +	struct crq *crq;
> +
> +	dprintf("q_entry = %d\n", spapr_vtpm.q_entry);
> +
> +	crq = &((struct crq *)spapr_vtpm.qaddr)[spapr_vtpm.q_entry];

Add a one line helper for this, will be more cleaner:

static struct crq* get_crq(unsigned long qaddr, unsigned long q_entry)
{
       return &((struct crq *)qaddr)[q_entry];
}

> +	memset(crq, 0, sizeof(*crq));
> +
> +	spapr_vtpm.q_entry += 1;
> +	if (spapr_vtpm.q_entry == spapr_vtpm.qsize / sizeof(struct crq))

Prefer with braces or can you have this as a define VTPM_Q_ENTRY_NUMS:

if (spapr_vtpm.q_entry == (spapr_vtpm.qsize / sizeof(struct crq)))

> +		spapr_vtpm.q_entry = 0;
> +
> +	return crq;
> +}
> +
> +/*
> + * Send a message via CRQ and wait for the response
> + */
> +static bool spapr_send_crq_and_wait(unsigned long unit,
> +                                    struct crq *crq,
> +                                    struct crq **resp,
> +                                    unsigned timeout,
> +                                    pfw_drv_state state1,
> +                                    pfw_drv_state state2)
> +{
> +	long rc;
> +	unsigned i;
> +
> +	*resp = get_response_crq();
> +
> +	pfw_drv_state_set(state1, PFW_DRV_ERROR_NO_FAILURE);
> +
> +	rc = hv_send_crq(unit, (uint64_t *)crq);
> +	if (rc != H_SUCCESS) {
> +		pfw_drv_state_set(PFW_DRV_STATE_WAIT_INIT,
> +				  PFW_DRV_ERROR_TPM_CRQ_ERROR);
> +		return false;
> +	}
> +
> +	pfw_drv_state_set(state2,
> +	                  PFW_DRV_ERROR_NO_FAILURE);
> +
> +	for (i = 0; i < timeout; i++) {
> +		if (((*resp)->valid & PAPR_VTPM_MSG_RESULT))
> +			return true;
> +		SLOF_msleep(1);
> +	}
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_FAILURE,
> +			  PFW_DRV_ERROR_WAIT_TIMEOUT);
> +
> +	dprintf("Received no response from CRQ\n");
> +	return false;
> +}
> +
> +/*
> + * Get parameters from the CRQ
> + */
> +static bool spapr_vtpm_get_params(void)
> +{
> +	struct crq crq, *response;

for consistency "*resp" ?

> +	static bool completed = false; /* only once */
> +
> +	if (completed)
> +		return true;
> +
> +	/* get the TPM version */
> +	crq.valid = PAPR_VTPM_VALID_COMMAND;
> +	crq.msg = PAPR_VTPM_GET_VERSION;
> +
> +	if (!spapr_send_crq_and_wait(spapr_vtpm.vtpm_unit, &crq, &response, 10,
> +	                             PFW_DRV_STATE_SEND_GET_VERSION,
> +	                             PFW_DRV_STATE_WAIT_VERSION)) {
> +		dprintf("Failure getting TPM version from CRQ\n");
> +		return false;
> +	}
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_CHECK_VERSION,
> +	                  PFW_DRV_ERROR_NO_FAILURE);
> +
> +	spapr_vtpm.tpm_version = be32_to_cpu(response->data);
> +	dprintf("TPM backend version: %d\n", spapr_vtpm.tpm_version);
> +
> +	/* get the TPM's buffer size */
> +	crq.valid = PAPR_VTPM_VALID_COMMAND;
> +	crq.msg = PAPR_VTPM_GET_RTCE_BUFFER_SIZE;
> +
> +	if (!spapr_send_crq_and_wait(spapr_vtpm.vtpm_unit, &crq, &response, 10,
> +	                             PFW_DRV_STATE_SEND_BUFSIZE_REQ,
> +	                             PFW_DRV_STATE_WAIT_BUFSIZE)) {
> +		dprintf("Failure getting RTCE buffer size from CRQ\n");
> +		return false;
> +	}
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_ALLOC_RTCE_BUF,
> +	                  PFW_DRV_ERROR_NO_FAILURE);
> +
> +	dprintf("RTCE buffer size: %u\n", be16_to_cpu(response->len));
> +	spapr_vtpm.buffer_size = MIN(spapr_vtpm.buffer_size,
> +				     be16_to_cpu(response->len));
> +	if (spapr_vtpm.buffer_size < 1024) {
> +		dprintf("RTCE buffer size of %u bytes is too small. "
> +		        "Minimum is 1024 bytes.\n", spapr_vtpm.buffer_size);
> +		pfw_drv_state_set(PFW_DRV_STATE_FAILURE,
> +				  PFW_DRV_ERROR_BAD_RTCE_SIZE);
> +		return false;
> +	}
> +
> +	completed = true;
> +
> +	return true;
> +}
> +
> +static bool spapr_vtpm_activate(uint8_t locty)
> +{
> +	long rc;
> +	struct crq crq, *resp;
> +	static bool initialized = false; /* only one init */

I would better limit number of devices in QEMU rather than limiting the
driver.

> +
> +	spapr_vtpm.buffer_offset = 0;
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_REG_CRQ,
> +			  PFW_DRV_ERROR_NO_FAILURE);
> +
> +	rc = hv_reg_crq(spapr_vtpm.vtpm_unit, (unsigned long)spapr_vtpm.qaddr,
> +	                spapr_vtpm.qsize);
> +	if (rc != H_SUCCESS) {
> +		pfw_drv_state_set(PFW_DRV_STATE_WAIT_INIT,
> +		                  PFW_DRV_ERROR_UNEXPECTED_REG_ERROR);
> +		dprintf("CRQ registration failed\n");
> +		return false;
> +	}
> +
> +	/* we always start with q_entry 0 */
> +	spapr_vtpm.q_entry = 0;
> +
> +	if (initialized)
> +		goto skip_init;
> +
> +	crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND;
> +	crq.msg = PAPR_VTPM_INIT_CRQ_RESULT;
> +
> +	if (!spapr_send_crq_and_wait(spapr_vtpm.vtpm_unit,
> +	                             &crq,
> +	                             &resp,
> +	                             10,
> +	                             PFW_DRV_STATE_SEND_INIT,
> +	                             PFW_DRV_STATE_WAIT_INIT_COMP)) {
> +		dprintf("Initializing CRQ failed\n");
> +		goto err_exit;
> +	}
> +	dprintf("Successfully initialized CRQ\n");
> +
> +	initialized = true;
> +
> +skip_init:
> +	if (!spapr_vtpm_get_params())
> +		goto err_exit;
> +
> +	return true;
> +
> +err_exit:
> +	hv_free_crq(spapr_vtpm.vtpm_unit);

and do we need to set "initialized = false"  here?

> +
> +	return false;
> +}
> +
> +static bool spapr_vtpm_init(void)
> +{
> +        spapr_vtpm_set_durations(tpm_default_durations);
> +
> +	return true;
> +}
> +
> +/*
> + * Check whether we have a CRQ underneath us
> + */
> +static bool spapr_vtpm_probe(void)
> +{
> +	bool good = true;
> +
> +	spapr_vtpm_init();
> +
> +	if (!spapr_vtpm.qaddr) {
> +		spapr_vtpm.qaddr = SLOF_alloc_mem(spapr_vtpm.qsize);

what if  .qaddr is NULL ?

> +		memset(spapr_vtpm.qaddr, 0, spapr_vtpm.qsize);
> +
> +		dprintf("getting FORTH vtpm-unit\n");
> +		spapr_vtpm.vtpm_unit = SLOF_get_vtpm_unit();
> +	}
> +
> +	dprintf("vtpm_unit = %lx, buffer = %p\n",
> +	        spapr_vtpm.vtpm_unit, spapr_vtpm.qaddr);
> +	if (!spapr_vtpm_activate(0)) {
> +		good = false;
                return false;
> +	} else {
> +		hv_free_crq(spapr_vtpm.vtpm_unit);
> +	}
> +
> +	return good;

	if (!spapr_vtpm_activate(0))
                return false;

        hv_free_crq(spapr_vtpm.vtpm_unit);
        return true;

dont seem to need a "good" variable, and simple code.

> +}
> +
> +static bool spapr_vtpm_senddata(const uint8_t *const data, uint32_t len)
> +{
> +	/*
> +	 * we have to collect all data to be sent in a buffer
> +	 */
> +
> +	if (spapr_vtpm.buffer_offset + len > spapr_vtpm.buffer_size) {

what if the len > buffer_size ?

> +		spapr_vtpm.buffer_offset = 0;
> +		return false;
> +	}
> +
> +	memcpy(&spapr_vtpm.buffer[spapr_vtpm.buffer_offset], data, len);
> +
> +	spapr_vtpm.buffer_offset += len;
> +
> +	return true;
> +}
> +
> +static bool spapr_vtpm_transfer(void)
> +{
> +	struct crq crq;
> +	long rc;
> +
> +	spapr_vtpm.response = get_response_crq();

I see that "resp" and "response" is used interchangeably, for
consistency use one of them.

> +	/* response CRQ has been set and valid field cleared */
> +
> +	crq.valid = PAPR_VTPM_VALID_COMMAND;
> +	crq.msg = PAPR_VTPM_TPM_COMMAND;
> +	crq.len = cpu_to_be16(spapr_vtpm.buffer_offset);
> +	crq.data = cpu_to_be32((uint64_t)spapr_vtpm.buffer);
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_SEND_TPM_CMD,
> +	                  PFW_DRV_ERROR_NO_FAILURE);
> +
> +	rc = hv_send_crq(spapr_vtpm.vtpm_unit, (uint64_t *)&crq);
> +
> +	if (rc == H_SUCCESS) {
> +		pfw_drv_state_set(PFW_DRV_STATE_WAIT_TPM_RSP,
> +		                  PFW_DRV_ERROR_NO_FAILURE);
> +	} else {
> +		/* per pfw doc, move to wait_init state */

Is this available externally? where ?

> +		pfw_drv_state_set(PFW_DRV_STATE_WAIT_INIT,
> +		                  PFW_DRV_ERROR_UNEXPECTED_SEND_ERROR);
> +	}
> +
> +	spapr_vtpm.buffer_offset = 0;
> +
> +	return (rc == H_SUCCESS);
> +}
> +
> +static bool spapr_vtpm_waitrespready(enum tpmDurationType to_t)

"tpmDurationType" we dont use such camel case in our code.

> +{
> +	uint32_t timeout = spapr_vtpm.durations[to_t];
> +	int i;
> +
> +	/* response CRQ has been set */
> +
> +	for (i = 0; i < timeout; i++) {
> +		if (spapr_vtpm.response->valid & PAPR_VTPM_MSG_RESULT) {
> +			/* TPM responded: move to Send tpm-cmd state */
> +			pfw_drv_state_set(PFW_DRV_STATE_SEND_TPM_CMD,
> +					  PFW_DRV_ERROR_NO_FAILURE);
> +			dprintf("Received response to TPM command\n");
> +			return true;
> +		}
> +		SLOF_msleep(1);
> +	}
> +
> +	pfw_drv_state_set(PFW_DRV_STATE_FAILURE,
> +			  PFW_DRV_ERROR_WAIT_TIMEOUT);
> +
> +	dprintf("Received NO response to TPM command");
> +
> +	return false;
> +}
> +
> +static bool spapr_vtpm_readresp(uint8_t *buffer, uint32_t *len)
> +{
> +	/* response CRQ has been set */
> +
> +	memcpy(buffer, (void *)(uint64_t)spapr_vtpm.response->data,
> +	       MIN(*len, be32_to_cpu(spapr_vtpm.response->len)));
> +
> +	*len = be32_to_cpu(spapr_vtpm.response->len);

*len = MIN(*len, be32_to_cpu(spapr_vtpm.response->len));

> +	dprintf("Length of copied response: %d\n", *len);
> +
> +	return true;
> +}
> +
> +static bool spapr_vtpm_endcycle(void)
> +{
> +	hv_free_crq(spapr_vtpm.vtpm_unit);
> +
> +	spapr_vtpm.response = NULL;
> +
> +	return true;
> +}
> +
> +static uint32_t spapr_vtpm_get_buffersize(void)
> +{
> +	return spapr_vtpm.buffer_size;
> +}
> +
> +static pfw_drv_state spapr_vtpm_get_state(void)
> +{
> +	return pfw_drv_state_get();
> +}
> +
> +static pfw_drv_error spapr_vtpm_get_error(void)
> +{
> +	return pfw_drv_error_get();
> +}
> +
> +/**** driver structures ****/
> +
> +struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
> +	[PAPR_DRIVER_IDX] = {
> +		.setdurations  = spapr_vtpm_set_durations,
> +		.probe         = spapr_vtpm_probe,
> +		.init          = spapr_vtpm_init,
> +		.activate      = spapr_vtpm_activate,
> +		.ready         = spapr_vtpm_endcycle,
> +		.senddata      = spapr_vtpm_senddata,
> +		.transfer      = spapr_vtpm_transfer,
> +		.waitrespready = spapr_vtpm_waitrespready,
> +		.readresp      = spapr_vtpm_readresp,
> +		.sha1threshold = 100 * 1024,
> +		.getbuffersize = spapr_vtpm_get_buffersize,
> +		.getstate      = spapr_vtpm_get_state,
> +		.geterror      = spapr_vtpm_get_error,
> +	},
> +};
> diff --git a/lib/libtpm/tpm_drivers.h b/lib/libtpm/tpm_drivers.h
> new file mode 100644
> index 0000000..2d74cc0
> --- /dev/null
> +++ b/lib/libtpm/tpm_drivers.h
> @@ -0,0 +1,93 @@
> +/*****************************************************************************
> + * Copyright (c) 2015 IBM Corporation
> + * All rights reserved.
> + * This program and the accompanying materials
> + * are made available under the terms of the BSD License
> + * which accompanies this distribution, and is available at
> + * http://www.opensource.org/licenses/bsd-license.php
> + *
> + * Contributors:
> + *     IBM Corporation - initial implementation
> + *****************************************************************************/
> +
> +#ifndef TPM_DRIVERS_H
> +#define TPM_DRIVERS_H
> +
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +enum tpmDurationType {
> +	TPM_DURATION_TYPE_SHORT = 0,
> +	TPM_DURATION_TYPE_MEDIUM,
> +	TPM_DURATION_TYPE_LONG,
> +};
> +
> +#define TPM_NUM_DURATIONS    3
> +
> +#define PAPR_DRIVER_IDX      0
> +#define TPM_NUM_DRIVERS      1
> +
> +/* firmware driver states */
> +typedef enum {
> +	PFW_DRV_STATE_INVALID = 0,
> +	PFW_DRV_STATE_INIT_CALLED = 1,
> +	PFW_DRV_STATE_REG_CRQ = 2,
> +	PFW_DRV_STATE_WAIT_INIT = 3,
> +	PFW_DRV_STATE_SEND_INIT = 4,
> +	PFW_DRV_STATE_FAILURE = 5,
> +	PFW_DRV_STATE_WAIT_INIT_COMP = 6,
> +	PFW_DRV_STATE_SEND_INIT_COMP = 7,
> +	PFW_DRV_STATE_SEND_GET_VERSION = 8,
> +	PFW_DRV_STATE_WAIT_VERSION = 9,
> +	PFW_DRV_STATE_CHECK_VERSION = 10,
> +	PFW_DRV_STATE_SEND_BUFSIZE_REQ = 11,
> +	PFW_DRV_STATE_WAIT_BUFSIZE = 12,
> +	PFW_DRV_STATE_ALLOC_RTCE_BUF = 13,
> +	PFW_DRV_STATE_SEND_TPM_CMD = 14,
> +	PFW_DRV_STATE_WAIT_TPM_RSP = 15,
> +} pfw_drv_state;

As mentioned earilier, you will need to get rid or the PFW_ suffix, with
may be VTPM_FOO_BAR

> +
> +/* firmware driver errors */
> +typedef enum {
> +	PFW_DRV_ERROR_NO_FAILURE = -1,
> +	PFW_DRV_ERROR_NOT_FOUND_TIMEOUT = 0,
> +	PFW_DRV_ERROR_UNEXPECTED_REG_ERROR = 1,
> +	PFW_DRV_ERROR_PARTNER_FAILED = 2,
> +	PFW_DRV_ERROR_UNEXPECTED_TSP_ERROR = 3,
> +	PFW_DRV_ERROR_TPM_PROTOCOL_ERROR = 4,
> +	PFW_DRV_ERROR_WAIT_TIMEOUT = 5,
> +	PFW_DRV_ERROR_UNEXPECTED_SEND_ERROR = 6,
> +	PFW_DRV_ERROR_CRQ_OPEN_FAIL = 7,
> +	PFW_DRV_ERROR_BAD_STATE = 8,
> +	PFW_DRV_ERROR_TPM_FAIL = 9,
> +	PFW_DRV_ERROR_TPM_CRQ_ERROR = 10,
> +	PFW_DRV_ERROR_BAD_VERSION = 11,
> +	PFW_DRV_ERROR_BAD_RTCE_SIZE = 12,
> +	PFW_DRV_ERROR_SML_FAILURE = 13,
> +	PFW_DRV_ERROR_SML_HANDED_OVER = 14,
> +} pfw_drv_error;
> +
> +/* low level driver implementation */
> +struct tpm_driver {
> +	void (*setdurations)(const uint32_t durations[TPM_NUM_DURATIONS]);
> +	bool (*probe)(void);
> +	bool (*init)(void);
> +	bool (*activate)(uint8_t locty);
> +	bool (*ready)(void);
> +	bool (*senddata)(const uint8_t *const data, uint32_t len);
> +	bool (*transfer)(void);
> +	bool (*waitrespready)(enum tpmDurationType to_t);
> +	bool (*readresp)(uint8_t *buffer, uint32_t *len);
> +	/* the TPM will be used for buffers of sizes below the sha1threshold
> +	   for calculating the hash */
> +	uint32_t sha1threshold;
> +	void (*get_vers_data)(uint16_t *did, uint16_t *vid, uint16_t *rid);
> +	uint32_t (*getbuffersize)(void);
> +	pfw_drv_state (*getstate)(void);
> +	pfw_drv_error (*geterror)(void);
> +};
> +
> +/* the max. buffer size by the external TPM is 4k */
> +#define PAPR_VTPM_MAX_BUFFER_SIZE       4096
> +
> +#endif /* TPM_DRIVERS_H */
> diff --git a/slof/helpers.c b/slof/helpers.c
> index d7c1888..dc7f08c 100644
> --- a/slof/helpers.c
> +++ b/slof/helpers.c
> @@ -134,3 +134,9 @@ void *SLOF_translate_my_address(void *addr)
>  	forth_eval("translate-my-address");
>  	return (void *)forth_pop();
>  }
> +
> +unsigned long SLOF_get_vtpm_unit(void)
> +{
> +	forth_eval("vtpm-unit");
> +	return forth_pop();
> +}
> -- 
> 1.9.3



More information about the SLOF mailing list