root/drivers/char/tpm/tpm_ppi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tpm_ppi_req_has_parameter
  2. tpm_eval_dsm
  3. tpm_show_ppi_version
  4. tpm_show_ppi_request
  5. tpm_store_ppi_request
  6. tpm_show_ppi_transition_action
  7. tpm_show_ppi_response
  8. show_ppi_operations
  9. tpm_show_ppi_tcg_operations
  10. tpm_show_ppi_vs_operations
  11. tpm_add_ppi

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2012-2014 Intel Corporation
   4  *
   5  * Authors:
   6  * Xiaoyan Zhang <xiaoyan.zhang@intel.com>
   7  * Jiang Liu <jiang.liu@linux.intel.com>
   8  * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
   9  *
  10  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  11  *
  12  * This file contains implementation of the sysfs interface for PPI.
  13  */
  14 
  15 
  16 #include <linux/acpi.h>
  17 #include "tpm.h"
  18 
  19 #define TPM_PPI_REVISION_ID_1   1
  20 #define TPM_PPI_REVISION_ID_2   2
  21 #define TPM_PPI_FN_VERSION      1
  22 #define TPM_PPI_FN_SUBREQ       2
  23 #define TPM_PPI_FN_GETREQ       3
  24 #define TPM_PPI_FN_GETACT       4
  25 #define TPM_PPI_FN_GETRSP       5
  26 #define TPM_PPI_FN_SUBREQ2      7
  27 #define TPM_PPI_FN_GETOPR       8
  28 #define PPI_TPM_REQ_MAX         101 /* PPI 1.3 for TPM 2 */
  29 #define PPI_VS_REQ_START        128
  30 #define PPI_VS_REQ_END          255
  31 
  32 static const guid_t tpm_ppi_guid =
  33         GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
  34                   0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
  35 
  36 static bool tpm_ppi_req_has_parameter(u64 req)
  37 {
  38         return req == 23;
  39 }
  40 
  41 static inline union acpi_object *
  42 tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
  43              union acpi_object *argv4, u64 rev)
  44 {
  45         BUG_ON(!ppi_handle);
  46         return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
  47                                        rev, func, argv4, type);
  48 }
  49 
  50 static ssize_t tpm_show_ppi_version(struct device *dev,
  51                                     struct device_attribute *attr, char *buf)
  52 {
  53         struct tpm_chip *chip = to_tpm_chip(dev);
  54 
  55         return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
  56 }
  57 
  58 static ssize_t tpm_show_ppi_request(struct device *dev,
  59                                     struct device_attribute *attr, char *buf)
  60 {
  61         ssize_t size = -EINVAL;
  62         union acpi_object *obj;
  63         struct tpm_chip *chip = to_tpm_chip(dev);
  64         u64 rev = TPM_PPI_REVISION_ID_2;
  65         u64 req;
  66 
  67         if (strcmp(chip->ppi_version, "1.2") < 0)
  68                 rev = TPM_PPI_REVISION_ID_1;
  69 
  70         obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
  71                            ACPI_TYPE_PACKAGE, NULL, rev);
  72         if (!obj)
  73                 return -ENXIO;
  74 
  75         /*
  76          * output.pointer should be of package type, including two integers.
  77          * The first is function return code, 0 means success and 1 means
  78          * error. The second is pending TPM operation requested by the OS, 0
  79          * means none and >0 means operation value.
  80          */
  81         if (obj->package.count == 3 &&
  82             obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
  83             obj->package.elements[1].type == ACPI_TYPE_INTEGER &&
  84             obj->package.elements[2].type == ACPI_TYPE_INTEGER) {
  85                 if (obj->package.elements[0].integer.value)
  86                         size = -EFAULT;
  87                 else {
  88                         req = obj->package.elements[1].integer.value;
  89                         if (tpm_ppi_req_has_parameter(req))
  90                                 size = scnprintf(buf, PAGE_SIZE,
  91                                     "%llu %llu\n", req,
  92                                     obj->package.elements[2].integer.value);
  93                         else
  94                                 size = scnprintf(buf, PAGE_SIZE,
  95                                                 "%llu\n", req);
  96                 }
  97         } else if (obj->package.count == 2 &&
  98             obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
  99             obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
 100                 if (obj->package.elements[0].integer.value)
 101                         size = -EFAULT;
 102                 else
 103                         size = scnprintf(buf, PAGE_SIZE, "%llu\n",
 104                                  obj->package.elements[1].integer.value);
 105         }
 106 
 107         ACPI_FREE(obj);
 108 
 109         return size;
 110 }
 111 
 112 static ssize_t tpm_store_ppi_request(struct device *dev,
 113                                      struct device_attribute *attr,
 114                                      const char *buf, size_t count)
 115 {
 116         u32 req;
 117         u64 ret;
 118         int func = TPM_PPI_FN_SUBREQ;
 119         union acpi_object *obj, tmp[2];
 120         union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp);
 121         struct tpm_chip *chip = to_tpm_chip(dev);
 122         u64 rev = TPM_PPI_REVISION_ID_1;
 123 
 124         /*
 125          * the function to submit TPM operation request to pre-os environment
 126          * is updated with function index from SUBREQ to SUBREQ2 since PPI
 127          * version 1.1
 128          */
 129         if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
 130                            TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2))
 131                 func = TPM_PPI_FN_SUBREQ2;
 132 
 133         /*
 134          * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
 135          * accept buffer/string/integer type, but some BIOS accept buffer/
 136          * string/package type. For PPI version 1.0 and 1.1, use buffer type
 137          * for compatibility, and use package type since 1.2 according to spec.
 138          */
 139         if (strcmp(chip->ppi_version, "1.3") == 0) {
 140                 if (sscanf(buf, "%llu %llu", &tmp[0].integer.value,
 141                            &tmp[1].integer.value) != 2)
 142                         goto ppi12;
 143                 rev = TPM_PPI_REVISION_ID_2;
 144                 tmp[0].type = ACPI_TYPE_INTEGER;
 145                 tmp[1].type = ACPI_TYPE_INTEGER;
 146         } else if (strcmp(chip->ppi_version, "1.2") < 0) {
 147                 if (sscanf(buf, "%d", &req) != 1)
 148                         return -EINVAL;
 149                 argv4.type = ACPI_TYPE_BUFFER;
 150                 argv4.buffer.length = sizeof(req);
 151                 argv4.buffer.pointer = (u8 *)&req;
 152         } else {
 153 ppi12:
 154                 argv4.package.count = 1;
 155                 tmp[0].type = ACPI_TYPE_INTEGER;
 156                 if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1)
 157                         return -EINVAL;
 158         }
 159 
 160         obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
 161                            &argv4, rev);
 162         if (!obj) {
 163                 return -ENXIO;
 164         } else {
 165                 ret = obj->integer.value;
 166                 ACPI_FREE(obj);
 167         }
 168 
 169         if (ret == 0)
 170                 return (acpi_status)count;
 171 
 172         return (ret == 1) ? -EPERM : -EFAULT;
 173 }
 174 
 175 static ssize_t tpm_show_ppi_transition_action(struct device *dev,
 176                                               struct device_attribute *attr,
 177                                               char *buf)
 178 {
 179         u32 ret;
 180         acpi_status status;
 181         union acpi_object *obj = NULL;
 182         union acpi_object tmp = {
 183                 .buffer.type = ACPI_TYPE_BUFFER,
 184                 .buffer.length = 0,
 185                 .buffer.pointer = NULL
 186         };
 187         struct tpm_chip *chip = to_tpm_chip(dev);
 188 
 189         static char *info[] = {
 190                 "None",
 191                 "Shutdown",
 192                 "Reboot",
 193                 "OS Vendor-specific",
 194                 "Error",
 195         };
 196 
 197         /*
 198          * PPI spec defines params[3].type as empty package, but some platforms
 199          * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
 200          * compatibility, define params[3].type as buffer, if PPI version < 1.2
 201          */
 202         if (strcmp(chip->ppi_version, "1.2") < 0)
 203                 obj = &tmp;
 204         obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
 205                            ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1);
 206         if (!obj) {
 207                 return -ENXIO;
 208         } else {
 209                 ret = obj->integer.value;
 210                 ACPI_FREE(obj);
 211         }
 212 
 213         if (ret < ARRAY_SIZE(info) - 1)
 214                 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]);
 215         else
 216                 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret,
 217                                    info[ARRAY_SIZE(info)-1]);
 218         return status;
 219 }
 220 
 221 static ssize_t tpm_show_ppi_response(struct device *dev,
 222                                      struct device_attribute *attr,
 223                                      char *buf)
 224 {
 225         acpi_status status = -EINVAL;
 226         union acpi_object *obj, *ret_obj;
 227         u64 req, res;
 228         struct tpm_chip *chip = to_tpm_chip(dev);
 229 
 230         obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
 231                            ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1);
 232         if (!obj)
 233                 return -ENXIO;
 234 
 235         /*
 236          * parameter output.pointer should be of package type, including
 237          * 3 integers. The first means function return code, the second means
 238          * most recent TPM operation request, and the last means response to
 239          * the most recent TPM operation request. Only if the first is 0, and
 240          * the second integer is not 0, the response makes sense.
 241          */
 242         ret_obj = obj->package.elements;
 243         if (obj->package.count < 3 ||
 244             ret_obj[0].type != ACPI_TYPE_INTEGER ||
 245             ret_obj[1].type != ACPI_TYPE_INTEGER ||
 246             ret_obj[2].type != ACPI_TYPE_INTEGER)
 247                 goto cleanup;
 248 
 249         if (ret_obj[0].integer.value) {
 250                 status = -EFAULT;
 251                 goto cleanup;
 252         }
 253 
 254         req = ret_obj[1].integer.value;
 255         res = ret_obj[2].integer.value;
 256         if (req) {
 257                 if (res == 0)
 258                         status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
 259                                            "0: Success");
 260                 else if (res == 0xFFFFFFF0)
 261                         status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
 262                                            "0xFFFFFFF0: User Abort");
 263                 else if (res == 0xFFFFFFF1)
 264                         status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
 265                                            "0xFFFFFFF1: BIOS Failure");
 266                 else if (res >= 1 && res <= 0x00000FFF)
 267                         status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
 268                                            req, res, "Corresponding TPM error");
 269                 else
 270                         status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
 271                                            req, res, "Error");
 272         } else {
 273                 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n",
 274                                    req, "No Recent Request");
 275         }
 276 
 277 cleanup:
 278         ACPI_FREE(obj);
 279         return status;
 280 }
 281 
 282 static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
 283                                    u32 end)
 284 {
 285         int i;
 286         u32 ret;
 287         char *str = buf;
 288         union acpi_object *obj, tmp;
 289         union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
 290 
 291         static char *info[] = {
 292                 "Not implemented",
 293                 "BIOS only",
 294                 "Blocked for OS by BIOS",
 295                 "User required",
 296                 "User not required",
 297         };
 298 
 299         if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
 300                             1 << TPM_PPI_FN_GETOPR))
 301                 return -EPERM;
 302 
 303         tmp.integer.type = ACPI_TYPE_INTEGER;
 304         for (i = start; i <= end; i++) {
 305                 tmp.integer.value = i;
 306                 obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
 307                                    ACPI_TYPE_INTEGER, &argv,
 308                                    TPM_PPI_REVISION_ID_1);
 309                 if (!obj) {
 310                         return -ENOMEM;
 311                 } else {
 312                         ret = obj->integer.value;
 313                         ACPI_FREE(obj);
 314                 }
 315 
 316                 if (ret > 0 && ret < ARRAY_SIZE(info))
 317                         str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",
 318                                          i, ret, info[ret]);
 319         }
 320 
 321         return str - buf;
 322 }
 323 
 324 static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
 325                                            struct device_attribute *attr,
 326                                            char *buf)
 327 {
 328         struct tpm_chip *chip = to_tpm_chip(dev);
 329 
 330         return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
 331                                    PPI_TPM_REQ_MAX);
 332 }
 333 
 334 static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
 335                                           struct device_attribute *attr,
 336                                           char *buf)
 337 {
 338         struct tpm_chip *chip = to_tpm_chip(dev);
 339 
 340         return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
 341                                    PPI_VS_REQ_END);
 342 }
 343 
 344 static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
 345 static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP,
 346                    tpm_show_ppi_request, tpm_store_ppi_request);
 347 static DEVICE_ATTR(transition_action, S_IRUGO,
 348                    tpm_show_ppi_transition_action, NULL);
 349 static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL);
 350 static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL);
 351 static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL);
 352 
 353 static struct attribute *ppi_attrs[] = {
 354         &dev_attr_version.attr,
 355         &dev_attr_request.attr,
 356         &dev_attr_transition_action.attr,
 357         &dev_attr_response.attr,
 358         &dev_attr_tcg_operations.attr,
 359         &dev_attr_vs_operations.attr, NULL,
 360 };
 361 static struct attribute_group ppi_attr_grp = {
 362         .name = "ppi",
 363         .attrs = ppi_attrs
 364 };
 365 
 366 void tpm_add_ppi(struct tpm_chip *chip)
 367 {
 368         union acpi_object *obj;
 369 
 370         if (!chip->acpi_dev_handle)
 371                 return;
 372 
 373         if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
 374                             TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION))
 375                 return;
 376 
 377         /* Cache PPI version string. */
 378         obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid,
 379                                       TPM_PPI_REVISION_ID_1,
 380                                       TPM_PPI_FN_VERSION,
 381                                       NULL, ACPI_TYPE_STRING);
 382         if (obj) {
 383                 strlcpy(chip->ppi_version, obj->string.pointer,
 384                         sizeof(chip->ppi_version));
 385                 ACPI_FREE(obj);
 386         }
 387 
 388         chip->groups[chip->groups_cnt++] = &ppi_attr_grp;
 389 }

/* [<][>][^][v][top][bottom][index][help] */