[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 18:17:30 CET 2018
On 02/27/2018 12:14 PM, Stephen Douthit wrote:
> On 02/26/2018 07:45 PM, Stefan Berger wrote:
>> 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
>>
>>
>>
>
> My interface ID reads as 0xffffffff, and the interface capability
> register reads as intf_cap 0x30000697. So your suggestion of
> checking for 3 in that bitfield of the interface capability register
> works here.
>
> If I change the version check function to the following and drop all
> the other changes from patch 3/3 would that be acceptable?
>
> static TPMVersion tis_get_tpm_version(void)
> {
> u32 reg = readl(TIS_REG(0, TIS_REG_IFACE_ID));
>
> /* FIFO interface as defined in PTP for TPM 2.0 is active */
> if ((reg & 0xf) == 0) {
> return TPM_VERSION_2;
> }
> /*
> * FIFO interface as defined in TIS1.3 is active
> * Interface capabilities are defined in TIS_REG_INTF_CAPABILITY
> */
> else if ((reg & 0xf) == 0xf) {
> reg = readl(TIS_REG(0, TIS_REG_INTF_CAPABILITY));
> /* Interface 1.3 for TPM 2.0 */
> if (((reg >> 28) & 0x7) == 3)
> return TPM_VERSION_2;
I think this is actually the better test and you should put this one up
front.
Stefan
> }
>
> return TPM_VERSION_1_2;
> }
>
More information about the SeaBIOS
mailing list