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