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