xref: /illumos-gate/usr/src/cmd/bhyve/tpm_ppi_qemu.c (revision 32640292339b07090f10ce34d455f98711077343)
1*32640292SAndy Fiddaman /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
3*32640292SAndy Fiddaman  *
4*32640292SAndy Fiddaman  * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
5*32640292SAndy Fiddaman  * Author: Corvin Köhne <c.koehne@beckhoff.com>
6*32640292SAndy Fiddaman  */
7*32640292SAndy Fiddaman 
8*32640292SAndy Fiddaman #include <sys/cdefs.h>
9*32640292SAndy Fiddaman #include <sys/types.h>
10*32640292SAndy Fiddaman #include <sys/param.h>
11*32640292SAndy Fiddaman #include <sys/endian.h>
12*32640292SAndy Fiddaman #include <sys/linker_set.h>
13*32640292SAndy Fiddaman 
14*32640292SAndy Fiddaman #include <machine/vmm.h>
15*32640292SAndy Fiddaman 
16*32640292SAndy Fiddaman #include <assert.h>
17*32640292SAndy Fiddaman #include <err.h>
18*32640292SAndy Fiddaman #include <errno.h>
19*32640292SAndy Fiddaman #include <vmmapi.h>
20*32640292SAndy Fiddaman 
21*32640292SAndy Fiddaman #include "acpi.h"
22*32640292SAndy Fiddaman #include "acpi_device.h"
23*32640292SAndy Fiddaman #include "config.h"
24*32640292SAndy Fiddaman #include "mem.h"
25*32640292SAndy Fiddaman #include "qemu_fwcfg.h"
26*32640292SAndy Fiddaman #include "tpm_ppi.h"
27*32640292SAndy Fiddaman 
28*32640292SAndy Fiddaman #define TPM_PPI_ADDRESS 0xFED45000
29*32640292SAndy Fiddaman #define TPM_PPI_SIZE 0x1000
30*32640292SAndy Fiddaman 
31*32640292SAndy Fiddaman #define TPM_PPI_FWCFG_FILE "etc/tpm/config"
32*32640292SAndy Fiddaman 
33*32640292SAndy Fiddaman #define TPM_PPI_QEMU_NAME "qemu"
34*32640292SAndy Fiddaman 
35*32640292SAndy Fiddaman struct tpm_ppi_qemu {
36*32640292SAndy Fiddaman 	uint8_t func[256];	    // FUNC
37*32640292SAndy Fiddaman 	uint8_t in;		    // PPIN
38*32640292SAndy Fiddaman 	uint32_t ip;		    // PPIP
39*32640292SAndy Fiddaman 	uint32_t response;	    // PPRP
40*32640292SAndy Fiddaman 	uint32_t request;	    // PPRQ
41*32640292SAndy Fiddaman 	uint32_t request_parameter; // PPRM
42*32640292SAndy Fiddaman 	uint32_t last_request;	    // LPPR
43*32640292SAndy Fiddaman 	uint32_t func_ret;	    // FRET
44*32640292SAndy Fiddaman 	uint8_t _reserved1[0x40];   // RES1
45*32640292SAndy Fiddaman 	uint8_t next_step;	    // next_step
46*32640292SAndy Fiddaman } __packed;
47*32640292SAndy Fiddaman static_assert(sizeof(struct tpm_ppi_qemu) <= TPM_PPI_SIZE,
48*32640292SAndy Fiddaman     "Wrong size of tpm_ppi_qemu");
49*32640292SAndy Fiddaman 
50*32640292SAndy Fiddaman struct tpm_ppi_fwcfg {
51*32640292SAndy Fiddaman 	uint32_t ppi_address;
52*32640292SAndy Fiddaman 	uint8_t tpm_version;
53*32640292SAndy Fiddaman 	uint8_t ppi_version;
54*32640292SAndy Fiddaman } __packed;
55*32640292SAndy Fiddaman 
56*32640292SAndy Fiddaman 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)57*32640292SAndy Fiddaman tpm_ppi_mem_handler(struct vcpu *const vcpu __unused, const int dir,
58*32640292SAndy Fiddaman     const uint64_t addr, const int size, uint64_t *const val, void *const arg1,
59*32640292SAndy Fiddaman     const long arg2 __unused)
60*32640292SAndy Fiddaman {
61*32640292SAndy Fiddaman 	struct tpm_ppi_qemu *ppi;
62*32640292SAndy Fiddaman 	uint8_t *ptr;
63*32640292SAndy Fiddaman 	uint64_t off;
64*32640292SAndy Fiddaman 
65*32640292SAndy Fiddaman 	if ((addr & (size - 1)) != 0) {
66*32640292SAndy Fiddaman 		warnx("%s: unaligned %s access @ %16lx [size = %x]", __func__,
67*32640292SAndy Fiddaman 		    (dir == MEM_F_READ) ? "read" : "write", addr, size);
68*32640292SAndy Fiddaman 	}
69*32640292SAndy Fiddaman 
70*32640292SAndy Fiddaman 	ppi = arg1;
71*32640292SAndy Fiddaman 
72*32640292SAndy Fiddaman 	off = addr - TPM_PPI_ADDRESS;
73*32640292SAndy Fiddaman 	ptr = (uint8_t *)ppi + off;
74*32640292SAndy Fiddaman 
75*32640292SAndy Fiddaman 	if (off > TPM_PPI_SIZE || off + size > TPM_PPI_SIZE) {
76*32640292SAndy Fiddaman 		return (EINVAL);
77*32640292SAndy Fiddaman 	}
78*32640292SAndy Fiddaman 
79*32640292SAndy Fiddaman 	assert(size == 1 || size == 2 || size == 4 || size == 8);
80*32640292SAndy Fiddaman 	if (dir == MEM_F_READ) {
81*32640292SAndy Fiddaman 		memcpy(val, ptr, size);
82*32640292SAndy Fiddaman 	} else {
83*32640292SAndy Fiddaman 		memcpy(ptr, val, size);
84*32640292SAndy Fiddaman 	}
85*32640292SAndy Fiddaman 
86*32640292SAndy Fiddaman 	return (0);
87*32640292SAndy Fiddaman }
88*32640292SAndy Fiddaman 
89*32640292SAndy Fiddaman static struct mem_range ppi_mmio = {
90*32640292SAndy Fiddaman 	.name = "ppi-mmio",
91*32640292SAndy Fiddaman 	.base = TPM_PPI_ADDRESS,
92*32640292SAndy Fiddaman 	.size = TPM_PPI_SIZE,
93*32640292SAndy Fiddaman 	.flags = MEM_F_RW,
94*32640292SAndy Fiddaman 	.handler = tpm_ppi_mem_handler,
95*32640292SAndy Fiddaman };
96*32640292SAndy Fiddaman 
97*32640292SAndy Fiddaman static int
tpm_ppi_init(void ** sc)98*32640292SAndy Fiddaman tpm_ppi_init(void **sc)
99*32640292SAndy Fiddaman {
100*32640292SAndy Fiddaman 	struct tpm_ppi_qemu *ppi = NULL;
101*32640292SAndy Fiddaman 	struct tpm_ppi_fwcfg *fwcfg = NULL;
102*32640292SAndy Fiddaman 	int error;
103*32640292SAndy Fiddaman 
104*32640292SAndy Fiddaman 	ppi = calloc(1, sizeof(*ppi));
105*32640292SAndy Fiddaman 	if (ppi == NULL) {
106*32640292SAndy Fiddaman 		warnx("%s: failed to allocate acpi region for ppi", __func__);
107*32640292SAndy Fiddaman 		error = ENOMEM;
108*32640292SAndy Fiddaman 		goto err_out;
109*32640292SAndy Fiddaman 	}
110*32640292SAndy Fiddaman 
111*32640292SAndy Fiddaman 	fwcfg = calloc(1, sizeof(struct tpm_ppi_fwcfg));
112*32640292SAndy Fiddaman 	if (fwcfg == NULL) {
113*32640292SAndy Fiddaman 		warnx("%s: failed to allocate fwcfg item", __func__);
114*32640292SAndy Fiddaman 		error = ENOMEM;
115*32640292SAndy Fiddaman 		goto err_out;
116*32640292SAndy Fiddaman 	}
117*32640292SAndy Fiddaman 
118*32640292SAndy Fiddaman 	fwcfg->ppi_address = htole32(TPM_PPI_ADDRESS);
119*32640292SAndy Fiddaman 	fwcfg->tpm_version = 2;
120*32640292SAndy Fiddaman 	fwcfg->ppi_version = 1;
121*32640292SAndy Fiddaman 
122*32640292SAndy Fiddaman 	error = qemu_fwcfg_add_file(TPM_PPI_FWCFG_FILE,
123*32640292SAndy Fiddaman 	    sizeof(struct tpm_ppi_fwcfg), fwcfg);
124*32640292SAndy Fiddaman 	if (error) {
125*32640292SAndy Fiddaman 		warnx("%s: failed to add fwcfg file", __func__);
126*32640292SAndy Fiddaman 		goto err_out;
127*32640292SAndy Fiddaman 	}
128*32640292SAndy Fiddaman 
129*32640292SAndy Fiddaman 	/*
130*32640292SAndy Fiddaman 	 * We would just need to create some guest memory for the PPI region.
131*32640292SAndy Fiddaman 	 * Sadly, bhyve has a strange memory interface. We can't just add more
132*32640292SAndy Fiddaman 	 * memory to the VM. So, create a trap instead which reads and writes to
133*32640292SAndy Fiddaman 	 * the ppi region. It's very slow but ppi shouldn't be used frequently.
134*32640292SAndy Fiddaman 	 */
135*32640292SAndy Fiddaman 	ppi_mmio.arg1 = ppi;
136*32640292SAndy Fiddaman 	error = register_mem(&ppi_mmio);
137*32640292SAndy Fiddaman 	if (error) {
138*32640292SAndy Fiddaman 		warnx("%s: failed to create trap for ppi accesses", __func__);
139*32640292SAndy Fiddaman 		goto err_out;
140*32640292SAndy Fiddaman 	}
141*32640292SAndy Fiddaman 
142*32640292SAndy Fiddaman 	*sc = ppi;
143*32640292SAndy Fiddaman 
144*32640292SAndy Fiddaman 	return (0);
145*32640292SAndy Fiddaman 
146*32640292SAndy Fiddaman err_out:
147*32640292SAndy Fiddaman 	free(fwcfg);
148*32640292SAndy Fiddaman 	free(ppi);
149*32640292SAndy Fiddaman 
150*32640292SAndy Fiddaman 	return (error);
151*32640292SAndy Fiddaman }
152*32640292SAndy Fiddaman 
153*32640292SAndy Fiddaman static void
tpm_ppi_deinit(void * sc)154*32640292SAndy Fiddaman tpm_ppi_deinit(void *sc)
155*32640292SAndy Fiddaman {
156*32640292SAndy Fiddaman 	struct tpm_ppi_qemu *ppi;
157*32640292SAndy Fiddaman 	int error;
158*32640292SAndy Fiddaman 
159*32640292SAndy Fiddaman 	if (sc == NULL)
160*32640292SAndy Fiddaman 		return;
161*32640292SAndy Fiddaman 
162*32640292SAndy Fiddaman 	ppi = sc;
163*32640292SAndy Fiddaman 
164*32640292SAndy Fiddaman 	error = unregister_mem(&ppi_mmio);
165*32640292SAndy Fiddaman 	assert(error == 0);
166*32640292SAndy Fiddaman 
167*32640292SAndy Fiddaman 	free(ppi);
168*32640292SAndy Fiddaman }
169*32640292SAndy Fiddaman 
170*32640292SAndy Fiddaman static int
tpm_ppi_write_dsdt_regions(void * sc __unused)171*32640292SAndy Fiddaman tpm_ppi_write_dsdt_regions(void *sc __unused)
172*32640292SAndy Fiddaman {
173*32640292SAndy Fiddaman 	/*
174*32640292SAndy Fiddaman 	 * struct tpm_ppi_qemu
175*32640292SAndy Fiddaman 	 */
176*32640292SAndy Fiddaman 	/*
177*32640292SAndy Fiddaman 	 * According to qemu the Windows ACPI parser has a bug that DerefOf is
178*32640292SAndy Fiddaman 	 * broken for SYSTEM_MEMORY. Due to that bug, qemu uses a dynamic
179*32640292SAndy Fiddaman 	 * operation region inside a method.
180*32640292SAndy Fiddaman 	 */
181*32640292SAndy Fiddaman 	dsdt_line("Method(TPFN, 1, Serialized)");
182*32640292SAndy Fiddaman 	dsdt_line("{");
183*32640292SAndy Fiddaman 	dsdt_line("  If(LGreaterEqual(Arg0, 0x100))");
184*32640292SAndy Fiddaman 	dsdt_line("  {");
185*32640292SAndy Fiddaman 	dsdt_line("    Return(Zero)");
186*32640292SAndy Fiddaman 	dsdt_line("  }");
187*32640292SAndy Fiddaman 	dsdt_line(
188*32640292SAndy Fiddaman 	    "  OperationRegion(TPP1, SystemMemory, Add(0x%8x, Arg0), One)",
189*32640292SAndy Fiddaman 	    TPM_PPI_ADDRESS);
190*32640292SAndy Fiddaman 	dsdt_line("  Field(TPP1, ByteAcc, NoLock, Preserve)");
191*32640292SAndy Fiddaman 	dsdt_line("  {");
192*32640292SAndy Fiddaman 	dsdt_line("    TPPF, 8,");
193*32640292SAndy Fiddaman 	dsdt_line("  }");
194*32640292SAndy Fiddaman 	dsdt_line("  Return(TPPF)");
195*32640292SAndy Fiddaman 	dsdt_line("}");
196*32640292SAndy Fiddaman 	dsdt_line("OperationRegion(TPP2, SystemMemory, 0x%8x, 0x%x)",
197*32640292SAndy Fiddaman 	    TPM_PPI_ADDRESS + 0x100, 0x5A);
198*32640292SAndy Fiddaman 	dsdt_line("Field(TPP2, AnyAcc, NoLock, Preserve)");
199*32640292SAndy Fiddaman 	dsdt_line("{");
200*32640292SAndy Fiddaman 	dsdt_line("  PPIN, 8,");
201*32640292SAndy Fiddaman 	dsdt_line("  PPIP, 32,");
202*32640292SAndy Fiddaman 	dsdt_line("  PPRP, 32,");
203*32640292SAndy Fiddaman 	dsdt_line("  PPRQ, 32,");
204*32640292SAndy Fiddaman 	dsdt_line("  PPRM, 32,");
205*32640292SAndy Fiddaman 	dsdt_line("  LPPR, 32,");
206*32640292SAndy Fiddaman 	dsdt_line("}");
207*32640292SAndy Fiddaman 	/*
208*32640292SAndy Fiddaman 	 * Used for TCG Platform Reset Attack Mitigation
209*32640292SAndy Fiddaman 	 */
210*32640292SAndy Fiddaman 	dsdt_line("OperationRegion(TPP3, SystemMemory, 0x%8x, 1)",
211*32640292SAndy Fiddaman 	    TPM_PPI_ADDRESS + sizeof(struct tpm_ppi_qemu));
212*32640292SAndy Fiddaman 	dsdt_line("Field(TPP3, ByteAcc, NoLock, Preserve)");
213*32640292SAndy Fiddaman 	dsdt_line("{");
214*32640292SAndy Fiddaman 	dsdt_line("  MOVV, 8,");
215*32640292SAndy Fiddaman 	dsdt_line("}");
216*32640292SAndy Fiddaman 
217*32640292SAndy Fiddaman 	return (0);
218*32640292SAndy Fiddaman }
219*32640292SAndy Fiddaman 
220*32640292SAndy Fiddaman static int
tpm_ppi_write_dsdt_dsm(void * sc __unused)221*32640292SAndy Fiddaman tpm_ppi_write_dsdt_dsm(void *sc __unused)
222*32640292SAndy Fiddaman {
223*32640292SAndy Fiddaman 	/*
224*32640292SAndy Fiddaman 	 * Physical Presence Interface
225*32640292SAndy Fiddaman 	 */
226*32640292SAndy Fiddaman 	dsdt_line(
227*32640292SAndy Fiddaman 	    "If(LEqual(Arg0, ToUUID(\"3DDDFAA6-361B-4EB4-A424-8D10089D1653\"))) /* UUID */");
228*32640292SAndy Fiddaman 	dsdt_line("{");
229*32640292SAndy Fiddaman 	/*
230*32640292SAndy Fiddaman 	 * Function 0 - _DSM Query Function
231*32640292SAndy Fiddaman 	 * Arguments:
232*32640292SAndy Fiddaman 	 *   Empty Package
233*32640292SAndy Fiddaman 	 * Return:
234*32640292SAndy Fiddaman 	 *   Buffer - Index field of supported functions
235*32640292SAndy Fiddaman 	 */
236*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 0)) /* Function */");
237*32640292SAndy Fiddaman 	dsdt_line("  {");
238*32640292SAndy Fiddaman 	dsdt_line("    Return(Buffer(0x02)");
239*32640292SAndy Fiddaman 	dsdt_line("    {");
240*32640292SAndy Fiddaman 	dsdt_line("      0xFF, 0x01");
241*32640292SAndy Fiddaman 	dsdt_line("    })");
242*32640292SAndy Fiddaman 	dsdt_line("  }");
243*32640292SAndy Fiddaman 	/*
244*32640292SAndy Fiddaman 	 * Function 1 - Get Physical Presence Interface Version
245*32640292SAndy Fiddaman 	 * Arguments:
246*32640292SAndy Fiddaman 	 *   Empty Package
247*32640292SAndy Fiddaman 	 * Return:
248*32640292SAndy Fiddaman 	 *   String - Supported Physical Presence Interface revision
249*32640292SAndy Fiddaman 	 */
250*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 1)) /* Function */");
251*32640292SAndy Fiddaman 	dsdt_line("  {");
252*32640292SAndy Fiddaman 	dsdt_line("    Return(\"1.3\")");
253*32640292SAndy Fiddaman 	dsdt_line("  }");
254*32640292SAndy Fiddaman 	/*
255*32640292SAndy Fiddaman 	 * Function 2 - Submit TPM Operation Request to Pre-OS Environment
256*32640292SAndy Fiddaman 	 * !!!DEPRECATED BUT MANDATORY!!!
257*32640292SAndy Fiddaman 	 * Arguments:
258*32640292SAndy Fiddaman 	 *   Integer - Operation Value of the Request
259*32640292SAndy Fiddaman 	 * Return:
260*32640292SAndy Fiddaman 	 *   Integer - Function Return Code
261*32640292SAndy Fiddaman 	 *     0 - Success
262*32640292SAndy Fiddaman 	 *     1 - Operation Value of the Request Not Supported
263*32640292SAndy Fiddaman 	 *     2 - General Failure
264*32640292SAndy Fiddaman 	 */
265*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 2)) /* Function */");
266*32640292SAndy Fiddaman 	dsdt_line("  {");
267*32640292SAndy Fiddaman 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
268*32640292SAndy Fiddaman 	dsdt_line("    Store(TPFN(Local0), Local1)");
269*32640292SAndy Fiddaman 	dsdt_line("    If (LEqual(And(Local1, 7), 0))");
270*32640292SAndy Fiddaman 	dsdt_line("    {");
271*32640292SAndy Fiddaman 	dsdt_line("      Return(1)");
272*32640292SAndy Fiddaman 	dsdt_line("    }");
273*32640292SAndy Fiddaman 	dsdt_line("    Store(Local0, PPRQ)");
274*32640292SAndy Fiddaman 	dsdt_line("    Store(0, PPRM)");
275*32640292SAndy Fiddaman 	dsdt_line("    Return(0)");
276*32640292SAndy Fiddaman 	dsdt_line("  }");
277*32640292SAndy Fiddaman 	/*
278*32640292SAndy Fiddaman 	 * Function 3 - Get Pending TPM Operation Request By the OS
279*32640292SAndy Fiddaman 	 * Arguments:
280*32640292SAndy Fiddaman 	 *   Empty Package
281*32640292SAndy Fiddaman 	 * Return:
282*32640292SAndy Fiddaman 	 *   Package
283*32640292SAndy Fiddaman 	 *     Integer 1 - Function Return Code
284*32640292SAndy Fiddaman 	 *       0 - Success
285*32640292SAndy Fiddaman 	 *       1 - General Failure
286*32640292SAndy Fiddaman 	 *     Integer 2 - Pending operation requested by the OS
287*32640292SAndy Fiddaman 	 *       0 - None
288*32640292SAndy Fiddaman 	 *      >0 - Operation Value of the Pending Request
289*32640292SAndy Fiddaman 	 *     Integer 3 - Optional argument to pending operation requested by
290*32640292SAndy Fiddaman 	 *                 the OS
291*32640292SAndy Fiddaman 	 *       0 - None
292*32640292SAndy Fiddaman 	 *      >0 - Argument of the Pending Request
293*32640292SAndy Fiddaman 	 */
294*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 3)) /* Function */");
295*32640292SAndy Fiddaman 	dsdt_line("  {");
296*32640292SAndy Fiddaman 	dsdt_line("    If(LEqual(Arg1, 1)) /* Revision */");
297*32640292SAndy Fiddaman 	dsdt_line("    {");
298*32640292SAndy Fiddaman 	dsdt_line("      Store(PPRQ, Index(TPM2, 1))");
299*32640292SAndy Fiddaman 	dsdt_line("      Return(TPM2)");
300*32640292SAndy Fiddaman 	dsdt_line("    }");
301*32640292SAndy Fiddaman 	dsdt_line("    If(LEqual(Arg1, 2)) /* Revision */");
302*32640292SAndy Fiddaman 	dsdt_line("    {");
303*32640292SAndy Fiddaman 	dsdt_line("      Store(PPRQ, Index(TPM3, 1))");
304*32640292SAndy Fiddaman 	dsdt_line("      Store(PPRM, Index(TPM3, 2))");
305*32640292SAndy Fiddaman 	dsdt_line("      Return(TPM3)");
306*32640292SAndy Fiddaman 	dsdt_line("    }");
307*32640292SAndy Fiddaman 	dsdt_line("  }");
308*32640292SAndy Fiddaman 	/*
309*32640292SAndy Fiddaman 	 * Function 4 - Get Platform-Specific Action to Transition to Pre-OS
310*32640292SAndy Fiddaman 	 *              Environment
311*32640292SAndy Fiddaman 	 * Arguments:
312*32640292SAndy Fiddaman 	 *   Empty Package
313*32640292SAndy Fiddaman 	 * Return:
314*32640292SAndy Fiddaman 	 *   Integer - Action that the OS should take to transition to the
315*32640292SAndy Fiddaman 	 *             pre-OS environment for execution of a requested operation
316*32640292SAndy Fiddaman 	 *     0 - None
317*32640292SAndy Fiddaman 	 *     1 - Shutdown
318*32640292SAndy Fiddaman 	 *     2 - Reboot
319*32640292SAndy Fiddaman 	 *     3 - OS Vendor-specific
320*32640292SAndy Fiddaman 	 */
321*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 4)) /* Function */");
322*32640292SAndy Fiddaman 	dsdt_line("  {");
323*32640292SAndy Fiddaman 	dsdt_line("    Return(2)");
324*32640292SAndy Fiddaman 	dsdt_line("  }");
325*32640292SAndy Fiddaman 	/*
326*32640292SAndy Fiddaman 	 * Function 5 - Return TPM Operation Response to OS Environment
327*32640292SAndy Fiddaman 	 * Arguments:
328*32640292SAndy Fiddaman 	 *   Empty Package
329*32640292SAndy Fiddaman 	 * Return:
330*32640292SAndy Fiddaman 	 *   Package
331*32640292SAndy Fiddaman 	 *     Integer 1 - Function Return Code
332*32640292SAndy Fiddaman 	 *       0 - Success
333*32640292SAndy Fiddaman 	 *       1 - General Failure
334*32640292SAndy Fiddaman 	 *     Integer 2 - Most recent operation request
335*32640292SAndy Fiddaman 	 *       0 - None
336*32640292SAndy Fiddaman 	 *      >0 - Operation value of the most recent request
337*32640292SAndy Fiddaman 	 *     Integer 3 - Response to the most recent operation request
338*32640292SAndy Fiddaman 	 *       0 - Success
339*32640292SAndy Fiddaman 	 *       0x00000001..0x000000FF - Corresponding TPM error code
340*32640292SAndy Fiddaman 	 *       0xFFFFFFF0 - User Abort or timeout of dialog
341*32640292SAndy Fiddaman 	 *       0xFFFFFFF1 - firmware failure
342*32640292SAndy Fiddaman 	 */
343*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 5)) /* Function */");
344*32640292SAndy Fiddaman 	dsdt_line("  {");
345*32640292SAndy Fiddaman 	dsdt_line("    Store(LPPR, Index(TPM3, 1))");
346*32640292SAndy Fiddaman 	dsdt_line("    Store(PPRP, Index(TPM3, 2))");
347*32640292SAndy Fiddaman 	dsdt_line("    Return(TPM3)");
348*32640292SAndy Fiddaman 	dsdt_line("  }");
349*32640292SAndy Fiddaman 	/*
350*32640292SAndy Fiddaman 	 * Function 6 - Submit preferred user language
351*32640292SAndy Fiddaman 	 * !!!DEPRECATED BUT MANDATORY!!!
352*32640292SAndy Fiddaman 	 * Arguments:
353*32640292SAndy Fiddaman 	 *   Package
354*32640292SAndy Fiddaman 	 *     String - Preferred language code
355*32640292SAndy Fiddaman 	 * Return:
356*32640292SAndy Fiddaman 	 *   Integer
357*32640292SAndy Fiddaman 	 *     3 - Not implemented
358*32640292SAndy Fiddaman 	 */
359*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 6)) /* Function */");
360*32640292SAndy Fiddaman 	dsdt_line("  {");
361*32640292SAndy Fiddaman 	dsdt_line("    Return(3)");
362*32640292SAndy Fiddaman 	dsdt_line("  }");
363*32640292SAndy Fiddaman 	/*
364*32640292SAndy Fiddaman 	 * Function 7 - Submit TPM Operation Request to Pre-OS Environment 2
365*32640292SAndy Fiddaman 	 * Arguments:
366*32640292SAndy Fiddaman 	 *   Package
367*32640292SAndy Fiddaman 	 *     Integer 1 - Operation Value of the Request
368*32640292SAndy Fiddaman 	 *     Integer 2 - Argument for Operation
369*32640292SAndy Fiddaman 	 * Return:
370*32640292SAndy Fiddaman 	 *   Integer - Function Return Code
371*32640292SAndy Fiddaman 	 *     0 - Success
372*32640292SAndy Fiddaman 	 *     1 - Not Implemented
373*32640292SAndy Fiddaman 	 *     2 - General Failure
374*32640292SAndy Fiddaman 	 *     3 - Operation blocked by current firmware settings
375*32640292SAndy Fiddaman 	 */
376*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 7)) /* Function */");
377*32640292SAndy Fiddaman 	dsdt_line("  {");
378*32640292SAndy Fiddaman 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
379*32640292SAndy Fiddaman 	dsdt_line("    Store(TPFN(Local0), Local1)");
380*32640292SAndy Fiddaman 	dsdt_line("    If (LEqual(And(Local1, 7), 0)) /* Not Implemented */");
381*32640292SAndy Fiddaman 	dsdt_line("    {");
382*32640292SAndy Fiddaman 	dsdt_line("      Return(1)");
383*32640292SAndy Fiddaman 	dsdt_line("    }");
384*32640292SAndy Fiddaman 	dsdt_line("    If (LEqual(And(Local1, 7), 2)) /* Blocked */ ");
385*32640292SAndy Fiddaman 	dsdt_line("    {");
386*32640292SAndy Fiddaman 	dsdt_line("      Return(3)");
387*32640292SAndy Fiddaman 	dsdt_line("    }");
388*32640292SAndy Fiddaman 	dsdt_line("    If(LEqual(Arg1, 1)) /* Revision */");
389*32640292SAndy Fiddaman 	dsdt_line("    {");
390*32640292SAndy Fiddaman 	dsdt_line("      Store(Local0, PPRQ)");
391*32640292SAndy Fiddaman 	dsdt_line("      Store(0, PPRM)");
392*32640292SAndy Fiddaman 	dsdt_line("    }");
393*32640292SAndy Fiddaman 	dsdt_line("    If(LEqual(Arg1, 2)) /* Revision */");
394*32640292SAndy Fiddaman 	dsdt_line("    {");
395*32640292SAndy Fiddaman 	dsdt_line("      Store(Local0, PPRQ)");
396*32640292SAndy Fiddaman 	dsdt_line("      Store(DerefOf(Index(Arg3, 1)), PPRM)");
397*32640292SAndy Fiddaman 	dsdt_line("    }");
398*32640292SAndy Fiddaman 	dsdt_line("    Return(0)");
399*32640292SAndy Fiddaman 	dsdt_line("  }");
400*32640292SAndy Fiddaman 	/*
401*32640292SAndy Fiddaman 	 * Function 8 - Get User Confirmation Status for Operation
402*32640292SAndy Fiddaman 	 * Arguments:
403*32640292SAndy Fiddaman 	 *   Package
404*32640292SAndy Fiddaman 	 *     Integer - Operation Value that may need user confirmation
405*32640292SAndy Fiddaman 	 * Return:
406*32640292SAndy Fiddaman 	 *   Integer - Function Return Code
407*32640292SAndy Fiddaman 	 *     0 - Not implemented
408*32640292SAndy Fiddaman 	 *     1 - Firmware only
409*32640292SAndy Fiddaman 	 *     2 - Blocked for OS by firmware configuration
410*32640292SAndy Fiddaman 	 *     3 - Allowed and physically present user required
411*32640292SAndy Fiddaman 	 *     4 - Allowed and physically present user not required
412*32640292SAndy Fiddaman 	 */
413*32640292SAndy Fiddaman 	dsdt_line("    If(LEqual(Arg2, 8)) /* Function */");
414*32640292SAndy Fiddaman 	dsdt_line("    {");
415*32640292SAndy Fiddaman 	dsdt_line("      Store(DerefOf(Index(Arg3, 0)), Local0)");
416*32640292SAndy Fiddaman 	dsdt_line("      Store(TPFN(Local0), Local1)");
417*32640292SAndy Fiddaman 	dsdt_line("      Return(And(Local1, 7))");
418*32640292SAndy Fiddaman 	dsdt_line("    }");
419*32640292SAndy Fiddaman 	/*
420*32640292SAndy Fiddaman 	 * Unknown function
421*32640292SAndy Fiddaman 	 */
422*32640292SAndy Fiddaman 	dsdt_line("  Return(Buffer(1)");
423*32640292SAndy Fiddaman 	dsdt_line("  {");
424*32640292SAndy Fiddaman 	dsdt_line("    0x00");
425*32640292SAndy Fiddaman 	dsdt_line("  })");
426*32640292SAndy Fiddaman 	dsdt_line("}");
427*32640292SAndy Fiddaman 
428*32640292SAndy Fiddaman 	/*
429*32640292SAndy Fiddaman 	 * TCG Platform Reset Attack Mitigation
430*32640292SAndy Fiddaman 	 */
431*32640292SAndy Fiddaman 	dsdt_line(
432*32640292SAndy Fiddaman 	    "If(LEqual(Arg0, ToUUID(\"376054ED-CC13-4675-901C-4756D7F2D45D\"))) /* UUID */");
433*32640292SAndy Fiddaman 	dsdt_line("{");
434*32640292SAndy Fiddaman 	/*
435*32640292SAndy Fiddaman 	 * Function 0 - _DSM Query Function
436*32640292SAndy Fiddaman 	 * Arguments:
437*32640292SAndy Fiddaman 	 *   Empty Package
438*32640292SAndy Fiddaman 	 * Return:
439*32640292SAndy Fiddaman 	 *   Buffer - Index field of supported functions
440*32640292SAndy Fiddaman 	 */
441*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 0)) /* Function */");
442*32640292SAndy Fiddaman 	dsdt_line("  {");
443*32640292SAndy Fiddaman 	dsdt_line("    Return(Buffer(1)");
444*32640292SAndy Fiddaman 	dsdt_line("    {");
445*32640292SAndy Fiddaman 	dsdt_line("      0x03");
446*32640292SAndy Fiddaman 	dsdt_line("    })");
447*32640292SAndy Fiddaman 	dsdt_line("  }");
448*32640292SAndy Fiddaman 	/*
449*32640292SAndy Fiddaman 	 * Function 1 - Memory Clear
450*32640292SAndy Fiddaman 	 * Arguments:
451*32640292SAndy Fiddaman 	 *   Package
452*32640292SAndy Fiddaman 	 *     Integer - Operation Value of the Request
453*32640292SAndy Fiddaman 	 * Return:
454*32640292SAndy Fiddaman 	 *   Integer - Function Return Code
455*32640292SAndy Fiddaman 	 *     0 - Success
456*32640292SAndy Fiddaman 	 *     1 - General Failure
457*32640292SAndy Fiddaman 	 */
458*32640292SAndy Fiddaman 	dsdt_line("  If(LEqual(Arg2, 1)) /* Function */");
459*32640292SAndy Fiddaman 	dsdt_line("  {");
460*32640292SAndy Fiddaman 	dsdt_line("    Store(DerefOf(Index(Arg3, 0)), Local0)");
461*32640292SAndy Fiddaman 	dsdt_line("    Store(Local0, MOVV)");
462*32640292SAndy Fiddaman 	dsdt_line("    Return(0)");
463*32640292SAndy Fiddaman 	dsdt_line("  }");
464*32640292SAndy Fiddaman 	dsdt_line("}");
465*32640292SAndy Fiddaman 
466*32640292SAndy Fiddaman 	return (0);
467*32640292SAndy Fiddaman }
468*32640292SAndy Fiddaman 
469*32640292SAndy Fiddaman static struct tpm_ppi tpm_ppi_qemu = {
470*32640292SAndy Fiddaman 	.name = TPM_PPI_QEMU_NAME,
471*32640292SAndy Fiddaman 	.init = tpm_ppi_init,
472*32640292SAndy Fiddaman 	.deinit = tpm_ppi_deinit,
473*32640292SAndy Fiddaman 	.write_dsdt_regions = tpm_ppi_write_dsdt_regions,
474*32640292SAndy Fiddaman 	.write_dsdt_dsm = tpm_ppi_write_dsdt_dsm,
475*32640292SAndy Fiddaman };
476*32640292SAndy Fiddaman TPM_PPI_SET(tpm_ppi_qemu);
477