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