[SLOF] [PATCH 02/16] Add TPM initialization support

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


On 11/09/2015 03:29 AM, Nikunj A Dadhania wrote:
> Stefan Berger <stefanb at linux.vnet.ibm.com> writes:
>
>> +
>> +: vtpm-init ( -- true | false )
>> +    0 0 get-node open-node ?dup 0= IF EXIT THEN
>> +    my-self >r
>> +    dup to my-self
>> +
>> +    vtpm-debug? IF ." VTPM: Initializing for c-driver" cr THEN
>> +
>> +    my-unit to vtpm-unit
>> +
>> +    \ Enable TCE bypass special qemu feature
>> +    vtpm-unit 1 rtas-set-tce-bypass
>> +
>> +    \ Have TCE bypass cleaned up
>> +    ['] vtpm-cleanup add-quiesce-xt
>> +
>> +    tpm-start                              ( -- errcode )
>> +    vtpm-debug? IF
>> +        ." VTPM: Error code from tpm-start: " dup . cr
>> +    THEN
>> +
>> +    \ check errorcode
>> +    0= IF
>> +        \ tpm-start had no error: Setup an alias
>> +        setup-alias
>> +    THEN
> Why dont you print an error when the TPM start fails ? Something like
> below ?
>
>
>      tpm-start dup 0= IF
>          vtpm-debug? IF ." VTPM: Success code: " dup . cr THEN
>          setup-alias drop
>      ELSE
>           ." VTPM: Init Error, code: " . cr THEN
>      THEN

Will do.


>
>> +
>> +    close-node
>> +    r> to my-self
>> +;
>> +
>> +: open ( )
>> +    vtpm-debug? IF ." VTPM: vTPM open()" cr THEN
>> +    true
>> +;
>> +
>> +: close ( )
>> +    vtpm-debug? IF ." VTPM: vTPM close()" cr THEN
>> +;
>> +
>> +\ setup alias and the RTAS bypass
>> +vtpm-init
>> +
>> +\ setup the log
>> +include vtpm-sml.fs
>> diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
>> new file mode 100644
>> index 0000000..72edac0
>> --- /dev/null
>> +++ b/board-qemu/slof/vtpm-sml.fs
>> @@ -0,0 +1,56 @@
>> +\ *****************************************************************************
>> +\ * 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
>> +\ ****************************************************************************/
>> +
>> +\ KVM/qemu TPM SML entries in /ibm,vtpm
> Why is it there in root, is this documented in PAPR?

It's documented in that PFW Virtual TPM Driver spec... So I guess we can 
leave it there?

>
> We generally push such changes in /openprom.
>
> Thomas do you have some suggestions here?
>
>> +
>> +" /" find-device
>> +
>> +new-device
>> +
>> +false VALUE    vtpm-debug?
>> +0     VALUE    log-base
>> +40000 CONSTANT LOG-SIZE   \ 256k per VTPM FW spec.
>> +
>> +LOG-SIZE alloc-mem to log-base
>> +
>> +\ create /ibm,vtpm
>> +s" ibm,vtpm" 2dup device-name device-type
>> +
>> +: sml-get-allocated-size ( -- buffer-size)
>> +    vtpm-debug? IF
>> +        ." Call to sml-get-allocated-size; size = " LOG-SIZE . cr
>> +    THEN
>> +    LOG-SIZE
>> +;
>> +
>> +: sml-get-handover-size ( -- size )
>> +    vtpm-debug? IF
>> +        ." Call to sml-get-handover-size; size = " LOG-SIZE . cr
>> +    THEN
>> +    LOG-SIZE
>> +;
> What is the difference between the above two ?
>
> : sml-get-handover-size sml-get-allocated-size ;


The former returns the number of bytes that were actually written into 
the log, the latter returns the actual size of the log.
The latter will be used by forthcoming versions of Linux due to a 
off-by-one problem related to the former.

>
>> +
>> +: sml-handover ( dest size -- )
>> +    vtpm-debug? IF
>> +        2dup
>> +        ." Call to sml-handover; size = " . ." dest = " . cr
>> +    THEN
>> +    log-base        ( dest size src )
>> +    -rot            ( src dest size )
>> +    move
>> +;
>> +
>> +: open  true ;
>> +: close ;
>> +
>> +finish-device
>> +device-end
>> diff --git a/lib/Makefile b/lib/Makefile
>> index ed8a359..9c802e2 100644
>> --- a/lib/Makefile
>> +++ b/lib/Makefile
>> @@ -11,7 +11,7 @@
>>   # ****************************************************************************/
>>
>>   SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \
>> -          libusb libveth libe1k libbcm
>> +          libusb libveth libe1k libbcm libtpm
>>
>>   all:  subdirs
>>
>> diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile
>> index a174815..53d3abb 100644
>> --- a/lib/libtpm/Makefile
>> +++ b/lib/libtpm/Makefile
>> @@ -24,7 +24,7 @@ TARGET = ../libtpm.a
>>
>>   all: $(TARGET)
>>
>> -SRCS = tpm_drivers.c
>> +SRCS = tpm_drivers.c tcgbios.c
>>
>>   OBJS = $(SRCS:%.c=%.o)
>>
>> diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c
>> new file mode 100644
>> index 0000000..efa4cdf
>> --- /dev/null
>> +++ b/lib/libtpm/tcgbios.c
>> @@ -0,0 +1,371 @@
>> +/*****************************************************************************
>> + * 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
>> + *****************************************************************************/
>> +
>> +/*
>> + *  Implementation of the TPM BIOS extension according to the specification
>> + *  described in the IBM VTPM Firmware document and the TCG Specification
>> + *  that can be found here under the following link:
>> + *  http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
>> + */
>> +
>> +#include "types.h"
>> +#include "byteorder.h"
>> +#include "tpm_drivers.h"
>> +#include "string.h"
>> +#include "tcgbios.h"
>> +#include "tcgbios_int.h"
>> +#include "stdio.h"
>> +
>> +#define DEBUG 0
>> +#define dprintf(_x ...) do { \
>> +	if (DEBUG) { \
>> +		printf("TCGBIOS: " _x); \
>> +	} \
>> +} while (0);
> This will be do { if (0)  { printf (); } } while(0);
>
> which i assume compiler can optimize, but as suggested in earlier patch
> can we make it more explicit ?
>
> Variable names look foreign in the SLOF code !
>
>> +
>> +static const uint8_t Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
>> +static const uint8_t Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
>> +
>> +static const uint8_t PhysicalPresence_CMD_ENABLE[]  = { 0x00, 0x20 };
>> +static const uint8_t PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
>> +static const uint8_t PhysicalPresence_PRESENT[]     = { 0x00, 0x08 };
>> +static const uint8_t PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
>> +
>> +static const uint8_t CommandFlag_FALSE[] = { 0x00 };
>> +static const uint8_t CommandFlag_TRUE[]  = { 0x01 };
>> +
>> +static const uint8_t GetCapability_Permanent_Flags[] = {
>> +	0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
>> +	0x00, 0x00, 0x01, 0x08
>> +};
>> +
>> +static const uint8_t GetCapability_OwnerAuth[] = {
>> +	0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
>> +	0x00, 0x00, 0x01, 0x11
>> +};
>> +
>> +static const uint8_t GetCapability_Timeouts[] = {
>> +	0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
>> +	0x00, 0x00, 0x01, 0x15
>> +};
>> +
>> +static const uint8_t GetCapability_Durations[] = {
>> +	0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
>> +	0x00, 0x00, 0x01, 0x20
>> +};
>
>> +
>> +struct tpm_state {
>> +	uint8_t	  tpm_probed:1;
>> +	uint8_t   tpm_found:1;
>> +	uint8_t   tpm_working:1;
>> +	uint8_t   if_shutdown:1;
>> +	struct tpm_driver *tpm_driver_to_use;
> 	struct tpm_driver *tpm_drv;
>
>> +};
>> +
>> +static struct tpm_state tpm_state = {
>> +	.tpm_driver_to_use = NULL,
>> +};
>> +
>> +extern struct tpm_driver tpm_drivers[];
>> +
>> +/********************************************************
>> +  Extensions for TCG-enabled BIOS
>> + *******************************************************/
>> +
>> +static bool is_tpm_present(void)
>> +{
>> +	bool rc = false;
>> +	unsigned int i;
>> +
>> +	for (i = 0; i < TPM_NUM_DRIVERS; i++) {
>> +		struct tpm_driver *td = &tpm_drivers[i];
>> +		if (td->probe()) {
>> +			td->init();
>> +			tpm_state.tpm_driver_to_use = td;
>> +			rc = true;
>> +			break;
>> +		}
>> +	}
>> +
>> +	return rc;
>> +}
>> +
>> +static void probe_tpm(void)
>> +{
>> +	if (!tpm_state.tpm_probed) {
>> +		tpm_state.tpm_probed = 1;
>> +		tpm_state.tpm_found = (is_tpm_present() != 0);
> 		tpm_state.tpm_found = is_tpm_present();
>
>> +		tpm_state.tpm_working = tpm_state.tpm_found;
>> +	}
>> +}
>> +
>> +static bool has_working_tpm(void)
>> +{
>> +	probe_tpm();
> 	if (!tpm_state.tpm_probed) {
>             probe_tpm(); /* get rid of condition in probe_tpm() */
>          }
>
>> +
>> +	return tpm_state.tpm_working;
>> +}
>> +
>> +static uint32_t transmit(uint8_t locty, const struct iovec iovec[],
>> +			 uint8_t *respbuffer, uint32_t *respbufferlen,
>> +			 enum tpmDurationType to_t)
>> +{
>> +	struct tpm_driver *td;
>> +	unsigned int i;
>> +
>> +	if (tpm_state.tpm_driver_to_use == NULL)
>> +		return TCGBIOS_FATAL_COM_ERROR;
>> +
>> +	td = tpm_state.tpm_driver_to_use;
> can be replaced by:
>
> 	struct tpm_driver *td = tpm_state.tpm_driver_to_use;
> 	unsigned int i;
>
>          if (!td)
>                 return TCGBIOS_FATAL_COM_ERROR;
>
>> +
>> +	if (!td->activate(locty))
>> +		return TCGBIOS_FATAL_COM_ERROR;
>> +
>> +	for (i = 0; iovec[i].length; i++) {
>> +		if (!td->senddata(iovec[i].data,
>> +				  iovec[i].length))
>> +			return TCGBIOS_FATAL_COM_ERROR;
>> +	}
>> +
>> +	if (!td->transfer())
>> +		return TCGBIOS_FATAL_COM_ERROR;
>> +
>> +	if (!td->waitrespready(to_t))
>> +		return TCGBIOS_FATAL_COM_ERROR;
>> +
>> +	if (!td->readresp(respbuffer, respbufferlen))
>> +		return TCGBIOS_FATAL_COM_ERROR;
>> +
>> +	td->ready();
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Send a TPM command with the given ordinal. Append the given buffer
>> + * containing all data in network byte order to the command (this is
>> + * the custom part per command) and expect a response of the given size.
>> + * If a buffer is provided, the response will be copied into it.
>> + */
>> +static uint32_t build_and_send_cmd_od(uint32_t ordinal,
>> +				      const uint8_t *append,
>> +				      uint32_t append_size,
>> +				      uint8_t *resbuffer,
>> +				      uint32_t return_size,
>> +				      uint32_t *returnCode,
>> +				      const uint8_t *otherdata,
>> +				      uint32_t otherdata_size,
>> +				      enum tpmDurationType to_t)
>> +{
>> +#define MAX_APPEND_SIZE   sizeof(GetCapability_Timeouts)
>> +#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
> move these to the headers please where you have GetCapability_Timeouts
> and name it appropriately. I do not get how is GetCapability_Timeouts
> linked to APPEND_SIZE.

I would like to keep these around here since that's the only place where 
they are used.
The above shown structures relate to the biggest request and response 
packets
exchanged with the TPM.

+
+err_exit:
+	dprintf("TPM malfunctioning (line %d).\n", __LINE__);
+
+	tpm_state.tpm_working = 0;
+	if (rc)
+		return rc;
+	return TCGBIOS_COMMAND_ERROR;
+}
+
+uint32_t tpm_start(void)
+{
+	tpm_state.if_shutdown = 0;
+	tpm_state.tpm_probed = 0;
+	tpm_state.tpm_found = 0;
+	tpm_state.tpm_working = 0;
+
+	if (!has_working_tpm()) {
+		dprintf("%s: Machine does not have a working TPM\n",
+			__func__);
+		tpm_state.if_shutdown = 1;
+		return TCGBIOS_FATAL_COM_ERROR;
+	}
+
+	return tpm_startup();
+}
+
+uint32_t tpm_unassert_pp(void)

> What does unassert_pp mean ?

Will rename to unassert_physical_presence.

+
+: vtpm-unassert-pp
+    vtpm-available? IF
+        tpm-unassert-pp                              ( -- errcode )

> ignoring the error code here ? why?

The question is how to react ...


    Stefan



More information about the SLOF mailing list