linux/drivers/char/tpm/tpm_ppi.c
<<
>>
Prefs
   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
  32static const guid_t tpm_ppi_guid =
  33        GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
  34                  0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
  35
  36static bool tpm_ppi_req_has_parameter(u64 req)
  37{
  38        return req == 23;
  39}
  40
  41static inline union acpi_object *
  42tpm_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
  50static 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
  58static 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
 112static 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 {
 153ppi12:
 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
 175static 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
 221static 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
 277cleanup:
 278        ACPI_FREE(obj);
 279        return status;
 280}
 281
 282static 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
 324static 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
 334static 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
 344static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
 345static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP,
 346                   tpm_show_ppi_request, tpm_store_ppi_request);
 347static DEVICE_ATTR(transition_action, S_IRUGO,
 348                   tpm_show_ppi_transition_action, NULL);
 349static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL);
 350static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL);
 351static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL);
 352
 353static 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};
 361static const struct attribute_group ppi_attr_grp = {
 362        .name = "ppi",
 363        .attrs = ppi_attrs
 364};
 365
 366void 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}
 390