qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
To: "Marc-André Lureau" <marcandre.lureau@gmail.com>
Cc: QEMU <qemu-devel@nongnu.org>,
	kevin@koconnor.net, "Michael S. Tsirkin" <mst@redhat.com>,
	Laszlo Ersek <lersek@redhat.com>,
	Igor Mammedov <imammedo@redhat.com>
Subject: Re: [Qemu-devel] [RFC PATCH 3/3] acpi: Build TPM Physical Presence interface
Date: Fri, 12 Jan 2018 15:16:32 -0500	[thread overview]
Message-ID: <adb2b9e0-43b6-85fa-9832-f29b9d7b391d@linux.vnet.ibm.com> (raw)
In-Reply-To: <CAJ+F1CK4umAVmPvPLunjXf10UcL_gVqENgu94eO17h82BPQzRA@mail.gmail.com>

On 01/12/2018 11:07 AM, Marc-André Lureau wrote:
> Hi
>
> On Wed, Jan 10, 2018 at 7:49 PM, Stefan Berger
> <stefanb@linux.vnet.ibm.com> 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 <stefanb@linux.vnet.ibm.com>
>>> ---
>>>    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);
>>> +


CKOP checks whether the firmware implements a certain code. Function 8 
returns a number 0 - 4 for a certain code, 0 meaning 'Not implemented'. 
Maybe the firmware should fill an array and put the numbers in that 
function 8 expects and CKOP can use that also to see whether functions 
are supported. That may 'loosen' the ACPI a bit from the firmware.

Comments? Is that better than hard coding in the ACPI what the firmware 
supports?

specs: 
https://trustedcomputinggroup.org/wp-content/uploads/Physical_Presence_Interface_1-20_0-100.pdf


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

      parent reply	other threads:[~2018-01-12 20:16 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-10 18:35 [Qemu-devel] [RFC PATCH 0/3] Implement Pysical Presence Interface for TPM 1.2 and 2 Stefan Berger
2018-01-10 18:35 ` [Qemu-devel] [RFC PATCH 1/3] tpm: Implement virtual memory device for TPM PPI Stefan Berger
2018-01-12 14:55   ` Marc-André Lureau
2018-01-12 16:29     ` Eric Blake
2018-01-12 17:24       ` Stefan Berger
2018-01-12 18:23     ` Stefan Berger
2018-01-15 14:49     ` Stefan Berger
2018-01-10 18:35 ` [Qemu-devel] [RFC PATCH 2/3] acpi: implement aml_lless_equal Stefan Berger
2018-01-12 15:17   ` Marc-André Lureau
2018-01-12 19:42     ` Stefan Berger
2018-01-15 14:31       ` Igor Mammedov
2018-01-10 18:35 ` [Qemu-devel] [RFC PATCH 3/3] acpi: Build TPM Physical Presence interface Stefan Berger
2018-01-10 18:49   ` Stefan Berger
2018-01-12 16:07     ` Marc-André Lureau
2018-01-12 17:00       ` Stefan Berger
2018-01-12 20:16       ` Stefan Berger [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=adb2b9e0-43b6-85fa-9832-f29b9d7b391d@linux.vnet.ibm.com \
    --to=stefanb@linux.vnet.ibm.com \
    --cc=imammedo@redhat.com \
    --cc=kevin@koconnor.net \
    --cc=lersek@redhat.com \
    --cc=marcandre.lureau@gmail.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).