xref: /qemu/hw/acpi/tpm.c (revision b355f08a)
1 /* Support for generating ACPI TPM tables
2  *
3  * Copyright (C) 2018 IBM, Corp.
4  * Copyright (C) 2018 Red Hat Inc
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15 
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
21 #include "hw/acpi/tpm.h"
22 
23 void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)
24 {
25     Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *func_mask,
26         *not_implemented, *pak, *tpm2, *tpm3, *pprm, *pprq, *zero, *one;
27 
28     if (!object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) {
29         return;
30     }
31 
32     zero = aml_int(0);
33     one = aml_int(1);
34     func_mask = aml_int(TPM_PPI_FUNC_MASK);
35     not_implemented = aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED);
36 
37     /*
38      * TPP2 is for the registers that ACPI code used to pass
39      * the PPI code and parameter (PPRQ, PPRM) to the firmware.
40      */
41     aml_append(dev,
42                aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
43                                     aml_int(TPM_PPI_ADDR_BASE + 0x100),
44                                     0x5A));
45     field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
46     aml_append(field, aml_named_field("PPIN", 8));
47     aml_append(field, aml_named_field("PPIP", 32));
48     aml_append(field, aml_named_field("PPRP", 32));
49     aml_append(field, aml_named_field("PPRQ", 32));
50     aml_append(field, aml_named_field("PPRM", 32));
51     aml_append(field, aml_named_field("LPPR", 32));
52     aml_append(dev, field);
53     pprq = aml_name("PPRQ");
54     pprm = aml_name("PPRM");
55 
56     aml_append(dev,
57                aml_operation_region(
58                    "TPP3", AML_SYSTEM_MEMORY,
59                    aml_int(TPM_PPI_ADDR_BASE +
60                            0x15a /* movv, docs/specs/tpm.rst */),
61                            0x1));
62     field = aml_field("TPP3", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
63     aml_append(field, aml_named_field("MOVV", 8));
64     aml_append(dev, field);
65 
66     /*
67      * DerefOf in Windows is broken with SYSTEM_MEMORY.  Use a dynamic
68      * operation region inside of a method for getting FUNC[op].
69      */
70     method = aml_method("TPFN", 1, AML_SERIALIZED);
71     {
72         Aml *op = aml_arg(0);
73         ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100)));
74         {
75             aml_append(ifctx, aml_return(zero));
76         }
77         aml_append(method, ifctx);
78 
79         aml_append(method,
80             aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
81                 aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1));
82         field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
83         aml_append(field, aml_named_field("TPPF", 8));
84         aml_append(method, field);
85         aml_append(method, aml_return(aml_name("TPPF")));
86     }
87     aml_append(dev, method);
88 
89     /*
90      * Use global TPM2 & TPM3 variables to workaround Windows ACPI bug
91      * when returning packages.
92      */
93     pak = aml_package(2);
94     aml_append(pak, zero);
95     aml_append(pak, zero);
96     aml_append(dev, aml_name_decl("TPM2", pak));
97     tpm2 = aml_name("TPM2");
98 
99     pak = aml_package(3);
100     aml_append(pak, zero);
101     aml_append(pak, zero);
102     aml_append(pak, zero);
103     aml_append(dev, aml_name_decl("TPM3", pak));
104     tpm3 = aml_name("TPM3");
105 
106     method = aml_method("_DSM", 4, AML_SERIALIZED);
107     {
108         uint8_t zerobyte[1] = { 0 };
109         Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid;
110 
111         uuid = aml_arg(0);
112         rev = aml_arg(1);
113         function = aml_arg(2);
114         arguments = aml_arg(3);
115         op = aml_local(0);
116         op_flags = aml_local(1);
117 
118         /* Physical Presence Interface */
119         ifctx = aml_if(
120             aml_equal(uuid,
121                       aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
122         {
123             /* standard DSM query function */
124             ifctx2 = aml_if(aml_equal(function, zero));
125             {
126                 uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */
127 
128                 aml_append(ifctx2,
129                            aml_return(aml_buffer(sizeof(byte_list),
130                                                  byte_list)));
131             }
132             aml_append(ifctx, ifctx2);
133 
134             /*
135              * PPI 1.0: 2.1.1 Get Physical Presence Interface Version
136              *
137              * Arg 2 (Integer): Function Index = 1
138              * Arg 3 (Package): Arguments = Empty Package
139              * Returns: Type: String
140              */
141             ifctx2 = aml_if(aml_equal(function, one));
142             {
143                 aml_append(ifctx2, aml_return(aml_string("1.3")));
144             }
145             aml_append(ifctx, ifctx2);
146 
147             /*
148              * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment
149              *
150              * Arg 2 (Integer): Function Index = 2
151              * Arg 3 (Package): Arguments = Package: Type: Integer
152              *                              Operation Value of the Request
153              * Returns: Type: Integer
154              *          0: Success
155              *          1: Operation Value of the Request Not Supported
156              *          2: General Failure
157              */
158             ifctx2 = aml_if(aml_equal(function, aml_int(2)));
159             {
160                 /* get opcode */
161                 aml_append(ifctx2,
162                            aml_store(aml_derefof(aml_index(arguments,
163                                                            zero)), op));
164 
165                 /* get opcode flags */
166                 aml_append(ifctx2,
167                            aml_store(aml_call1("TPFN", op), op_flags));
168 
169                 /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
170                 ifctx3 = aml_if(
171                     aml_equal(
172                         aml_and(op_flags, func_mask, NULL),
173                         not_implemented));
174                 {
175                     /* 1: Operation Value of the Request Not Supported */
176                     aml_append(ifctx3, aml_return(one));
177                 }
178                 aml_append(ifctx2, ifctx3);
179 
180                 aml_append(ifctx2, aml_store(op, pprq));
181                 aml_append(ifctx2, aml_store(zero, pprm));
182                 /* 0: success */
183                 aml_append(ifctx2, aml_return(zero));
184             }
185             aml_append(ifctx, ifctx2);
186 
187             /*
188              * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS
189              *
190              * Arg 2 (Integer): Function Index = 3
191              * Arg 3 (Package): Arguments = Empty Package
192              * Returns: Type: Package of Integers
193              *          Integer 1: Function Return code
194              *                     0: Success
195              *                     1: General Failure
196              *          Integer 2: Pending operation requested by the OS
197              *                     0: None
198              *                    >0: Operation Value of the Pending Request
199              *          Integer 3: Optional argument to pending operation
200              *                     requested by the OS
201              *                     0: None
202              *                    >0: Argument Value of the Pending Request
203              */
204             ifctx2 = aml_if(aml_equal(function, aml_int(3)));
205             {
206                 /*
207                  * Revision ID of 1, no integer parameter beyond
208                  * parameter two are expected
209                  */
210                 ifctx3 = aml_if(aml_equal(rev, one));
211                 {
212                     /* TPM2[1] = PPRQ */
213                     aml_append(ifctx3,
214                                aml_store(pprq, aml_index(tpm2, one)));
215                     aml_append(ifctx3, aml_return(tpm2));
216                 }
217                 aml_append(ifctx2, ifctx3);
218 
219                 /*
220                  * A return value of {0, 23, 1} indicates that
221                  * operation 23 with argument 1 is pending.
222                  */
223                 ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
224                 {
225                     /* TPM3[1] = PPRQ */
226                     aml_append(ifctx3,
227                                aml_store(pprq, aml_index(tpm3, one)));
228                     /* TPM3[2] = PPRM */
229                     aml_append(ifctx3,
230                                aml_store(pprm, aml_index(tpm3, aml_int(2))));
231                     aml_append(ifctx3, aml_return(tpm3));
232                 }
233                 aml_append(ifctx2, ifctx3);
234             }
235             aml_append(ifctx, ifctx2);
236 
237             /*
238              * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to
239              *     Pre-OS Environment
240              *
241              * Arg 2 (Integer): Function Index = 4
242              * Arg 3 (Package): Arguments = Empty Package
243              * Returns: Type: Integer
244              *          0: None
245              *          1: Shutdown
246              *          2: Reboot
247              *          3: OS Vendor-specific
248              */
249             ifctx2 = aml_if(aml_equal(function, aml_int(4)));
250             {
251                 /* reboot */
252                 aml_append(ifctx2, aml_return(aml_int(2)));
253             }
254             aml_append(ifctx, ifctx2);
255 
256             /*
257              * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment
258              *
259              * Arg 2 (Integer): Function Index = 5
260              * Arg 3 (Package): Arguments = Empty Package
261              * Returns: Type: Package of Integer
262              *          Integer 1: Function Return code
263              *                     0: Success
264              *                     1: General Failure
265              *          Integer 2: Most recent operation request
266              *                     0: None
267              *                    >0: Operation Value of the most recent request
268              *          Integer 3: Response to the most recent operation request
269              *                     0: Success
270              *                     0x00000001..0x00000FFF: Corresponding TPM
271              *                                             error code
272              *                     0xFFFFFFF0: User Abort or timeout of dialog
273              *                     0xFFFFFFF1: firmware Failure
274              */
275             ifctx2 = aml_if(aml_equal(function, aml_int(5)));
276             {
277                 /* TPM3[1] = LPPR */
278                 aml_append(ifctx2,
279                            aml_store(aml_name("LPPR"),
280                                      aml_index(tpm3, one)));
281                 /* TPM3[2] = PPRP */
282                 aml_append(ifctx2,
283                            aml_store(aml_name("PPRP"),
284                                      aml_index(tpm3, aml_int(2))));
285                 aml_append(ifctx2, aml_return(tpm3));
286             }
287             aml_append(ifctx, ifctx2);
288 
289             /*
290              * PPI 1.0: 2.1.7 Submit preferred user language
291              *
292              * Arg 2 (Integer): Function Index = 6
293              * Arg 3 (Package): Arguments = String Package
294              *                  Preferred language code
295              * Returns: Type: Integer
296              * Function Return Code
297              *          3: Not implemented
298              */
299             ifctx2 = aml_if(aml_equal(function, aml_int(6)));
300             {
301                 /* 3 = not implemented */
302                 aml_append(ifctx2, aml_return(aml_int(3)));
303             }
304             aml_append(ifctx, ifctx2);
305 
306             /*
307              * PPI 1.1: 2.1.7 Submit TPM Operation Request to
308              *     Pre-OS Environment 2
309              *
310              * Arg 2 (Integer): Function Index = 7
311              * Arg 3 (Package): Arguments = Package: Type: Integer
312              *                  Integer 1: Operation Value of the Request
313              *                  Integer 2: Argument for Operation (optional)
314              * Returns: Type: Integer
315              *          0: Success
316              *          1: Not Implemented
317              *          2: General Failure
318              *          3: Operation blocked by current firmware settings
319              */
320             ifctx2 = aml_if(aml_equal(function, aml_int(7)));
321             {
322                 /* get opcode */
323                 aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments,
324                                                                    zero)),
325                                              op));
326 
327                 /* get opcode flags */
328                 aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
329                                              op_flags));
330                 /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
331                 ifctx3 = aml_if(
332                     aml_equal(
333                         aml_and(op_flags, func_mask, NULL),
334                         not_implemented));
335                 {
336                     /* 1: not implemented */
337                     aml_append(ifctx3, aml_return(one));
338                 }
339                 aml_append(ifctx2, ifctx3);
340 
341                 /* if func[opcode] & TPM_PPI_FUNC_BLOCKED */
342                 ifctx3 = aml_if(
343                     aml_equal(
344                         aml_and(op_flags, func_mask, NULL),
345                         aml_int(TPM_PPI_FUNC_BLOCKED)));
346                 {
347                     /* 3: blocked by firmware */
348                     aml_append(ifctx3, aml_return(aml_int(3)));
349                 }
350                 aml_append(ifctx2, ifctx3);
351 
352                 /* revision to integer */
353                 ifctx3 = aml_if(aml_equal(rev, one));
354                 {
355                     /* revision 1 */
356                     /* PPRQ = op */
357                     aml_append(ifctx3, aml_store(op, pprq));
358                     /* no argument, PPRM = 0 */
359                     aml_append(ifctx3, aml_store(zero, pprm));
360                 }
361                 aml_append(ifctx2, ifctx3);
362 
363                 ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
364                 {
365                     /* revision 2 */
366                     /* PPRQ = op */
367                     op_arg = aml_derefof(aml_index(arguments, one));
368                     aml_append(ifctx3, aml_store(op, pprq));
369                     /* PPRM = arg3[1] */
370                     aml_append(ifctx3, aml_store(op_arg, pprm));
371                 }
372                 aml_append(ifctx2, ifctx3);
373                 /* 0: success */
374                 aml_append(ifctx2, aml_return(zero));
375             }
376             aml_append(ifctx, ifctx2);
377 
378             /*
379              * PPI 1.1: 2.1.8 Get User Confirmation Status for Operation
380              *
381              * Arg 2 (Integer): Function Index = 8
382              * Arg 3 (Package): Arguments = Package: Type: Integer
383              *                  Operation Value that may need user confirmation
384              * Returns: Type: Integer
385              *          0: Not implemented
386              *          1: Firmware only
387              *          2: Blocked for OS by firmware configuration
388              *          3: Allowed and physically present user required
389              *          4: Allowed and physically present user not required
390              */
391             ifctx2 = aml_if(aml_equal(function, aml_int(8)));
392             {
393                 /* get opcode */
394                 aml_append(ifctx2,
395                            aml_store(aml_derefof(aml_index(arguments,
396                                                            zero)),
397                                      op));
398 
399                 /* get opcode flags */
400                 aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
401                                              op_flags));
402                 /* return confirmation status code */
403                 aml_append(ifctx2,
404                            aml_return(
405                                aml_and(op_flags, func_mask, NULL)));
406             }
407             aml_append(ifctx, ifctx2);
408 
409             aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
410         }
411         aml_append(method, ifctx);
412 
413         /*
414          * "TCG Platform Reset Attack Mitigation Specification 1.00",
415          * Chapter 6 "ACPI _DSM Function"
416          */
417         ifctx = aml_if(
418             aml_equal(uuid,
419                       aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
420         {
421             /* standard DSM query function */
422             ifctx2 = aml_if(aml_equal(function, zero));
423             {
424                 uint8_t byte_list[1] = { 0x03 }; /* functions 1-2 supported */
425 
426                 aml_append(ifctx2,
427                            aml_return(aml_buffer(sizeof(byte_list),
428                                                  byte_list)));
429             }
430             aml_append(ifctx, ifctx2);
431 
432             /*
433              * TCG Platform Reset Attack Mitigation Specification 1.0 Ch.6
434              *
435              * Arg 2 (Integer): Function Index = 1
436              * Arg 3 (Package): Arguments = Package: Type: Integer
437              *                  Operation Value of the Request
438              * Returns: Type: Integer
439              *          0: Success
440              *          1: General Failure
441              */
442             ifctx2 = aml_if(aml_equal(function, one));
443             {
444                 aml_append(ifctx2,
445                            aml_store(aml_derefof(aml_index(arguments, zero)),
446                                      op));
447                 {
448                     aml_append(ifctx2, aml_store(op, aml_name("MOVV")));
449 
450                     /* 0: success */
451                     aml_append(ifctx2, aml_return(zero));
452                 }
453             }
454             aml_append(ifctx, ifctx2);
455         }
456         aml_append(method, ifctx);
457     }
458     aml_append(dev, method);
459 }
460