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