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