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