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 35 static 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 43 static inline union acpi_object * 44 tpm_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 53 static ssize_t tpm_show_ppi_version(struct device *dev, 54 struct device_attribute *attr, char *buf) 55 { 56 struct tpm_chip *chip = dev_get_drvdata(dev); 57 58 return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); 59 } 60 61 static 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 = dev_get_drvdata(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 94 static 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 = dev_get_drvdata(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 147 static 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 = dev_get_drvdata(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 193 static 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 = dev_get_drvdata(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 249 cleanup: 250 ACPI_FREE(obj); 251 return status; 252 } 253 254 static 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 295 static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 296 struct device_attribute *attr, 297 char *buf) 298 { 299 struct tpm_chip *chip = dev_get_drvdata(dev); 300 301 return show_ppi_operations(chip->acpi_dev_handle, buf, 0, 302 PPI_TPM_REQ_MAX); 303 } 304 305 static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 306 struct device_attribute *attr, 307 char *buf) 308 { 309 struct tpm_chip *chip = dev_get_drvdata(dev); 310 311 return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, 312 PPI_VS_REQ_END); 313 } 314 315 static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 316 static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 317 tpm_show_ppi_request, tpm_store_ppi_request); 318 static DEVICE_ATTR(transition_action, S_IRUGO, 319 tpm_show_ppi_transition_action, NULL); 320 static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 321 static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 322 static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 323 324 static 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 }; 332 static struct attribute_group ppi_attr_grp = { 333 .name = "ppi", 334 .attrs = ppi_attrs 335 }; 336 337 int tpm_add_ppi(struct tpm_chip *chip) 338 { 339 union acpi_object *obj; 340 int rc; 341 342 if (!chip->acpi_dev_handle) 343 return 0; 344 345 if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, 346 TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) 347 return 0; 348 349 /* Cache PPI version string. */ 350 obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid, 351 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, 352 NULL, ACPI_TYPE_STRING); 353 if (obj) { 354 strlcpy(chip->ppi_version, obj->string.pointer, 355 sizeof(chip->ppi_version)); 356 ACPI_FREE(obj); 357 } 358 359 rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp); 360 361 if (!rc) 362 chip->flags |= TPM_CHIP_FLAG_PPI; 363 364 return rc; 365 } 366 367 void tpm_remove_ppi(struct tpm_chip *chip) 368 { 369 if (chip->flags & TPM_CHIP_FLAG_PPI) 370 sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp); 371 } 372