qemu/hw/acpi/tpm.c
<<
>>
Prefs
   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{
  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