xref: /openbmc/qemu/hw/acpi/tpm.c (revision ac6dd31e3fe7e19be6fcaa7bf2396780b355137d)
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     /*
57      * DerefOf in Windows is broken with SYSTEM_MEMORY.  Use a dynamic
58      * operation region inside of a method for getting FUNC[op].
59      */
60     method = aml_method("TPFN", 1, AML_SERIALIZED);
61     {
62         Aml *op = aml_arg(0);
63         ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100)));
64         {
65             aml_append(ifctx, aml_return(zero));
66         }
67         aml_append(method, ifctx);
68 
69         aml_append(method,
70             aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
71                 aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1));
72         field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
73         aml_append(field, aml_named_field("TPPF", 8));
74         aml_append(method, field);
75         aml_append(method, aml_return(aml_name("TPPF")));
76     }
77     aml_append(dev, method);
78 
79     /*
80      * Use global TPM2 & TPM3 variables to workaround Windows ACPI bug
81      * when returning packages.
82      */
83     pak = aml_package(2);
84     aml_append(pak, zero);
85     aml_append(pak, zero);
86     aml_append(dev, aml_name_decl("TPM2", pak));
87     tpm2 = aml_name("TPM2");
88 
89     pak = aml_package(3);
90     aml_append(pak, zero);
91     aml_append(pak, zero);
92     aml_append(pak, zero);
93     aml_append(dev, aml_name_decl("TPM3", pak));
94     tpm3 = aml_name("TPM3");
95 
96     method = aml_method("_DSM", 4, AML_SERIALIZED);
97     {
98         uint8_t zerobyte[1] = { 0 };
99         Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid;
100 
101         uuid = aml_arg(0);
102         rev = aml_arg(1);
103         function = aml_arg(2);
104         arguments = aml_arg(3);
105         op = aml_local(0);
106         op_flags = aml_local(1);
107 
108         /* Physical Presence Interface */
109         ifctx = aml_if(
110             aml_equal(uuid,
111                       aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
112         {
113             /* standard DSM query function */
114             ifctx2 = aml_if(aml_equal(function, zero));
115             {
116                 uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */
117 
118                 aml_append(ifctx2,
119                            aml_return(aml_buffer(sizeof(byte_list),
120                                                  byte_list)));
121             }
122             aml_append(ifctx, ifctx2);
123 
124             /*
125              * PPI 1.0: 2.1.1 Get Physical Presence Interface Version
126              *
127              * Arg 2 (Integer): Function Index = 1
128              * Arg 3 (Package): Arguments = Empty Package
129              * Returns: Type: String
130              */
131             ifctx2 = aml_if(aml_equal(function, one));
132             {
133                 aml_append(ifctx2, aml_return(aml_string("1.3")));
134             }
135             aml_append(ifctx, ifctx2);
136 
137             /*
138              * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment
139              *
140              * Arg 2 (Integer): Function Index = 2
141              * Arg 3 (Package): Arguments = Package: Type: Integer
142              *                              Operation Value of the Request
143              * Returns: Type: Integer
144              *          0: Success
145              *          1: Operation Value of the Request Not Supported
146              *          2: General Failure
147              */
148             ifctx2 = aml_if(aml_equal(function, aml_int(2)));
149             {
150                 /* get opcode */
151                 aml_append(ifctx2,
152                            aml_store(aml_derefof(aml_index(arguments,
153                                                            zero)), op));
154 
155                 /* get opcode flags */
156                 aml_append(ifctx2,
157                            aml_store(aml_call1("TPFN", op), op_flags));
158 
159                 /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
160                 ifctx3 = aml_if(
161                     aml_equal(
162                         aml_and(op_flags, func_mask, NULL),
163                         not_implemented));
164                 {
165                     /* 1: Operation Value of the Request Not Supported */
166                     aml_append(ifctx3, aml_return(one));
167                 }
168                 aml_append(ifctx2, ifctx3);
169 
170                 aml_append(ifctx2, aml_store(op, pprq));
171                 aml_append(ifctx2, aml_store(zero, pprm));
172                 /* 0: success */
173                 aml_append(ifctx2, aml_return(zero));
174             }
175             aml_append(ifctx, ifctx2);
176 
177             /*
178              * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS
179              *
180              * Arg 2 (Integer): Function Index = 3
181              * Arg 3 (Package): Arguments = Empty Package
182              * Returns: Type: Package of Integers
183              *          Integer 1: Function Return code
184              *                     0: Success
185              *                     1: General Failure
186              *          Integer 2: Pending operation requested by the OS
187              *                     0: None
188              *                    >0: Operation Value of the Pending Request
189              *          Integer 3: Optional argument to pending operation
190              *                     requested by the OS
191              *                     0: None
192              *                    >0: Argument Value of the Pending Request
193              */
194             ifctx2 = aml_if(aml_equal(function, aml_int(3)));
195             {
196                 /*
197                  * Revision ID of 1, no integer parameter beyond
198                  * parameter two are expected
199                  */
200                 ifctx3 = aml_if(aml_equal(rev, one));
201                 {
202                     /* TPM2[1] = PPRQ */
203                     aml_append(ifctx3,
204                                aml_store(pprq, aml_index(tpm2, one)));
205                     aml_append(ifctx3, aml_return(tpm2));
206                 }
207                 aml_append(ifctx2, ifctx3);
208 
209                 /*
210                  * A return value of {0, 23, 1} indicates that
211                  * operation 23 with argument 1 is pending.
212                  */
213                 ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
214                 {
215                     /* TPM3[1] = PPRQ */
216                     aml_append(ifctx3,
217                                aml_store(pprq, aml_index(tpm3, one)));
218                     /* TPM3[2] = PPRM */
219                     aml_append(ifctx3,
220                                aml_store(pprm, aml_index(tpm3, aml_int(2))));
221                     aml_append(ifctx3, aml_return(tpm3));
222                 }
223                 aml_append(ifctx2, ifctx3);
224             }
225             aml_append(ifctx, ifctx2);
226 
227             /*
228              * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to
229              *     Pre-OS Environment
230              *
231              * Arg 2 (Integer): Function Index = 4
232              * Arg 3 (Package): Arguments = Empty Package
233              * Returns: Type: Integer
234              *          0: None
235              *          1: Shutdown
236              *          2: Reboot
237              *          3: OS Vendor-specific
238              */
239             ifctx2 = aml_if(aml_equal(function, aml_int(4)));
240             {
241                 /* reboot */
242                 aml_append(ifctx2, aml_return(aml_int(2)));
243             }
244             aml_append(ifctx, ifctx2);
245 
246             /*
247              * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment
248              *
249              * Arg 2 (Integer): Function Index = 5
250              * Arg 3 (Package): Arguments = Empty Package
251              * Returns: Type: Package of Integer
252              *          Integer 1: Function Return code
253              *                     0: Success
254              *                     1: General Failure
255              *          Integer 2: Most recent operation request
256              *                     0: None
257              *                    >0: Operation Value of the most recent request
258              *          Integer 3: Response to the most recent operation request
259              *                     0: Success
260              *                     0x00000001..0x00000FFF: Corresponding TPM
261              *                                             error code
262              *                     0xFFFFFFF0: User Abort or timeout of dialog
263              *                     0xFFFFFFF1: firmware Failure
264              */
265             ifctx2 = aml_if(aml_equal(function, aml_int(5)));
266             {
267                 /* TPM3[1] = LPPR */
268                 aml_append(ifctx2,
269                            aml_store(aml_name("LPPR"),
270                                      aml_index(tpm3, one)));
271                 /* TPM3[2] = PPRP */
272                 aml_append(ifctx2,
273                            aml_store(aml_name("PPRP"),
274                                      aml_index(tpm3, aml_int(2))));
275                 aml_append(ifctx2, aml_return(tpm3));
276             }
277             aml_append(ifctx, ifctx2);
278 
279             /*
280              * PPI 1.0: 2.1.7 Submit preferred user language
281              *
282              * Arg 2 (Integer): Function Index = 6
283              * Arg 3 (Package): Arguments = String Package
284              *                  Preferred language code
285              * Returns: Type: Integer
286              * Function Return Code
287              *          3: Not implemented
288              */
289             ifctx2 = aml_if(aml_equal(function, aml_int(6)));
290             {
291                 /* 3 = not implemented */
292                 aml_append(ifctx2, aml_return(aml_int(3)));
293             }
294             aml_append(ifctx, ifctx2);
295 
296             /*
297              * PPI 1.1: 2.1.7 Submit TPM Operation Request to
298              *     Pre-OS Environment 2
299              *
300              * Arg 2 (Integer): Function Index = 7
301              * Arg 3 (Package): Arguments = Package: Type: Integer
302              *                  Integer 1: Operation Value of the Request
303              *                  Integer 2: Argument for Operation (optional)
304              * Returns: Type: Integer
305              *          0: Success
306              *          1: Not Implemented
307              *          2: General Failure
308              *          3: Operation blocked by current firmware settings
309              */
310             ifctx2 = aml_if(aml_equal(function, aml_int(7)));
311             {
312                 /* get opcode */
313                 aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments,
314                                                                    zero)),
315                                              op));
316 
317                 /* get opcode flags */
318                 aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
319                                              op_flags));
320                 /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
321                 ifctx3 = aml_if(
322                     aml_equal(
323                         aml_and(op_flags, func_mask, NULL),
324                         not_implemented));
325                 {
326                     /* 1: not implemented */
327                     aml_append(ifctx3, aml_return(one));
328                 }
329                 aml_append(ifctx2, ifctx3);
330 
331                 /* if func[opcode] & TPM_PPI_FUNC_BLOCKED */
332                 ifctx3 = aml_if(
333                     aml_equal(
334                         aml_and(op_flags, func_mask, NULL),
335                         aml_int(TPM_PPI_FUNC_BLOCKED)));
336                 {
337                     /* 3: blocked by firmware */
338                     aml_append(ifctx3, aml_return(aml_int(3)));
339                 }
340                 aml_append(ifctx2, ifctx3);
341 
342                 /* revision to integer */
343                 ifctx3 = aml_if(aml_equal(rev, one));
344                 {
345                     /* revision 1 */
346                     /* PPRQ = op */
347                     aml_append(ifctx3, aml_store(op, pprq));
348                     /* no argument, PPRM = 0 */
349                     aml_append(ifctx3, aml_store(zero, pprm));
350                 }
351                 aml_append(ifctx2, ifctx3);
352 
353                 ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
354                 {
355                     /* revision 2 */
356                     /* PPRQ = op */
357                     op_arg = aml_derefof(aml_index(arguments, one));
358                     aml_append(ifctx3, aml_store(op, pprq));
359                     /* PPRM = arg3[1] */
360                     aml_append(ifctx3, aml_store(op_arg, pprm));
361                 }
362                 aml_append(ifctx2, ifctx3);
363                 /* 0: success */
364                 aml_append(ifctx2, aml_return(zero));
365             }
366             aml_append(ifctx, ifctx2);
367 
368             /*
369              * PPI 1.1: 2.1.8 Get User Confirmation Status for Operation
370              *
371              * Arg 2 (Integer): Function Index = 8
372              * Arg 3 (Package): Arguments = Package: Type: Integer
373              *                  Operation Value that may need user confirmation
374              * Returns: Type: Integer
375              *          0: Not implemented
376              *          1: Firmware only
377              *          2: Blocked for OS by firmware configuration
378              *          3: Allowed and physically present user required
379              *          4: Allowed and physically present user not required
380              */
381             ifctx2 = aml_if(aml_equal(function, aml_int(8)));
382             {
383                 /* get opcode */
384                 aml_append(ifctx2,
385                            aml_store(aml_derefof(aml_index(arguments,
386                                                            zero)),
387                                      op));
388 
389                 /* get opcode flags */
390                 aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
391                                              op_flags));
392                 /* return confirmation status code */
393                 aml_append(ifctx2,
394                            aml_return(
395                                aml_and(op_flags, func_mask, NULL)));
396             }
397             aml_append(ifctx, ifctx2);
398 
399             aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
400         }
401         aml_append(method, ifctx);
402     }
403     aml_append(dev, method);
404 }
405