tpm_ppi.c 13 KB

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