qemu
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
23void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)24{
25Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *func_mask,26*not_implemented, *pak, *tpm2, *tpm3, *pprm, *pprq, *zero, *one;27
28if (!object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) {29return;30}31
32zero = aml_int(0);33one = aml_int(1);34func_mask = aml_int(TPM_PPI_FUNC_MASK);35not_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*/
41aml_append(dev,42aml_operation_region("TPP2", AML_SYSTEM_MEMORY,43aml_int(TPM_PPI_ADDR_BASE + 0x100),440x5A));45field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);46aml_append(field, aml_named_field("PPIN", 8));47aml_append(field, aml_named_field("PPIP", 32));48aml_append(field, aml_named_field("PPRP", 32));49aml_append(field, aml_named_field("PPRQ", 32));50aml_append(field, aml_named_field("PPRM", 32));51aml_append(field, aml_named_field("LPPR", 32));52aml_append(dev, field);53pprq = aml_name("PPRQ");54pprm = aml_name("PPRM");55
56aml_append(dev,57aml_operation_region(58"TPP3", AML_SYSTEM_MEMORY,59aml_int(TPM_PPI_ADDR_BASE +600x15a /* movv, docs/specs/tpm.rst */),610x1));62field = aml_field("TPP3", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);63aml_append(field, aml_named_field("MOVV", 8));64aml_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*/
70method = aml_method("TPFN", 1, AML_SERIALIZED);71{72Aml *op = aml_arg(0);73ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100)));74{75aml_append(ifctx, aml_return(zero));76}77aml_append(method, ifctx);78
79aml_append(method,80aml_operation_region("TPP1", AML_SYSTEM_MEMORY,81aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1));82field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);83aml_append(field, aml_named_field("TPPF", 8));84aml_append(method, field);85aml_append(method, aml_return(aml_name("TPPF")));86}87aml_append(dev, method);88
89/*90* Use global TPM2 & TPM3 variables to workaround Windows ACPI bug
91* when returning packages.
92*/
93pak = aml_package(2);94aml_append(pak, zero);95aml_append(pak, zero);96aml_append(dev, aml_name_decl("TPM2", pak));97tpm2 = aml_name("TPM2");98
99pak = aml_package(3);100aml_append(pak, zero);101aml_append(pak, zero);102aml_append(pak, zero);103aml_append(dev, aml_name_decl("TPM3", pak));104tpm3 = aml_name("TPM3");105
106method = aml_method("_DSM", 4, AML_SERIALIZED);107{108uint8_t zerobyte[1] = { 0 };109Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid;110
111uuid = aml_arg(0);112rev = aml_arg(1);113function = aml_arg(2);114arguments = aml_arg(3);115op = aml_local(0);116op_flags = aml_local(1);117
118/* Physical Presence Interface */119ifctx = aml_if(120aml_equal(uuid,121aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));122{123/* standard DSM query function */124ifctx2 = aml_if(aml_equal(function, zero));125{126uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */127
128aml_append(ifctx2,129aml_return(aml_buffer(sizeof(byte_list),130byte_list)));131}132aml_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*/
141ifctx2 = aml_if(aml_equal(function, one));142{143aml_append(ifctx2, aml_return(aml_string("1.3")));144}145aml_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*/
158ifctx2 = aml_if(aml_equal(function, aml_int(2)));159{160/* get opcode */161aml_append(ifctx2,162aml_store(aml_derefof(aml_index(arguments,163zero)), op));164
165/* get opcode flags */166aml_append(ifctx2,167aml_store(aml_call1("TPFN", op), op_flags));168
169/* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */170ifctx3 = aml_if(171aml_equal(172aml_and(op_flags, func_mask, NULL),173not_implemented));174{175/* 1: Operation Value of the Request Not Supported */176aml_append(ifctx3, aml_return(one));177}178aml_append(ifctx2, ifctx3);179
180aml_append(ifctx2, aml_store(op, pprq));181aml_append(ifctx2, aml_store(zero, pprm));182/* 0: success */183aml_append(ifctx2, aml_return(zero));184}185aml_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*/
204ifctx2 = 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*/
210ifctx3 = aml_if(aml_equal(rev, one));211{212/* TPM2[1] = PPRQ */213aml_append(ifctx3,214aml_store(pprq, aml_index(tpm2, one)));215aml_append(ifctx3, aml_return(tpm2));216}217aml_append(ifctx2, ifctx3);218
219/*220* A return value of {0, 23, 1} indicates that
221* operation 23 with argument 1 is pending.
222*/
223ifctx3 = aml_if(aml_equal(rev, aml_int(2)));224{225/* TPM3[1] = PPRQ */226aml_append(ifctx3,227aml_store(pprq, aml_index(tpm3, one)));228/* TPM3[2] = PPRM */229aml_append(ifctx3,230aml_store(pprm, aml_index(tpm3, aml_int(2))));231aml_append(ifctx3, aml_return(tpm3));232}233aml_append(ifctx2, ifctx3);234}235aml_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*/
249ifctx2 = aml_if(aml_equal(function, aml_int(4)));250{251/* reboot */252aml_append(ifctx2, aml_return(aml_int(2)));253}254aml_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*/
275ifctx2 = aml_if(aml_equal(function, aml_int(5)));276{277/* TPM3[1] = LPPR */278aml_append(ifctx2,279aml_store(aml_name("LPPR"),280aml_index(tpm3, one)));281/* TPM3[2] = PPRP */282aml_append(ifctx2,283aml_store(aml_name("PPRP"),284aml_index(tpm3, aml_int(2))));285aml_append(ifctx2, aml_return(tpm3));286}287aml_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*/
299ifctx2 = aml_if(aml_equal(function, aml_int(6)));300{301/* 3 = not implemented */302aml_append(ifctx2, aml_return(aml_int(3)));303}304aml_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*/
320ifctx2 = aml_if(aml_equal(function, aml_int(7)));321{322/* get opcode */323aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments,324zero)),325op));326
327/* get opcode flags */328aml_append(ifctx2, aml_store(aml_call1("TPFN", op),329op_flags));330/* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */331ifctx3 = aml_if(332aml_equal(333aml_and(op_flags, func_mask, NULL),334not_implemented));335{336/* 1: not implemented */337aml_append(ifctx3, aml_return(one));338}339aml_append(ifctx2, ifctx3);340
341/* if func[opcode] & TPM_PPI_FUNC_BLOCKED */342ifctx3 = aml_if(343aml_equal(344aml_and(op_flags, func_mask, NULL),345aml_int(TPM_PPI_FUNC_BLOCKED)));346{347/* 3: blocked by firmware */348aml_append(ifctx3, aml_return(aml_int(3)));349}350aml_append(ifctx2, ifctx3);351
352/* revision to integer */353ifctx3 = aml_if(aml_equal(rev, one));354{355/* revision 1 */356/* PPRQ = op */357aml_append(ifctx3, aml_store(op, pprq));358/* no argument, PPRM = 0 */359aml_append(ifctx3, aml_store(zero, pprm));360}361aml_append(ifctx2, ifctx3);362
363ifctx3 = aml_if(aml_equal(rev, aml_int(2)));364{365/* revision 2 */366/* PPRQ = op */367op_arg = aml_derefof(aml_index(arguments, one));368aml_append(ifctx3, aml_store(op, pprq));369/* PPRM = arg3[1] */370aml_append(ifctx3, aml_store(op_arg, pprm));371}372aml_append(ifctx2, ifctx3);373/* 0: success */374aml_append(ifctx2, aml_return(zero));375}376aml_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*/
391ifctx2 = aml_if(aml_equal(function, aml_int(8)));392{393/* get opcode */394aml_append(ifctx2,395aml_store(aml_derefof(aml_index(arguments,396zero)),397op));398
399/* get opcode flags */400aml_append(ifctx2, aml_store(aml_call1("TPFN", op),401op_flags));402/* return confirmation status code */403aml_append(ifctx2,404aml_return(405aml_and(op_flags, func_mask, NULL)));406}407aml_append(ifctx, ifctx2);408
409aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));410}411aml_append(method, ifctx);412
413/*414* "TCG Platform Reset Attack Mitigation Specification 1.00",
415* Chapter 6 "ACPI _DSM Function"
416*/
417ifctx = aml_if(418aml_equal(uuid,419aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));420{421/* standard DSM query function */422ifctx2 = aml_if(aml_equal(function, zero));423{424uint8_t byte_list[1] = { 0x03 }; /* functions 1-2 supported */425
426aml_append(ifctx2,427aml_return(aml_buffer(sizeof(byte_list),428byte_list)));429}430aml_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*/
442ifctx2 = aml_if(aml_equal(function, one));443{444aml_append(ifctx2,445aml_store(aml_derefof(aml_index(arguments, zero)),446op));447{448aml_append(ifctx2, aml_store(op, aml_name("MOVV")));449
450/* 0: success */451aml_append(ifctx2, aml_return(zero));452}453}454aml_append(ifctx, ifctx2);455}456aml_append(method, ifctx);457}458aml_append(dev, method);459}
460