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