tpm_ppi.c 9.5 KB

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