qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC PATCH 3/3] acpi: Build TPM Physical Presence inter


From: Marc-André Lureau
Subject: Re: [Qemu-devel] [RFC PATCH 3/3] acpi: Build TPM Physical Presence interface
Date: Fri, 12 Jan 2018 17:07:10 +0100

Hi

On Wed, Jan 10, 2018 at 7:49 PM, Stefan Berger
<address@hidden> wrote:
> On 01/10/2018 01:35 PM, Stefan Berger wrote:
>>
>> The TPM Physical Presence interface consists of an ACPI part, a shared
>> memory part, and code in the firmware. Users can send messages to the
>> firmware by writing a code into the shared memory through invoking the
>> ACPI code. When a reboot happens, the firmware looks for the code and
>> acts on it by sending sequences of commands to the TPM.
>>
>> This patch adds the ACPI code. It is similar to the one in EDK2 but
>> doesn't
>> assume that SMIs are necessary to use. Besides that it tests the code
>> entered by the user and checks whether it is supported. The range of codes
>> supported matches the range of codes supported in SeaBIOS. It uses the
>> same
>> datastructure for the shared memory as EDK2 does so that EDK2 and SeaBIOS
>> could both make use of the shared memory.
>>
>> The underlying TCG specification is accessible from the following page.
>>
>>
>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>
>> This patch implements version 1.20.
>
>
> The below ACPI code is partly a translation to C from a previous posted
> patch:
>
> https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg05353.html
>
>

And fwiw, this is the acpi dump disassembled:

            Device (ISA.TPM)
            {
                Name (_HID, EisaId ("PNP0C31"))  // _HID: Hardware ID
                Name (_STA, 0x0F)  // _STA: Status
                Name (_CRS, ResourceTemplate ()  // _CRS: Current
Resource Settings
                {
                    Memory32Fixed (ReadWrite,
                        0xFED40000,         // Address Base
                        0x00005000,         // Address Length
                        )
                })
                OperationRegion (TPPI, SystemMemory, 0xFFFF0000, 0x31)
                Field (TPPI, AnyAcc, NoLock, Preserve)
                {
                    PPIN,   8,
                    PPIP,   32,
                    PPRP,   32,
                    PPRQ,   32,
                    PPRM,   32,
                    LPPR,   32,
                    FRET,   32,
                    RES1,   8,
                    RES2,   128,
                    FAIL,   32
                }

                Method (WRAM, 2, Serialized)
                {
                    PPRQ = Arg0
                    PPRM = Arg1
                    Return (Zero)
                }

                Method (CKOP, 1, NotSerialized)
                {
                    If ((Arg0 == Zero))
                    {
                        Return (One)
                    }

                    Return (Zero)
                }

                Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
                {
                    If ((Arg0 == ToUUID
("3dddfaa6-361b-4eb4-a424-8d10089d1653") /* Physical Presence
Interface */))
                    {
                        Local0 = ToInteger (Arg2)
                        If ((Local0 == Zero))
                        {
                            Return (Buffer (0x02)
                            {
                                 0xFF, 0x01
           // ..
                            })
                        }

                        If ((Local0 == One))
                        {
                            Return ("1.2")
                        }

                        If ((Local0 == 0x02))
                        {
                            Local0 = DerefOf (Arg3 [Zero])
                            If (CKOP (Local0))
                            {
                                Return (WRAM (Local0, Zero))
                            }

                            Return (One)
                        }

                        If ((Local0 == 0x03))
                        {
                            Return (Package (0x02)
                            {
                                Zero,
                                PPRQ
                            })
                        }

                        If ((Local0 == 0x04))
                        {
                            Return (0x02)
                        }

                        If ((Local0 == 0x05))
                        {
                            Return (Package (0x03)
                            {
                                FAIL,
                                LPPR,
                                PPRP
                            })
                        }

                        If ((Local0 == 0x06))
                        {
                            Return (0x03)
                        }

                        If ((Local0 == 0x07))
                        {
                            Local0 = DerefOf (Arg3 [Zero])
                            If (CKOP (Local0))
                            {
                                Local1 = WRAM (Local0, Zero)
                                Return (Local1)
                            }

                            Return (One)
                        }

                        If ((Local0 == 0x08))
                        {
                            Local0 = DerefOf (Arg3 [Zero])
                            If (CKOP (Local0))
                            {
                                Return (0x04)
                            }

                            Return (Zero)
                        }

                        Return (Buffer (One)
                        {
                             0x00
       // .
                        })
                    }
                }

Linux PPI driver seems to be happy about it, looking at
/sys/devices/pnp0/00\:06/tpm/tpm0/ppi/.

I haven't done further testing. Is there anything using this on Linux?
tpm2-tools doesn't seem to use it. I suppose I should be able to write
something to /sys/devices/pnp0/00\:06/tpm/tpm0/ppi/request.

Any help appreciated :)

>    Stefan
>
>>
>> Signed-off-by: Stefan Berger <address@hidden>
>> ---
>>   hw/i386/acpi-build.c  | 227
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/hw/acpi/tpm.h |  15 ++++
>>   2 files changed, 242 insertions(+)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 18b939e..e3905a3 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -42,6 +42,7 @@
>>   #include "hw/acpi/memory_hotplug.h"
>>   #include "sysemu/tpm.h"
>>   #include "hw/acpi/tpm.h"
>> +#include "hw/tpm/tpm_ppi.h"
>>   #include "hw/acpi/vmgenid.h"
>>   #include "sysemu/tpm_backend.h"
>>   #include "hw/timer/mc146818rtc_regs.h"
>> @@ -1860,6 +1861,231 @@ static Aml *build_q35_osc_method(void)
>>   }
>>
>>   static void
>> +build_tpm_ppi(Aml *dev, TPMVersion tpm_version)
>> +{
>> +    Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *pak;
>> +
>> +    aml_append(dev,
>> +               aml_operation_region("TPPI", AML_SYSTEM_MEMORY,
>> +                                    aml_int(TPM_PPI_ADDR_BASE),
>> +                                    TPM_PPI_STRUCT_SIZE));
>> +
>> +    field = aml_field("TPPI", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
>> +    aml_append(field, aml_named_field("PPIN",
>> +               sizeof(uint8_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPIP",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRP",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRQ",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRM",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("LPPR",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("FRET",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("RES1",
>> +               sizeof(uint8_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("RES2",
>> +               sizeof(uint32_t) * BITS_PER_BYTE * 4));
>> +    aml_append(field, aml_named_field("FAIL",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(dev, field);
>> +
>> +    /*
>> +     * Write the given operations code into 'PPRQ'.
>> +     */
>> +    method = aml_method("WRAM", 2, AML_SERIALIZED);
>> +    {
>> +        aml_append(method, aml_store(aml_arg(0), aml_name("PPRQ")));
>> +        aml_append(method, aml_store(aml_arg(1), aml_name("PPRM")));
>> +        /* 0 = Success */
>> +        aml_append(method, aml_return(aml_int(0)));
>> +    }
>> +    aml_append(dev, method);
>> +
>> +    /*
>> +     * CKOP: Check whether the opcode is valid
>> +     */
>> +    if (tpm_version == TPM_VERSION_1_2) {
>> +        method = aml_method("CKOP", 1, AML_NOTSERIALIZED);
>> +        {
>> +            ifctx = aml_if(
>> +                      aml_or(
>> +                        aml_or(
>> +                          aml_and(
>> +                            aml_lgreater_equal(aml_arg(0), aml_int(0)),
>> +                            aml_lless_equal(aml_arg(0), aml_int(11)),
>> +                            NULL
>> +                          ),
>> +                          aml_equal(aml_arg(0), aml_int(14)),
>> +                          NULL
>> +                        ),
>> +                        aml_and(
>> +                          aml_lgreater_equal(aml_arg(0), aml_int(21)),
>> +                          aml_lless_equal(aml_arg(0), aml_int(22)),
>> +                          NULL
>> +                       ),
>> +                       NULL
>> +                      )
>> +                    );
>> +            {
>> +                aml_append(ifctx, aml_return(aml_int(1)));
>> +            }
>> +            aml_append(method, ifctx);
>> +
>> +            aml_append(method, aml_return(aml_int(0)));
>> +        }
>> +    } else {
>> +        method = aml_method("CKOP", 1, AML_NOTSERIALIZED);
>> +        {
>> +            ifctx = aml_if(
>> +                      aml_equal(aml_arg(0), aml_int(0))
>> +                    );
>> +            {
>> +                aml_append(ifctx, aml_return(aml_int(1)));
>> +            }
>> +            aml_append(method, ifctx);
>> +
>> +            aml_append(method, aml_return(aml_int(0)));
>> +        }
>> +    }
>> +    aml_append(dev, method);
>> +
>> +    method = aml_method("_DSM", 4, AML_SERIALIZED);
>> +    {
>> +        uint8_t zerobyte[1] = { 0 };
>> +
>> +        ifctx = aml_if(
>> +                  aml_equal(aml_arg(0),
>> +
>> aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))
>> +                );
>> +        {
>> +            aml_append(ifctx,
>> +                       aml_store(aml_to_integer(aml_arg(2)),
>> aml_local(0)));
>> +
>> +            /* standard DSM query function */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
>> +            {
>> +                uint8_t byte_list[2] = { 0xff, 0x01 };
>> +                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* interface version: 1.2 */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
>> +            {
>> +                aml_append(ifctx2, aml_return(aml_string("1.2")));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit TPM operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
>> +            {
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                ifctx3 = aml_if(aml_call1("CKOP", aml_local(0)));
>> +                {
>> +                    aml_append(ifctx3,
>> +                               aml_return(aml_call2("WRAM",
>> +                                                    aml_local(0),
>> +                                                    aml_int(0))));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +                aml_append(ifctx2, aml_return(aml_int(1)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get pending TPM operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
>> +            {
>> +                pak = aml_package(2);
>> +                aml_append(pak, aml_int(0));
>> +                aml_append(pak, aml_name("PPRQ"));
>> +                aml_append(ifctx2, aml_return(pak));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get platform-specific action to transition to pre-OS env.
>> */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
>> +            {
>> +                /* 2 = reboot */
>> +                aml_append(ifctx2, aml_return(aml_int(2)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get TPM operation response */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
>> +            {
>> +                pak = aml_package(3);
>> +
>> +                aml_append(pak, aml_name("FAIL"));
>> +                aml_append(pak, aml_name("LPPR"));
>> +                aml_append(pak, aml_name("PPRP"));
>> +
>> +                aml_append(ifctx2, aml_return(pak));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit preferred user language */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
>> +            {
>> +                /* 3 = not implemented */
>> +                aml_append(ifctx2, aml_return(aml_int(3)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit TPM operation v2 */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
>> +            {
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                ifctx3 = aml_if(aml_call1("CKOP", aml_local(0)));
>> +                {
>> +                    aml_append(ifctx3,
>> +                               aml_store(aml_call2("WRAM",
>> +                                                   aml_local(0),
>> +                                                   aml_int(0)),
>> +                                         aml_local(1)));
>> +                    aml_append(ifctx3, aml_return(aml_local(1)));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +                /* 1 = requested operation not implemented */
>> +                aml_append(ifctx2, aml_return(aml_int(1)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get user confirmation status for operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
>> +            {
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                ifctx3 = aml_if(aml_call1("CKOP", aml_local(0)));
>> +                {
>> +                    /* 4 = Allowed and physically present user not
>> required */
>> +                    aml_append(ifctx3, aml_return(aml_int(4)));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +                /* 0 = requested operation not implemented */
>> +                aml_append(ifctx2, aml_return(aml_int(0)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>> +        }
>> +        aml_append(method, ifctx);
>> +    }
>> +    aml_append(dev, method);
>> +}
>> +
>> +static void
>>   build_dsdt(GArray *table_data, BIOSLinker *linker,
>>              AcpiPmInfo *pm, AcpiMiscInfo *misc,
>>              Range *pci_hole, Range *pci_hole64, MachineState *machine)
>> @@ -2218,6 +2444,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>>                    */
>>                   /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
>>                   aml_append(dev, aml_name_decl("_CRS", crs));
>> +                build_tpm_ppi(dev, misc->tpm_version);
>>                   aml_append(scope, dev);
>>               }
>>
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index d9b7452..23f5da1 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -37,4 +37,19 @@
>>   #define TPM_PPI_ADDR_SIZE           0x100
>>   #define TPM_PPI_ADDR_BASE           0xffff0000
>>
>> +struct tpm_ppi {
>> +    uint8_t ppin;            /* set by BIOS; currently initialization
>> flag */
>> +    uint32_t ppip;           /* set by ACPI; not used */
>> +    uint32_t pprp;           /* response from TPM; set by BIOS */
>> +    uint32_t pprq;           /* opcode; set by ACPI */
>> +    uint32_t pprm;           /* parameter for opcode; set by ACPI */
>> +    uint32_t lppr;           /* last opcode; set by BIOS */
>> +    uint32_t fret;           /* set by ACPI; not used*/
>> +    uint32_t res1;           /* reserved */
>> +    uint32_t res2[4];        /* reserved */
>> +    uint32_t fail;           /* set by BIOS (0 = success) */
>> +} QEMU_PACKED;
>> +
>> +#define TPM_PPI_STRUCT_SIZE  sizeof(struct tpm_ppi)
>> +
>>   #endif /* HW_ACPI_TPM_H */
>
>
>
>

otherwise, patch looks good.

-- 
Marc-André Lureau



reply via email to

[Prev in Thread] Current Thread [Next in Thread]