tpm_ppi.c 9.5 KB

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