cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tpm_ppi.c (10780B)


      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}