[SeaBIOS] [PATCH 3/3] tpm: Support 2.0 TPM devices connected to a TIS host

Stefan Berger stefanb at linux.vnet.ibm.com
Tue Feb 27 01:45:02 CET 2018


On 02/26/2018 06:24 PM, Stephen Douthit wrote:
> On 02/26/2018 06:02 PM, Stefan Berger wrote:
>> On 02/26/2018 05:44 PM, Stephen Douthit wrote:
>>> On 02/26/2018 05:09 PM, Stefan Berger wrote:
>>>> On 02/26/2018 03:37 PM, Stephen Douthit wrote:
>>>>> tis_get_tpm_version() was returning the interface version, which 
>>>>> is always
>>>>> 1.2 since tis_probe() would have failed if the interface wasn't TIS.
>>>>>
>>>>> New version check is based on the tpm2_probe() function from the 
>>>>> Linux
>>>>> tpm_tis driver.
>>>>>
>>>>> Signed-off-by: Stephen Douthit <stephend at silicom-usa.com>
>>>>> Tested-by: Stephen Douthit <stephend at silicom-usa.com>
>>>>> ---
>>>>>   src/hw/tpm_drivers.c | 21 +++++++++++++++------
>>>>>   src/std/tcg.h        |  1 +
>>>>>   src/tcgbios.c        |  2 +-
>>>>>   src/tcgbios.h        |  4 ++++
>>>>>   4 files changed, 21 insertions(+), 7 deletions(-)
>>>>>
>>>>> diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c
>>>>> index 789d70a..32c34df 100644
>>>>> --- a/src/hw/tpm_drivers.c
>>>>> +++ b/src/hw/tpm_drivers.c
>>>>> @@ -11,6 +11,7 @@
>>>>>   #include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD
>>>>>   #include "hw/tpm_drivers.h" // struct tpm_driver
>>>>>   #include "std/tcg.h" // TCG_RESPONSE_TIMEOUT
>>>>> +#include "tcgbios.h" // tpm20_getcapability
>>>>>   #include "output.h" // warn_timeout
>>>>>   #include "stacks.h" // yield
>>>>>   #include "string.h" // memcpy
>>>>> @@ -119,7 +120,7 @@ static u32 tis_probe(void)
>>>>>       if ((didvid != 0) && (didvid != 0xffffffff))
>>>>>           rc = 1;
>>>>>
>>>>> -    /* TPM 2 has an interface register */
>>>>> +    /* Low 32 bits of CRB interface register overlap TIS 
>>>>> interface register */
>>>>>       u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID));
>>>>
>>>> Since this is tis_probe, I don't think we need to mention the CRB 
>>>> here ...
>>>
>>> I think that was a note to myself I forgot to strip out when I
>>> dropped my debug prints.  I'll change the comment back.
>>>
>>>>>
>>>>>       if ((ifaceid & 0xf) != 0xf) {
>>>>> @@ -142,13 +143,21 @@ static u32 tis_probe(void)
>>>>>
>>>>>   static TPMVersion tis_get_tpm_version(void)
>>>>>   {
>>>>> -    /* TPM 2 has an interface register */
>>>>> -    u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID));
>>>>> +    u8 buffer[128];
>>>>> +    int ret;
>>>>> +    struct tpm2_res_getcapability *trg =
>>>>> +      (struct tpm2_res_getcapability *)&buffer;
>>>>> +
>>>>> +    ret = tpm20_getcapability(TPM2_CAP_TPM_PROPERTIES, 
>>>>> cpu_to_be32(0x100),
>>>>> +                              cpu_to_be32(1), &trg->hdr, 
>>>>> sizeof(buffer));
>>>>> +    if (ret == TPM2_RC_INITIALIZE)
>>>>> +        return TPM_VERSION_2;
>>>>> +    else if (ret)
>>>>> +        return TPM_VERSION_NONE;
>>>> I haven't tried yet, but likely this will not work for TPM 1.2 
>>>> since it will also return an error.
>>>
>>> Doh.  That makes sense.  I'll need to find a 1.2 system to test on to
>>> avoid stupid mistakes like that.
>>>
>>>> Wouldn't the check for the tag below not be sufficient? We are 
>>>> doing something similar in QEMU when probing for the TPM. Here we 
>>>> send TPM 2 command TPM_CC_ReadClock and check the tag for TPM 2 
>>>> type and then TPM 1.2 command TPM_ORD_GetTicks and check for TPM 
>>>> 1.2 tag.
>>>
>>> It might be, it wasn't clear to me if the tag could be trusted if the
>>> return code wasn't success.  The Linux tpm2_probe() code bails before
>>> the tag comparison if tpm_transmit_cmd() returns an error.
>>>
>>> Is there a block of QEMU code you would recommend as a reference for
>>> probing TPMs?  I'm not very familiar with that code base, and a
>>> pointer would be handy.
>>
>> https://github.com/stefanberger/qemu-tpm/blob/v2.4.1%2Btpm/hw/tpm/tpm_util.c#L94 
>>
>>
>> What I don't like about the sending of commands is that we're 
>> breaking the layer here. We basically cannot send commands using this 
>> higher level API. The lowest we could go would be to call 
>> tpmhw_transmit, but that function cannot be used as it is but has to 
>> be split up to take tpm_driver as a parameter. You would pass to it 
>> &tpm_drivers[TIS_DRIVER_INDEX].
>>
>> As far as I know, TPM 1.2 didn't have that register, so they either 
>> return static 0 or 0xffffffff in that register.
>>
>> Though if reading the flags from the interface register really turns 
>> out to be insufficient, I think you should try to send a command like 
>> TPM2_CC_ReadClock. If you get back a TPM2_ST_NO_SESSION, it's a TPM 
>> 2. If you get a TPM_TAG_RSP_COMMAND it's a TPM 12.
>
> Thanks for all the info.  This gives me some experiments to run, and
> I'll try to find a solution that avoids sending commands if possible.

The following document on pdf page 100 defines bits 28-30 of the 
interface capability register. If the value there is 0x3 (mask 0x7), we 
should be sure to have a TPM 2. Hopefully that's sufficient also for 
your device for determining that it's a TPM 2.

https://trustedcomputinggroup.org/wp-content/uploads/TCG_PC_Client_Platform_TPM_Profile_PTP_Specification_Family_2.0_Revision_1.3v22.pdf





More information about the SeaBIOS mailing list