qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 2/5] Support Physical Presence Interface Spec


From: Stefan Berger
Subject: [Qemu-devel] [PATCH 2/5] Support Physical Presence Interface Spec
Date: Wed, 15 Apr 2015 18:38:45 -0400

For automated management of a TPM device, implement the TCG Physical Presence
Interface Specification that allows a root user on Linux (for example) to set
an opcode for a sequence of TPM operations that the BIOS is supposed to execute
upon reboot of the physical or virtual machine. A sequence of operations may for
example involve giving up ownership of the TPM and activating and enabling the
device.

The sequences of operations are defined in table 2 in the specs to be found
at the following link:

http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification

As an example, in recent versions of Linux the opcode (5) can be set as
follows:

cd /sys/devices/pnp0/00\:04/ppi

echo 5 > request

This ACPI implementation assumes that the underlying firmware (SeaBIOS)
has 'thrown an anchor' into the f-segment. The anchor is identified by
two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
in the f-segment is write-protected and holds a pointer to a structure
in high memmory area where the ACPI code writes the opcode into and
where it can read the last response from the BIOS.

The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
Also '0' is supported to 'clear' an intention.


Signed-off-by: Stefan Berger <address@hidden>
Cc: Michael Tsirkin <address@hidden>
Cc: Kevin O'Connor <address@hidden>
---
 hw/i386/acpi-tpm-core.dsl | 277 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/i386/acpi-tpm2.dsl     |  27 +++++
 hw/i386/q35-acpi-dsdt.dsl |   1 +
 hw/i386/ssdt-tpm.dsl      |  12 +-
 4 files changed, 306 insertions(+), 11 deletions(-)
 create mode 100644 hw/i386/acpi-tpm-core.dsl
 create mode 100644 hw/i386/acpi-tpm2.dsl

diff --git a/hw/i386/acpi-tpm-core.dsl b/hw/i386/acpi-tpm-core.dsl
new file mode 100644
index 0000000..20fdee4
--- /dev/null
+++ b/hw/i386/acpi-tpm-core.dsl
@@ -0,0 +1,277 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Note: This implementation follows the TCG specification
+ * 'TCG Physical Presence Interface Specification' of which the latest
+ * version can be found here:
+ * 
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
+ */
+
+#include "hw/acpi/tpm.h"
+
+#define TCG_MAGIC 0x41504354
+
+/*
+ * common code for TPM SSDT and TPM2
+ */
+Name (_HID, EisaID ("PNP0C31"))
+Name (_CRS, ResourceTemplate ()
+{
+    Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
+    // older Linux tpm_tis drivers do not work with IRQ
+    //IRQNoFlags () {TPM_TIS_IRQ}
+})
+
+Method (_STA, 0, NotSerialized) {
+    Return (0x0F)
+}
+
+OperationRegion (TTIS, SystemMemory,
+                 TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
+
+// Define TPM Debug register
+Field(TTIS, AnyAcc, NoLock, Preserve) {
+    Offset (0xf90),
+    TDBG, 32        // QEMU TIS Debug
+}
+
+// Last accepted opcode
+NAME(OP, Zero)
+
+// Field to access f-segment
+OperationRegion (FSEG, SystemMemory, 0xf0000, 0x10000)
+Field(FSEG, WordAcc, NoLock, Preserve) {
+   FDAT, 0x80000
+}
+
+// Read a 32bit word from memory; this function
+// is used for accessing the bitfield in FDAT
+Method (RD32, 2, NotSerialized) {
+    Store(DerefOf(Index(Arg0, Arg1)), Local0)
+    Increment(Arg1)
+    Store(DerefOf(Index(Arg0, Arg1)), Local1)
+    Increment(Arg1)
+    Store(DerefOf(Index(Arg0, Arg1)), Local2)
+    Increment(Arg1)
+    Store(DerefOf(Index(Arg0, Arg1)), Local3)
+    Or(Local0, ShiftLeft(Local1,  8), Local0)
+    Or(Local0, ShiftLeft(Local2, 16), Local0)
+    Or(Local0, ShiftLeft(Local3, 24), Local0)
+    Return (Local0)
+}
+
+// The address in high memory where we exchange
+// info with the BIOS
+Name(ADDR, 0x0)
+
+// Scan the f-segment for our anchor with
+// signature TCG_MAGIC
+Method (SCAN, 0, NotSerialized) {
+    Store( Zero, Local1)
+    While (LLess(Local1, 0x10000)) {
+        Store(DerefOf(Index(FDAT, Local1)), Local0)
+        // first scan for single byte
+        If (LEqual(Local0, 0x54)) {
+           // Check two two 4-byte signatures
+            If (LAnd(
+                 LEqual(RD32(FDAT,     Local1    ), TCG_MAGIC),
+                 LEqual(RD32(FDAT, Add(Local1, 8)), TCG_MAGIC)
+               )
+            ) {
+               //Store ( RD32(FDAT, Add(Local1, 4)), TDBG)
+               Store ( RD32(FDAT, Add(Local1, 4)), ADDR)
+               Break
+            }
+        }
+        Add(Local1, 16, Local1)
+    }
+}
+
+// Write given opcode into RAM
+Method (WRAM, 1, NotSerialized) {
+    If (LEqual(ADDR, 0x0)) {
+        // find high memory reserved by BIOS; this will
+        // set ADDR
+        SCAN( )
+    }
+    If (LNotEqual(ADDR, 0x0)) {
+        // Write to high memory pointed to by ADDR
+        OperationRegion (HIGH, SystemMemory, ADDR, 0x10)
+        Field(HIGH, AnyAcc, NoLock, Preserve) {
+           SIG1, 32,
+           SIZE, 16,
+           CODE, 8
+        }
+        If (LAnd(
+            LEqual(SIG1, TCG_MAGIC),
+            LGreaterEqual(SIZE, 1))
+        ) {
+            // Remember last opcode in CODE
+            Store(Arg0, CODE)
+            // Write opcode for BIOS to find
+            Store(Arg0, OP)
+            Return ( 0 )
+        }
+    }
+    Return ( 1 )
+}
+
+
+Method (RRAM, 0, NotSerialized) {
+    Name (OPRE, Package(3) { 1, 0, 0})
+    If (LEqual(ADDR, 0x0)) {
+        // find high memory reserved by BIOS; this will
+        // set ADDR
+        SCAN( )
+    }
+    If (LNotEqual(ADDR, 0x0)) {
+        // Read from memory pointed to by ADDR
+        OperationRegion (HIGH, SystemMemory, ADDR, 0x10)
+        Field(HIGH, AnyAcc, NoLock, Preserve) {
+           SIG1, 32,
+           SIZE, 16,
+           CODE, 8,
+           SUCC, 8,
+           CODO, 8,
+           RESP, 32
+        }
+        // Check signature and sufficient space
+        If (LAnd(
+            LEqual(SIG1, TCG_MAGIC),
+            LGreaterEqual(SIZE, 7)
+        )) {
+            Store(SUCC, Index(OPRE, 0))
+            Store(CODO, Index(OPRE, 1))
+            Store(RESP, Index(OPRE, 2))
+        }
+    }
+    return (OPRE)
+}
+
+Method (_DSM, 4, NotSerialized) {
+    If (LEqual (Arg0, ToUUID("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))) {
+
+        // only supporting API revision 1
+        If (LNotEqual (Arg1, 1)) {
+            Return (Buffer (1) {0})
+        }
+
+        Store(ToInteger(Arg2), Local0)
+        // standard DSM query function
+        If (LEqual (Local0, 0)) {
+            Return (Buffer () {0xFF, 0x01})
+        }
+
+        // interface version
+        If (LEqual (Local0, 1)) {
+            Return ("1.2")
+        }
+
+        // submit TPM operation
+        If (LEqual (Local0, 2)) {
+            // get opcode from package
+            Store(DerefOf(Index(Arg3, 0)), Local0)
+            // check for supported opcode
+            // supported opcodes: 0, 1-11, 14, 21-22
+            If (LOr(
+                  LOr(
+                    LAnd(LGreaterEqual(Local0, 0),
+                         LLessEqual(Local0, 11)),
+                    LEqual(Local0, 14)
+                  ),
+                    LAnd(LGreaterEqual(Local0, 21),
+                         LLessEqual(Local0, 22))
+                  )
+               ) {
+                // Write the OP into TPM NVRAM
+                Store(WRAM ( Local0 ), Local1)
+                return (Local1)
+            } else {
+                Return (1)
+            }
+        }
+
+        // get pending TPM operation
+        If (LEqual (Local0, 3)) {
+            NAME(PEOP, Package(2) { 0, 0 })
+
+            Store ( 0 , Index(PEOP, 0))
+            Store ( OP, Index(PEOP, 1))
+
+            Return (PEOP)
+        }
+
+        // action to transition to pre-OS env.
+        If (LEqual (Local0, 4)) {
+            return (2) // Requiring reboot
+        }
+
+        // get pre-OS TPM operation response
+        If (LEqual (Local0, 5)) {
+            Store (RRAM(), Local0)
+            return ( Local0 )
+        }
+
+        // preferred user language
+        If (LEqual (Local0, 6)) {
+            return (3) // Not implemented
+        }
+
+        // submit TPM operation v2
+        If (LEqual (Local0, 7)) {
+            Store(DerefOf(Index(Arg3, 0)), Local0)
+            // supported opcodes: 0, 1-11, 14, 21-22
+            If (LOr(
+                  LOr(
+                    LAnd(LGreaterEqual(Local0, 0),
+                         LLessEqual(Local0, 11)),
+                    LEqual(Local0, 14)
+                  ),
+                  LAnd(LGreaterEqual(Local0, 21),
+                  LLessEqual(Local0, 22))
+           )
+            ) {
+                // Write the OP into TPM NVRAM
+                Store(WRAM ( Local0 ), Local1)
+                return (Local1)
+            } else {
+                Return (1)
+            }
+        }
+
+        // get user confirmation status
+        If (LEqual (Local0, 8)) {
+            Store(DerefOf(Index(Arg3,0)), Local0)
+            // supported opcodes: 0, 1-11, 14, 21-22
+            If (LOr(
+                  LOr(
+                     LAnd(LGreaterEqual(Local0, 0),
+                          LLessEqual(Local0, 11)),
+                     LEqual(Local0, 14)
+                  ),
+                LAnd(LGreaterEqual(Local0, 21),
+                     LLessEqual(Local0, 22))
+                )
+            ) {
+                Return (4)  // allowed, no user required
+            } else {
+                Return (0)  // not implemented
+            }
+        }
+    }
+    return (Buffer() { 0x0 })
+}
+
diff --git a/hw/i386/acpi-tpm2.dsl b/hw/i386/acpi-tpm2.dsl
new file mode 100644
index 0000000..3d31125
--- /dev/null
+++ b/hw/i386/acpi-tpm2.dsl
@@ -0,0 +1,27 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Note: This implementation follows the TCG specification
+ * 'TCG Physical Presence Interface Specification' of which the latest
+ * version can be found here:
+ * 
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
+ */
+
+Scope(\_SB) {
+    Device(TPM2) {
+#include "acpi-tpm-core.dsl"
+    }
+}
diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
index 16eaca3..a73035d 100644
--- a/hw/i386/q35-acpi-dsdt.dsl
+++ b/hw/i386/q35-acpi-dsdt.dsl
@@ -115,6 +115,7 @@ DefinitionBlock (
     }
 
 #include "acpi-dsdt-hpet.dsl"
+#include "acpi-tpm2.dsl"
 
 
 /****************************************************************
diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
index 75d9691..32d268c 100644
--- a/hw/i386/ssdt-tpm.dsl
+++ b/hw/i386/ssdt-tpm.dsl
@@ -12,7 +12,6 @@
  * You should have received a copy of the GNU General Public License along
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include "hw/acpi/tpm.h"
 
 ACPI_EXTRACT_ALL_CODE ssdt_tpm_aml
 
@@ -28,16 +27,7 @@ DefinitionBlock (
     Scope(\_SB) {
         /* TPM with emulated TPM TIS interface */
         Device (TPM) {
-            Name (_HID, EisaID ("PNP0C31"))
-            Name (_CRS, ResourceTemplate ()
-            {
-                Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
-                // older Linux tpm_tis drivers do not work with IRQ
-                //IRQNoFlags () {TPM_TIS_IRQ}
-            })
-            Method (_STA, 0, NotSerialized) {
-                Return (0x0F)
-            }
+#include "acpi-tpm-core.dsl"
         }
     }
 }
-- 
1.9.3




reply via email to

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