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 <stef...@linux.vnet.ibm.com> Cc: Michael Tsirkin <m...@redhat.com> Cc: Kevin O'Connor <ke...@koconnor.net> --- hw/i386/ssdt-tpm.dsl | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/acpi/tpm.h | 20 ++++++ 2 files changed, 209 insertions(+) diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl index 75d9691..7d28899 100644 --- a/hw/i386/ssdt-tpm.dsl +++ b/hw/i386/ssdt-tpm.dsl @@ -38,6 +38,195 @@ DefinitionBlock ( 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) + + // The base address in TIS 'RAM' where we exchange + // data with the BIOS + Name(ADDR, 0xfed40fa0) + + // Write given opcode into 'RAM' + Method (WRAM, 1, NotSerialized) { + // Write to high memory pointed to by ADDR + OperationRegion (HIGH, SystemMemory, ADDR, TPM_PPI_STRUCT_SIZE) + Field(HIGH, AnyAcc, NoLock, Preserve) { + SIG1, 32, + SIZE, 16, + CODE, 8 + } + If (LAnd( + LEqual(SIG1, TCG_MAGIC), + LGreaterEqual(SIZE, 1)) + ) { + // Write opcode for BIOS to find + Store(Arg0, CODE) + // Remember last opcode in CODE + Store(Arg0, OP) + Return ( 0 ) + } + Return ( 1 ) + } + + // read data from 'RAM' + Method (RRAM, 0, NotSerialized) { + Name (OPRE, Package(3) { 1, 0, 0}) + // Read from memory pointed to by ADDR + OperationRegion (HIGH, SystemMemory, ADDR, TPM_PPI_STRUCT_SIZE) + 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/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h index 6d516c6..8d9c8dc 100644 --- a/include/hw/acpi/tpm.h +++ b/include/hw/acpi/tpm.h @@ -31,4 +31,24 @@ #define TPM2_START_METHOD_MMIO 6 +/* + * Physical Presence Interface -- shared with the BIOS + */ +#define TCG_MAGIC 0x41504354 + +#if 0 +struct tpm_ppi { + uint32_t sign1; // TCG_MAGIC + uint16_t size; // number of subsequent bytes for ACPI to access + uint8_t opcode; // set by ACPI + uint8_t failure; // set by BIOS (0 = success) + uint8_t recent_opcode; // set by BIOS + uint32_t response; // set by BIOS + uint8_t next_step; // BIOS only + uint32_t sign2; // TCG_MAGIC +} QEMU_PACKED; +#endif + +#define TPM_PPI_STRUCT_SIZE 18 + #endif /* HW_ACPI_TPM_H */ -- 1.9.3