xref: /freebsd/usr.sbin/bhyve/tpm_ppi_qemu.c (revision f7d45c54)
185a775e6SCorvin Köhne /*-
285a775e6SCorvin Köhne  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
385a775e6SCorvin Köhne  *
485a775e6SCorvin Köhne  * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
585a775e6SCorvin Köhne  * Author: Corvin Köhne <c.koehne@beckhoff.com>
685a775e6SCorvin Köhne  */
785a775e6SCorvin Köhne 
885a775e6SCorvin Köhne #include <sys/types.h>
985a775e6SCorvin Köhne #include <sys/param.h>
1085a775e6SCorvin Köhne #include <sys/endian.h>
1185a775e6SCorvin Köhne #include <sys/linker_set.h>
1285a775e6SCorvin Köhne 
1385a775e6SCorvin Köhne #include <machine/vmm.h>
1485a775e6SCorvin Köhne 
1585a775e6SCorvin Köhne #include <assert.h>
1685a775e6SCorvin Köhne #include <err.h>
1785a775e6SCorvin Köhne #include <errno.h>
1885a775e6SCorvin Köhne #include <vmmapi.h>
1985a775e6SCorvin Köhne 
2085a775e6SCorvin Köhne #include "acpi.h"
2185a775e6SCorvin Köhne #include "acpi_device.h"
2285a775e6SCorvin Köhne #include "config.h"
2385a775e6SCorvin Köhne #include "mem.h"
2485a775e6SCorvin Köhne #include "qemu_fwcfg.h"
2585a775e6SCorvin Köhne #include "tpm_ppi.h"
2685a775e6SCorvin Köhne 
2785a775e6SCorvin Köhne #define TPM_PPI_ADDRESS 0xFED45000
2885a775e6SCorvin Köhne #define TPM_PPI_SIZE 0x1000
2985a775e6SCorvin Köhne 
3085a775e6SCorvin Köhne #define TPM_PPI_FWCFG_FILE "etc/tpm/config"
3185a775e6SCorvin Köhne 
3285a775e6SCorvin Köhne #define TPM_PPI_QEMU_NAME "qemu"
3385a775e6SCorvin Köhne 
3485a775e6SCorvin Köhne struct tpm_ppi_qemu {
3585a775e6SCorvin Köhne 	uint8_t func[256];	    // FUNC
3685a775e6SCorvin Köhne 	uint8_t in;		    // PPIN
3785a775e6SCorvin Köhne 	uint32_t ip;		    // PPIP
3885a775e6SCorvin Köhne 	uint32_t response;	    // PPRP
3985a775e6SCorvin Köhne 	uint32_t request;	    // PPRQ
4085a775e6SCorvin Köhne 	uint32_t request_parameter; // PPRM
4185a775e6SCorvin Köhne 	uint32_t last_request;	    // LPPR
4285a775e6SCorvin Köhne 	uint32_t func_ret;	    // FRET
4385a775e6SCorvin Köhne 	uint8_t _reserved1[0x40];   // RES1
4485a775e6SCorvin Köhne 	uint8_t next_step;	    // next_step
4585a775e6SCorvin Köhne } __packed;
4685a775e6SCorvin Köhne static_assert(sizeof(struct tpm_ppi_qemu) <= TPM_PPI_SIZE,
4785a775e6SCorvin Köhne     "Wrong size of tpm_ppi_qemu");
4885a775e6SCorvin Köhne 
4985a775e6SCorvin Köhne struct tpm_ppi_fwcfg {
5085a775e6SCorvin Köhne 	uint32_t ppi_address;
5185a775e6SCorvin Köhne 	uint8_t tpm_version;
5285a775e6SCorvin Köhne 	uint8_t ppi_version;
5385a775e6SCorvin Köhne } __packed;
5485a775e6SCorvin Köhne 
5585a775e6SCorvin Köhne static int
tpm_ppi_mem_handler(struct vcpu * const vcpu __unused,const int dir,const uint64_t addr,const int size,uint64_t * const val,void * const arg1,const long arg2 __unused)5685a775e6SCorvin Köhne tpm_ppi_mem_handler(struct vcpu *const vcpu __unused, const int dir,
5785a775e6SCorvin Köhne     const uint64_t addr, const int size, uint64_t *const val, void *const arg1,
5885a775e6SCorvin Köhne     const long arg2 __unused)
5985a775e6SCorvin Köhne {
6085a775e6SCorvin Köhne 	struct tpm_ppi_qemu *ppi;
6185a775e6SCorvin Köhne 	uint8_t *ptr;
6285a775e6SCorvin Köhne 	uint64_t off;
6385a775e6SCorvin Köhne 
6485a775e6SCorvin Köhne 	if ((addr & (size - 1)) != 0) {
6585a775e6SCorvin Köhne 		warnx("%s: unaligned %s access @ %16lx [size = %x]", __func__,
6685a775e6SCorvin Köhne 		    (dir == MEM_F_READ) ? "read" : "write", addr, size);
6785a775e6SCorvin Köhne 	}
6885a775e6SCorvin Köhne 
6985a775e6SCorvin Köhne 	ppi = arg1;
7085a775e6SCorvin Köhne 
7185a775e6SCorvin Köhne 	off = addr - TPM_PPI_ADDRESS;
7285a775e6SCorvin Köhne 	ptr = (uint8_t *)ppi + off;
7385a775e6SCorvin Köhne 
7485a775e6SCorvin Köhne 	if (off > TPM_PPI_SIZE || off + size > TPM_PPI_SIZE) {
7585a775e6SCorvin Köhne 		return (EINVAL);
7685a775e6SCorvin Köhne 	}
7785a775e6SCorvin Köhne 
7885a775e6SCorvin Köhne 	assert(size == 1 || size == 2 || size == 4 || size == 8);
7985a775e6SCorvin Köhne 	if (dir == MEM_F_READ) {
8085a775e6SCorvin Köhne 		memcpy(val, ptr, size);
8185a775e6SCorvin Köhne 	} else {
8285a775e6SCorvin Köhne 		memcpy(ptr, val, size);
8385a775e6SCorvin Köhne 	}
8485a775e6SCorvin Köhne 
8585a775e6SCorvin Köhne 	return (0);
8685a775e6SCorvin Köhne }
8785a775e6SCorvin Köhne 
8885a775e6SCorvin Köhne static struct mem_range ppi_mmio = {
8985a775e6SCorvin Köhne 	.name = "ppi-mmio",
9085a775e6SCorvin Köhne 	.base = TPM_PPI_ADDRESS,
9185a775e6SCorvin Köhne 	.size = TPM_PPI_SIZE,
9285a775e6SCorvin Köhne 	.flags = MEM_F_RW,
9385a775e6SCorvin Köhne 	.handler = tpm_ppi_mem_handler,
9485a775e6SCorvin Köhne };
9585a775e6SCorvin Köhne 
9685a775e6SCorvin Köhne static int
tpm_ppi_init(void ** sc)9785a775e6SCorvin Köhne tpm_ppi_init(void **sc)
9885a775e6SCorvin Köhne {
9985a775e6SCorvin Köhne 	struct tpm_ppi_qemu *ppi = NULL;
10085a775e6SCorvin Köhne 	struct tpm_ppi_fwcfg *fwcfg = NULL;
10185a775e6SCorvin Köhne 	int error;
10285a775e6SCorvin Köhne 
10385a775e6SCorvin Köhne 	ppi = calloc(1, sizeof(*ppi));
10485a775e6SCorvin Köhne 	if (ppi == NULL) {
10585a775e6SCorvin Köhne 		warnx("%s: failed to allocate acpi region for ppi", __func__);
10685a775e6SCorvin Köhne 		error = ENOMEM;
10785a775e6SCorvin Köhne 		goto err_out;
10885a775e6SCorvin Köhne 	}
10985a775e6SCorvin Köhne 
11085a775e6SCorvin Köhne 	fwcfg = calloc(1, sizeof(struct tpm_ppi_fwcfg));
11185a775e6SCorvin Köhne 	if (fwcfg == NULL) {
11285a775e6SCorvin Köhne 		warnx("%s: failed to allocate fwcfg item", __func__);
11385a775e6SCorvin Köhne 		error = ENOMEM;
11485a775e6SCorvin Köhne 		goto err_out;
11585a775e6SCorvin Köhne 	}
11685a775e6SCorvin Köhne 
11785a775e6SCorvin Köhne 	fwcfg->ppi_address = htole32(TPM_PPI_ADDRESS);
11885a775e6SCorvin Köhne 	fwcfg->tpm_version = 2;
11985a775e6SCorvin Köhne 	fwcfg->ppi_version = 1;
12085a775e6SCorvin Köhne 
12185a775e6SCorvin Köhne 	error = qemu_fwcfg_add_file(TPM_PPI_FWCFG_FILE,
12285a775e6SCorvin Köhne 	    sizeof(struct tpm_ppi_fwcfg), fwcfg);
12385a775e6SCorvin Köhne 	if (error) {
12485a775e6SCorvin Köhne 		warnx("%s: failed to add fwcfg file", __func__);
12585a775e6SCorvin Köhne 		goto err_out;
12685a775e6SCorvin Köhne 	}
12785a775e6SCorvin Köhne 
12885a775e6SCorvin Köhne 	/*
12985a775e6SCorvin Köhne 	 * We would just need to create some guest memory for the PPI region.
13085a775e6SCorvin Köhne 	 * Sadly, bhyve has a strange memory interface. We can't just add more
13185a775e6SCorvin Köhne 	 * memory to the VM. So, create a trap instead which reads and writes to
13285a775e6SCorvin Köhne 	 * the ppi region. It's very slow but ppi shouldn't be used frequently.
13385a775e6SCorvin Köhne 	 */
13485a775e6SCorvin Köhne 	ppi_mmio.arg1 = ppi;
13585a775e6SCorvin Köhne 	error = register_mem(&ppi_mmio);
13685a775e6SCorvin Köhne 	if (error) {
13785a775e6SCorvin Köhne 		warnx("%s: failed to create trap for ppi accesses", __func__);
13885a775e6SCorvin Köhne 		goto err_out;
13985a775e6SCorvin Köhne 	}
14085a775e6SCorvin Köhne 
14185a775e6SCorvin Köhne 	*sc = ppi;
14285a775e6SCorvin Köhne 
14385a775e6SCorvin Köhne 	return (0);
14485a775e6SCorvin Köhne 
14585a775e6SCorvin Köhne err_out:
14685a775e6SCorvin Köhne 	free(fwcfg);
14785a775e6SCorvin Köhne 	free(ppi);
14885a775e6SCorvin Köhne 
14985a775e6SCorvin Köhne 	return (error);
15085a775e6SCorvin Köhne }
15185a775e6SCorvin Köhne 
15285a775e6SCorvin Köhne static void
tpm_ppi_deinit(void * sc)15385a775e6SCorvin Köhne tpm_ppi_deinit(void *sc)
15485a775e6SCorvin Köhne {
15585a775e6SCorvin Köhne 	struct tpm_ppi_qemu *ppi;
15685a775e6SCorvin Köhne 	int error;
15785a775e6SCorvin Köhne 
15885a775e6SCorvin Köhne 	if (sc == NULL)
15985a775e6SCorvin Köhne 		return;
16085a775e6SCorvin Köhne 
16185a775e6SCorvin Köhne 	ppi = sc;
16285a775e6SCorvin Köhne 
16385a775e6SCorvin Köhne 	error = unregister_mem(&ppi_mmio);
164*f7d45c54SPierre Pronchery 	assert(error == 0);
16585a775e6SCorvin Köhne 
16685a775e6SCorvin Köhne 	free(ppi);
16785a775e6SCorvin Köhne }
16885a775e6SCorvin Köhne 
16985a775e6SCorvin Köhne static int
tpm_ppi_write_dsdt_regions(void * sc __unused)17085a775e6SCorvin Köhne tpm_ppi_write_dsdt_regions(void *sc __unused)
17185a775e6SCorvin Köhne {
17285a775e6SCorvin Köhne 	/*
17385a775e6SCorvin Köhne 	 * struct tpm_ppi_qemu
17485a775e6SCorvin Köhne 	 */
17585a775e6SCorvin Köhne 	/*
17685a775e6SCorvin Köhne 	 * According to qemu the Windows ACPI parser has a bug that DerefOf is
17785a775e6SCorvin Köhne 	 * broken for SYSTEM_MEMORY. Due to that bug, qemu uses a dynamic
17885a775e6SCorvin Köhne 	 * operation region inside a method.
17985a775e6SCorvin Köhne 	 */
18085a775e6SCorvin Köhne 	dsdt_line("Method(TPFN, 1, Serialized)");
18185a775e6SCorvin Köhne 	dsdt_line("{");
18285a775e6SCorvin Köhne 	dsdt_line("  If(LGreaterEqual(Arg0, 0x100))");
18385a775e6SCorvin Köhne 	dsdt_line("  {");
18485a775e6SCorvin Köhne 	dsdt_line("    Return(Zero)");
18585a775e6SCorvin Köhne 	dsdt_line("  }");
18685a775e6SCorvin Köhne 	dsdt_line(
18785a775e6SCorvin Köhne 	    "  OperationRegion(TPP1, SystemMemory, Add(0x%8x, Arg0), One)",
18885a775e6SCorvin Köhne 	    TPM_PPI_ADDRESS);
18985a775e6SCorvin Köhne 	dsdt_line("  Field(TPP1, ByteAcc, NoLock, Preserve)");
19085a775e6SCorvin Köhne 	dsdt_line("  {");
19185a775e6SCorvin Köhne 	dsdt_line("    TPPF, 8,");
19285a775e6SCorvin Köhne 	dsdt_line("  }");
19385a775e6SCorvin Köhne 	dsdt_line("  Return(TPPF)");
19485a775e6SCorvin Köhne 	dsdt_line("}");
19585a775e6SCorvin Köhne 	dsdt_line("OperationRegion(TPP2, SystemMemory, 0x%8x, 0x%x)",
19685a775e6SCorvin Köhne 	    TPM_PPI_ADDRESS + 0x100, 0x5A);
19785a775e6SCorvin Köhne 	dsdt_line("Field(TPP2, AnyAcc, NoLock, Preserve)");
19885a775e6SCorvin Köhne 	dsdt_line("{");
19985a775e6SCorvin Köhne 	dsdt_line("  PPIN, 8,");
20085a775e6SCorvin Köhne 	dsdt_line("  PPIP, 32,");
20185a775e6SCorvin Köhne 	dsdt_line("  PPRP, 32,");
20285a775e6SCorvin Köhne 	dsdt_line("  PPRQ, 32,");
20385a775e6SCorvin Köhne 	dsdt_line("  PPRM, 32,");
20485a775e6SCorvin Köhne 	dsdt_line("  LPPR, 32,");
20585a775e6SCorvin Köhne 	dsdt_line("}");
20685a775e6SCorvin Köhne 	/*
20785a775e6SCorvin Köhne 	 * Used for TCG Platform Reset Attack Mitigation
20885a775e6SCorvin Köhne 	 */
20985a775e6SCorvin Köhne 	dsdt_line("OperationRegion(TPP3, SystemMemory, 0x%8x, 1)",
21085a775e6SCorvin Köhne 	    TPM_PPI_ADDRESS + sizeof(struct tpm_ppi_qemu));
21185a775e6SCorvin Köhne 	dsdt_line("Field(TPP3, ByteAcc, NoLock, Preserve)");
21285a775e6SCorvin Köhne 	dsdt_line("{");
21385a775e6SCorvin Köhne 	dsdt_line("  MOVV, 8,");
21485a775e6SCorvin Köhne 	dsdt_line("}");
21585a775e6SCorvin Köhne 
21685a775e6SCorvin Köhne 	return (0);
21785a775e6SCorvin Köhne }
21885a775e6SCorvin Köhne 
21985a775e6SCorvin Köhne static int
tpm_ppi_write_dsdt_dsm(void * sc __unused)22085a775e6SCorvin Köhne tpm_ppi_write_dsdt_dsm(void *sc __unused)
22185a775e6SCorvin Köhne {
22285a775e6SCorvin Köhne 	/*
22385a775e6SCorvin Köhne 	 * Physical Presence Interface
22485a775e6SCorvin Köhne 	 */
22585a775e6SCorvin Köhne 	dsdt_line(
22685a775e6SCorvin Köhne 	    "If(LEqual(Arg0, ToUUID(\"3DDDFAA6-361B-4EB4-A424-8D10089D1653\"))) /* UUID */");
22785a775e6SCorvin Köhne 	dsdt_line("{");
22885a775e6SCorvin Köhne 	/*
22985a775e6SCorvin Köhne 	 * Function 0 - _DSM Query Function
23085a775e6SCorvin Köhne 	 * Arguments:
23185a775e6SCorvin Köhne 	 *   Empty Package
23285a775e6SCorvin Köhne 	 * Return:
23385a775e6SCorvin Köhne 	 *   Buffer - Index field of supported functions
23485a775e6SCorvin Köhne 	 */
23585a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 0)) /* Function */");
23685a775e6SCorvin Köhne 	dsdt_line("  {");
23785a775e6SCorvin Köhne 	dsdt_line("    Return(Buffer(0x02)");
23885a775e6SCorvin Köhne 	dsdt_line("    {");
23985a775e6SCorvin Köhne 	dsdt_line("      0xFF, 0x01");
24085a775e6SCorvin Köhne 	dsdt_line("    })");
24185a775e6SCorvin Köhne 	dsdt_line("  }");
24285a775e6SCorvin Köhne 	/*
24385a775e6SCorvin Köhne 	 * Function 1 - Get Physical Presence Interface Version
24485a775e6SCorvin Köhne 	 * Arguments:
24585a775e6SCorvin Köhne 	 *   Empty Package
24685a775e6SCorvin Köhne 	 * Return:
24785a775e6SCorvin Köhne 	 *   String - Supported Physical Presence Interface revision
24885a775e6SCorvin Köhne 	 */
24985a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 1)) /* Function */");
25085a775e6SCorvin Köhne 	dsdt_line("  {");
25185a775e6SCorvin Köhne 	dsdt_line("    Return(\"1.3\")");
25285a775e6SCorvin Köhne 	dsdt_line("  }");
25385a775e6SCorvin Köhne 	/*
25485a775e6SCorvin Köhne 	 * Function 2 - Submit TPM Operation Request to Pre-OS Environment
25585a775e6SCorvin Köhne 	 * !!!DEPRECATED BUT MANDATORY!!!
25685a775e6SCorvin Köhne 	 * Arguments:
25785a775e6SCorvin Köhne 	 *   Integer - Operation Value of the Request
25885a775e6SCorvin Köhne 	 * Return:
25985a775e6SCorvin Köhne 	 *   Integer - Function Return Code
26085a775e6SCorvin Köhne 	 *     0 - Success
26185a775e6SCorvin Köhne 	 *     1 - Operation Value of the Request Not Supported
26285a775e6SCorvin Köhne 	 *     2 - General Failure
26385a775e6SCorvin Köhne 	 */
26485a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 2)) /* Function */");
26585a775e6SCorvin Köhne 	dsdt_line("  {");
26685a775e6SCorvin Köhne 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
26785a775e6SCorvin Köhne 	dsdt_line("    Store(TPFN(Local0), Local1)");
26885a775e6SCorvin Köhne 	dsdt_line("    If (LEqual(And(Local1, 7), 0))");
26985a775e6SCorvin Köhne 	dsdt_line("    {");
27085a775e6SCorvin Köhne 	dsdt_line("      Return(1)");
27185a775e6SCorvin Köhne 	dsdt_line("    }");
27285a775e6SCorvin Köhne 	dsdt_line("    Store(Local0, PPRQ)");
27385a775e6SCorvin Köhne 	dsdt_line("    Store(0, PPRM)");
27485a775e6SCorvin Köhne 	dsdt_line("    Return(0)");
27585a775e6SCorvin Köhne 	dsdt_line("  }");
27685a775e6SCorvin Köhne 	/*
27785a775e6SCorvin Köhne 	 * Function 3 - Get Pending TPM Operation Request By the OS
27885a775e6SCorvin Köhne 	 * Arguments:
27985a775e6SCorvin Köhne 	 *   Empty Package
28085a775e6SCorvin Köhne 	 * Return:
28185a775e6SCorvin Köhne 	 *   Package
28285a775e6SCorvin Köhne 	 *     Integer 1 - Function Return Code
28385a775e6SCorvin Köhne 	 *       0 - Success
28485a775e6SCorvin Köhne 	 *       1 - General Failure
28585a775e6SCorvin Köhne 	 *     Integer 2 - Pending operation requested by the OS
28685a775e6SCorvin Köhne 	 *       0 - None
28785a775e6SCorvin Köhne 	 *      >0 - Operation Value of the Pending Request
28885a775e6SCorvin Köhne 	 *     Integer 3 - Optional argument to pending operation requested by
28985a775e6SCorvin Köhne 	 *                 the OS
29085a775e6SCorvin Köhne 	 *       0 - None
29185a775e6SCorvin Köhne 	 *      >0 - Argument of the Pending Request
29285a775e6SCorvin Köhne 	 */
29385a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 3)) /* Function */");
29485a775e6SCorvin Köhne 	dsdt_line("  {");
29585a775e6SCorvin Köhne 	dsdt_line("    If(LEqual(Arg1, 1)) /* Revision */");
29685a775e6SCorvin Köhne 	dsdt_line("    {");
29785a775e6SCorvin Köhne 	dsdt_line("      Store(PPRQ, Index(TPM2, 1))");
29885a775e6SCorvin Köhne 	dsdt_line("      Return(TPM2)");
29985a775e6SCorvin Köhne 	dsdt_line("    }");
30085a775e6SCorvin Köhne 	dsdt_line("    If(LEqual(Arg1, 2)) /* Revision */");
30185a775e6SCorvin Köhne 	dsdt_line("    {");
30285a775e6SCorvin Köhne 	dsdt_line("      Store(PPRQ, Index(TPM3, 1))");
30385a775e6SCorvin Köhne 	dsdt_line("      Store(PPRM, Index(TPM3, 2))");
30485a775e6SCorvin Köhne 	dsdt_line("      Return(TPM3)");
30585a775e6SCorvin Köhne 	dsdt_line("    }");
30685a775e6SCorvin Köhne 	dsdt_line("  }");
30785a775e6SCorvin Köhne 	/*
30885a775e6SCorvin Köhne 	 * Function 4 - Get Platform-Specific Action to Transition to Pre-OS
30985a775e6SCorvin Köhne 	 *              Environment
31085a775e6SCorvin Köhne 	 * Arguments:
31185a775e6SCorvin Köhne 	 *   Empty Package
31285a775e6SCorvin Köhne 	 * Return:
31385a775e6SCorvin Köhne 	 *   Integer - Action that the OS should take to transition to the
31485a775e6SCorvin Köhne 	 *             pre-OS environment for execution of a requested operation
31585a775e6SCorvin Köhne 	 *     0 - None
31685a775e6SCorvin Köhne 	 *     1 - Shutdown
31785a775e6SCorvin Köhne 	 *     2 - Reboot
31885a775e6SCorvin Köhne 	 *     3 - OS Vendor-specific
31985a775e6SCorvin Köhne 	 */
32085a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 4)) /* Function */");
32185a775e6SCorvin Köhne 	dsdt_line("  {");
32285a775e6SCorvin Köhne 	dsdt_line("    Return(2)");
32385a775e6SCorvin Köhne 	dsdt_line("  }");
32485a775e6SCorvin Köhne 	/*
32585a775e6SCorvin Köhne 	 * Function 5 - Return TPM Operation Response to OS Environment
32685a775e6SCorvin Köhne 	 * Arguments:
32785a775e6SCorvin Köhne 	 *   Empty Package
32885a775e6SCorvin Köhne 	 * Return:
32985a775e6SCorvin Köhne 	 *   Package
33085a775e6SCorvin Köhne 	 *     Integer 1 - Function Return Code
33185a775e6SCorvin Köhne 	 *       0 - Success
33285a775e6SCorvin Köhne 	 *       1 - General Failure
33385a775e6SCorvin Köhne 	 *     Integer 2 - Most recent operation request
33485a775e6SCorvin Köhne 	 *       0 - None
33585a775e6SCorvin Köhne 	 *      >0 - Operation value of the most recent request
33685a775e6SCorvin Köhne 	 *     Integer 3 - Response to the most recent operation request
33785a775e6SCorvin Köhne 	 *       0 - Success
33885a775e6SCorvin Köhne 	 *       0x00000001..0x000000FF - Corresponding TPM error code
33985a775e6SCorvin Köhne 	 *       0xFFFFFFF0 - User Abort or timeout of dialog
34085a775e6SCorvin Köhne 	 *       0xFFFFFFF1 - firmware failure
34185a775e6SCorvin Köhne 	 */
34285a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 5)) /* Function */");
34385a775e6SCorvin Köhne 	dsdt_line("  {");
34485a775e6SCorvin Köhne 	dsdt_line("    Store(LPPR, Index(TPM3, 1))");
34585a775e6SCorvin Köhne 	dsdt_line("    Store(PPRP, Index(TPM3, 2))");
34685a775e6SCorvin Köhne 	dsdt_line("    Return(TPM3)");
34785a775e6SCorvin Köhne 	dsdt_line("  }");
34885a775e6SCorvin Köhne 	/*
34985a775e6SCorvin Köhne 	 * Function 6 - Submit preferred user language
35085a775e6SCorvin Köhne 	 * !!!DEPRECATED BUT MANDATORY!!!
35185a775e6SCorvin Köhne 	 * Arguments:
35285a775e6SCorvin Köhne 	 *   Package
35385a775e6SCorvin Köhne 	 *     String - Preferred language code
35485a775e6SCorvin Köhne 	 * Return:
35585a775e6SCorvin Köhne 	 *   Integer
35685a775e6SCorvin Köhne 	 *     3 - Not implemented
35785a775e6SCorvin Köhne 	 */
35885a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 6)) /* Function */");
35985a775e6SCorvin Köhne 	dsdt_line("  {");
36085a775e6SCorvin Köhne 	dsdt_line("    Return(3)");
36185a775e6SCorvin Köhne 	dsdt_line("  }");
36285a775e6SCorvin Köhne 	/*
36385a775e6SCorvin Köhne 	 * Function 7 - Submit TPM Operation Request to Pre-OS Environment 2
36485a775e6SCorvin Köhne 	 * Arguments:
36585a775e6SCorvin Köhne 	 *   Package
36685a775e6SCorvin Köhne 	 *     Integer 1 - Operation Value of the Request
36785a775e6SCorvin Köhne 	 *     Integer 2 - Argument for Operation
36885a775e6SCorvin Köhne 	 * Return:
36985a775e6SCorvin Köhne 	 *   Integer - Function Return Code
37085a775e6SCorvin Köhne 	 *     0 - Success
37185a775e6SCorvin Köhne 	 *     1 - Not Implemented
37285a775e6SCorvin Köhne 	 *     2 - General Failure
37385a775e6SCorvin Köhne 	 *     3 - Operation blocked by current firmware settings
37485a775e6SCorvin Köhne 	 */
37585a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 7)) /* Function */");
37685a775e6SCorvin Köhne 	dsdt_line("  {");
37785a775e6SCorvin Köhne 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
37885a775e6SCorvin Köhne 	dsdt_line("    Store(TPFN(Local0), Local1)");
37985a775e6SCorvin Köhne 	dsdt_line("    If (LEqual(And(Local1, 7), 0)) /* Not Implemented */");
38085a775e6SCorvin Köhne 	dsdt_line("    {");
38185a775e6SCorvin Köhne 	dsdt_line("      Return(1)");
38285a775e6SCorvin Köhne 	dsdt_line("    }");
38385a775e6SCorvin Köhne 	dsdt_line("    If (LEqual(And(Local1, 7), 2)) /* Blocked */ ");
38485a775e6SCorvin Köhne 	dsdt_line("    {");
38585a775e6SCorvin Köhne 	dsdt_line("      Return(3)");
38685a775e6SCorvin Köhne 	dsdt_line("    }");
38785a775e6SCorvin Köhne 	dsdt_line("    If(LEqual(Arg1, 1)) /* Revision */");
38885a775e6SCorvin Köhne 	dsdt_line("    {");
38985a775e6SCorvin Köhne 	dsdt_line("      Store(Local0, PPRQ)");
39085a775e6SCorvin Köhne 	dsdt_line("      Store(0, PPRM)");
39185a775e6SCorvin Köhne 	dsdt_line("    }");
39285a775e6SCorvin Köhne 	dsdt_line("    If(LEqual(Arg1, 2)) /* Revision */");
39385a775e6SCorvin Köhne 	dsdt_line("    {");
39485a775e6SCorvin Köhne 	dsdt_line("      Store(Local0, PPRQ)");
39585a775e6SCorvin Köhne 	dsdt_line("      Store(DerefOf(Index(Arg3, 1)), PPRM)");
39685a775e6SCorvin Köhne 	dsdt_line("    }");
39785a775e6SCorvin Köhne 	dsdt_line("    Return(0)");
39885a775e6SCorvin Köhne 	dsdt_line("  }");
39985a775e6SCorvin Köhne 	/*
40085a775e6SCorvin Köhne 	 * Function 8 - Get User Confirmation Status for Operation
40185a775e6SCorvin Köhne 	 * Arguments:
40285a775e6SCorvin Köhne 	 *   Package
40385a775e6SCorvin Köhne 	 *     Integer - Operation Value that may need user confirmation
40485a775e6SCorvin Köhne 	 * Return:
40585a775e6SCorvin Köhne 	 *   Integer - Function Return Code
40685a775e6SCorvin Köhne 	 *     0 - Not implemented
40785a775e6SCorvin Köhne 	 *     1 - Firmware only
40885a775e6SCorvin Köhne 	 *     2 - Blocked for OS by firmware configuration
40985a775e6SCorvin Köhne 	 *     3 - Allowed and physically present user required
41085a775e6SCorvin Köhne 	 *     4 - Allowed and physically present user not required
41185a775e6SCorvin Köhne 	 */
41285a775e6SCorvin Köhne 	dsdt_line("    If(LEqual(Arg2, 8)) /* Function */");
41385a775e6SCorvin Köhne 	dsdt_line("    {");
41485a775e6SCorvin Köhne 	dsdt_line("      Store(DerefOf(Index(Arg3, 0)), Local0)");
41585a775e6SCorvin Köhne 	dsdt_line("      Store(TPFN(Local0), Local1)");
41685a775e6SCorvin Köhne 	dsdt_line("      Return(And(Local1, 7))");
41785a775e6SCorvin Köhne 	dsdt_line("    }");
41885a775e6SCorvin Köhne 	/*
41985a775e6SCorvin Köhne 	 * Unknown function
42085a775e6SCorvin Köhne 	 */
42185a775e6SCorvin Köhne 	dsdt_line("  Return(Buffer(1)");
42285a775e6SCorvin Köhne 	dsdt_line("  {");
42385a775e6SCorvin Köhne 	dsdt_line("    0x00");
42485a775e6SCorvin Köhne 	dsdt_line("  })");
42585a775e6SCorvin Köhne 	dsdt_line("}");
42685a775e6SCorvin Köhne 
42785a775e6SCorvin Köhne 	/*
42885a775e6SCorvin Köhne 	 * TCG Platform Reset Attack Mitigation
42985a775e6SCorvin Köhne 	 */
43085a775e6SCorvin Köhne 	dsdt_line(
43185a775e6SCorvin Köhne 	    "If(LEqual(Arg0, ToUUID(\"376054ED-CC13-4675-901C-4756D7F2D45D\"))) /* UUID */");
43285a775e6SCorvin Köhne 	dsdt_line("{");
43385a775e6SCorvin Köhne 	/*
43485a775e6SCorvin Köhne 	 * Function 0 - _DSM Query Function
43585a775e6SCorvin Köhne 	 * Arguments:
43685a775e6SCorvin Köhne 	 *   Empty Package
43785a775e6SCorvin Köhne 	 * Return:
43885a775e6SCorvin Köhne 	 *   Buffer - Index field of supported functions
43985a775e6SCorvin Köhne 	 */
44085a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 0)) /* Function */");
44185a775e6SCorvin Köhne 	dsdt_line("  {");
44285a775e6SCorvin Köhne 	dsdt_line("    Return(Buffer(1)");
44385a775e6SCorvin Köhne 	dsdt_line("    {");
44485a775e6SCorvin Köhne 	dsdt_line("      0x03");
44585a775e6SCorvin Köhne 	dsdt_line("    })");
44685a775e6SCorvin Köhne 	dsdt_line("  }");
44785a775e6SCorvin Köhne 	/*
44885a775e6SCorvin Köhne 	 * Function 1 - Memory Clear
44985a775e6SCorvin Köhne 	 * Arguments:
45085a775e6SCorvin Köhne 	 *   Package
45185a775e6SCorvin Köhne 	 *     Integer - Operation Value of the Request
45285a775e6SCorvin Köhne 	 * Return:
45385a775e6SCorvin Köhne 	 *   Integer - Function Return Code
45485a775e6SCorvin Köhne 	 *     0 - Success
45585a775e6SCorvin Köhne 	 *     1 - General Failure
45685a775e6SCorvin Köhne 	 */
45785a775e6SCorvin Köhne 	dsdt_line("  If(LEqual(Arg2, 1)) /* Function */");
45885a775e6SCorvin Köhne 	dsdt_line("  {");
45985a775e6SCorvin Köhne 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
46085a775e6SCorvin Köhne 	dsdt_line("    Store(Local0, MOVV)");
46185a775e6SCorvin Köhne 	dsdt_line("    Return(0)");
46285a775e6SCorvin Köhne 	dsdt_line("  }");
46385a775e6SCorvin Köhne 	dsdt_line("}");
46485a775e6SCorvin Köhne 
46585a775e6SCorvin Köhne 	return (0);
46685a775e6SCorvin Köhne }
46785a775e6SCorvin Köhne 
46885a775e6SCorvin Köhne static struct tpm_ppi tpm_ppi_qemu = {
46985a775e6SCorvin Köhne 	.name = TPM_PPI_QEMU_NAME,
47085a775e6SCorvin Köhne 	.init = tpm_ppi_init,
47185a775e6SCorvin Köhne 	.deinit = tpm_ppi_deinit,
47285a775e6SCorvin Köhne 	.write_dsdt_regions = tpm_ppi_write_dsdt_regions,
47385a775e6SCorvin Köhne 	.write_dsdt_dsm = tpm_ppi_write_dsdt_dsm,
47485a775e6SCorvin Köhne };
47585a775e6SCorvin Köhne TPM_PPI_SET(tpm_ppi_qemu);
476