tpm_tis_sandbox.c 7.2 KB

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