tpm_tis_sandbox.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. * Copyright (c) 2013 Google, Inc
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <tpm.h>
  9. #include <asm/state.h>
  10. #include <asm/unaligned.h>
  11. #include <linux/crc8.h>
  12. /* TPM NVRAM location indices. */
  13. #define FIRMWARE_NV_INDEX 0x1007
  14. #define KERNEL_NV_INDEX 0x1008
  15. #define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
  16. /* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
  17. #define ROLLBACK_SPACE_KERNEL_VERSION 2
  18. #define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
  19. struct rollback_space_kernel {
  20. /* Struct version, for backwards compatibility */
  21. uint8_t struct_version;
  22. /* Unique ID to detect space redefinition */
  23. uint32_t uid;
  24. /* Kernel versions */
  25. uint32_t kernel_versions;
  26. /* Reserved for future expansion */
  27. uint8_t reserved[3];
  28. /* Checksum (v2 and later only) */
  29. uint8_t crc8;
  30. } __packed rollback_space_kernel;
  31. /*
  32. * These numbers derive from adding the sizes of command fields as shown in
  33. * the TPM commands manual.
  34. */
  35. #define TPM_REQUEST_HEADER_LENGTH 10
  36. #define TPM_RESPONSE_HEADER_LENGTH 10
  37. /* These are the different non-volatile spaces that we emulate */
  38. enum {
  39. NV_GLOBAL_LOCK,
  40. NV_SEQ_FIRMWARE,
  41. NV_SEQ_KERNEL,
  42. NV_SEQ_COUNT,
  43. };
  44. /* Size of each non-volatile space */
  45. #define NV_DATA_SIZE 0x20
  46. /*
  47. * Information about our TPM emulation. This is preserved in the sandbox
  48. * state file if enabled.
  49. */
  50. static struct tpm_state {
  51. uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
  52. } g_state;
  53. /**
  54. * sandbox_tpm_read_state() - read the sandbox EC state from the state file
  55. *
  56. * If data is available, then blob and node will provide access to it. If
  57. * not this function sets up an empty TPM.
  58. *
  59. * @blob: Pointer to device tree blob, or NULL if no data to read
  60. * @node: Node offset to read from
  61. */
  62. static int sandbox_tpm_read_state(const void *blob, int node)
  63. {
  64. const char *prop;
  65. int len;
  66. int i;
  67. if (!blob)
  68. return 0;
  69. for (i = 0; i < NV_SEQ_COUNT; i++) {
  70. char prop_name[20];
  71. sprintf(prop_name, "nvdata%d", i);
  72. prop = fdt_getprop(blob, node, prop_name, &len);
  73. if (prop && len == NV_DATA_SIZE)
  74. memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
  75. }
  76. return 0;
  77. }
  78. /**
  79. * cros_ec_write_state() - Write out our state to the state file
  80. *
  81. * The caller will ensure that there is a node ready for the state. The node
  82. * may already contain the old state, in which case it is overridden.
  83. *
  84. * @blob: Device tree blob holding state
  85. * @node: Node to write our state into
  86. */
  87. static int sandbox_tpm_write_state(void *blob, int node)
  88. {
  89. int i;
  90. /*
  91. * We are guaranteed enough space to write basic properties.
  92. * We could use fdt_add_subnode() to put each set of data in its
  93. * own node - perhaps useful if we add access informaiton to each.
  94. */
  95. for (i = 0; i < NV_SEQ_COUNT; i++) {
  96. char prop_name[20];
  97. sprintf(prop_name, "nvdata%d", i);
  98. fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
  99. NV_DATA_SIZE);
  100. }
  101. return 0;
  102. }
  103. SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
  104. sandbox_tpm_write_state);
  105. static int index_to_seq(uint32_t index)
  106. {
  107. switch (index) {
  108. case FIRMWARE_NV_INDEX:
  109. return NV_SEQ_FIRMWARE;
  110. case KERNEL_NV_INDEX:
  111. return NV_SEQ_KERNEL;
  112. case 0:
  113. return NV_GLOBAL_LOCK;
  114. }
  115. printf("Invalid nv index %#x\n", index);
  116. return -1;
  117. }
  118. static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
  119. size_t send_size, uint8_t *recvbuf,
  120. size_t *recv_len)
  121. {
  122. struct tpm_state *tpm = dev_get_priv(dev);
  123. uint32_t code, index, length, type;
  124. uint8_t *data;
  125. int seq;
  126. code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
  127. sizeof(uint32_t));
  128. printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
  129. *recv_len, code);
  130. print_buffer(0, sendbuf, 1, send_size, 0);
  131. switch (code) {
  132. case 0x65: /* get flags */
  133. type = get_unaligned_be32(sendbuf + 14);
  134. switch (type) {
  135. case 4:
  136. index = get_unaligned_be32(sendbuf + 18);
  137. printf("Get flags index %#02x\n", index);
  138. *recv_len = 22;
  139. memset(recvbuf, '\0', *recv_len);
  140. put_unaligned_be32(22, recvbuf +
  141. TPM_RESPONSE_HEADER_LENGTH);
  142. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  143. sizeof(uint32_t);
  144. switch (index) {
  145. case FIRMWARE_NV_INDEX:
  146. break;
  147. case KERNEL_NV_INDEX:
  148. /* TPM_NV_PER_PPWRITE */
  149. put_unaligned_be32(1, data +
  150. NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
  151. break;
  152. }
  153. break;
  154. case 0x11: /* TPM_CAP_NV_INDEX */
  155. index = get_unaligned_be32(sendbuf + 18);
  156. printf("Get cap nv index %#02x\n", index);
  157. put_unaligned_be32(22, recvbuf +
  158. TPM_RESPONSE_HEADER_LENGTH);
  159. break;
  160. default:
  161. printf(" ** Unknown 0x65 command type %#02x\n",
  162. type);
  163. return -1;
  164. }
  165. break;
  166. case 0xcd: /* nvwrite */
  167. index = get_unaligned_be32(sendbuf + 10);
  168. length = get_unaligned_be32(sendbuf + 18);
  169. seq = index_to_seq(index);
  170. if (seq < 0)
  171. return -1;
  172. printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
  173. memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
  174. *recv_len = 12;
  175. memset(recvbuf, '\0', *recv_len);
  176. break;
  177. case 0xcf: /* nvread */
  178. index = get_unaligned_be32(sendbuf + 10);
  179. length = get_unaligned_be32(sendbuf + 18);
  180. seq = index_to_seq(index);
  181. if (seq < 0)
  182. return -1;
  183. printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
  184. *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
  185. length;
  186. memset(recvbuf, '\0', *recv_len);
  187. put_unaligned_be32(length, recvbuf +
  188. TPM_RESPONSE_HEADER_LENGTH);
  189. if (seq == NV_SEQ_KERNEL) {
  190. struct rollback_space_kernel rsk;
  191. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  192. sizeof(uint32_t);
  193. memset(&rsk, 0, sizeof(struct rollback_space_kernel));
  194. rsk.struct_version = 2;
  195. rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
  196. rsk.crc8 = crc8(0, (unsigned char *)&rsk,
  197. offsetof(struct rollback_space_kernel,
  198. crc8));
  199. memcpy(data, &rsk, sizeof(rsk));
  200. } else {
  201. memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  202. sizeof(uint32_t), &tpm->nvdata[seq], length);
  203. }
  204. break;
  205. case 0x14: /* tpm extend */
  206. case 0x15: /* pcr read */
  207. case 0x5d: /* force clear */
  208. case 0x6f: /* physical enable */
  209. case 0x72: /* physical set deactivated */
  210. case 0x99: /* startup */
  211. case 0x4000000a: /* assert physical presence */
  212. *recv_len = 12;
  213. memset(recvbuf, '\0', *recv_len);
  214. break;
  215. default:
  216. printf("Unknown tpm command %02x\n", code);
  217. return -1;
  218. }
  219. return 0;
  220. }
  221. static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
  222. {
  223. if (size < 15)
  224. return -ENOSPC;
  225. return snprintf(buf, size, "sandbox TPM");
  226. }
  227. static int sandbox_tpm_probe(struct udevice *dev)
  228. {
  229. struct tpm_state *tpm = dev_get_priv(dev);
  230. memcpy(tpm, &g_state, sizeof(*tpm));
  231. return 0;
  232. }
  233. static int sandbox_tpm_open(struct udevice *dev)
  234. {
  235. return 0;
  236. }
  237. static int sandbox_tpm_close(struct udevice *dev)
  238. {
  239. return 0;
  240. }
  241. static const struct tpm_ops sandbox_tpm_ops = {
  242. .open = sandbox_tpm_open,
  243. .close = sandbox_tpm_close,
  244. .get_desc = sandbox_tpm_get_desc,
  245. .xfer = sandbox_tpm_xfer,
  246. };
  247. static const struct udevice_id sandbox_tpm_ids[] = {
  248. { .compatible = "google,sandbox-tpm" },
  249. { }
  250. };
  251. U_BOOT_DRIVER(sandbox_tpm) = {
  252. .name = "sandbox_tpm",
  253. .id = UCLASS_TPM,
  254. .of_match = sandbox_tpm_ids,
  255. .ops = &sandbox_tpm_ops,
  256. .probe = sandbox_tpm_probe,
  257. .priv_auto_alloc_size = sizeof(struct tpm_state),
  258. };