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

Stefan Berger stefanb at linux.vnet.ibm.com
Tue Nov 10 05:01:14 AEDT 2015


On 11/09/2015 01:11 AM, Nikunj A Dadhania wrote:
> Stefan Berger <stefanb at linux.vnet.ibm.com> writes:
>
>> +
>> +#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

I'll adapt it to that; since usb uses the same name dprintf, I'll keep 
it at that.

>
>> +
>> +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 ?

These are actually commands. I'll fix.

>> +	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 ?

These two variables are related to Power Firmware specs, so that's where 
the prefix 'pfw' comes from.


>
>> +	/* 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];
>> +}
>
>> + 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 ?

The Power Firmware spec states that only one device is supported 
(section on 'Additional driver requirements'); so QEMU doesn't not 
support more than one, either.

>
>
> Why PFW ? Please get rid of this suffix.

These would be the states and error codes defined by power firmware 
spec. Sure, will change it.

>
> +
> +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.

Ok, I'll move this one into the global structure.


>
>> +
>> +	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?

No, I do not think so.

>> +}
>> +
>> +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 ?

In this function we collect the data in a buffer. The check makes sure that
with the already accumulated data (buffer), the rest will fit into the 
buffer.
So the len > buffer_size is covered.

>
>> +		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 ?

It's not available externally. You should have received a copy, though.

I'll address all your other comments I deleted.

Thanks,
    Stefan



More information about the SLOF mailing list