tpm_tis_sandbox.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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 BACKUP_NV_INDEX 0x1009
  15. #define FWMP_NV_INDEX 0x100a
  16. #define REC_HASH_NV_INDEX 0x100b
  17. #define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE
  18. #define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
  19. /* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
  20. #define ROLLBACK_SPACE_KERNEL_VERSION 2
  21. #define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
  22. struct rollback_space_kernel {
  23. /* Struct version, for backwards compatibility */
  24. uint8_t struct_version;
  25. /* Unique ID to detect space redefinition */
  26. uint32_t uid;
  27. /* Kernel versions */
  28. uint32_t kernel_versions;
  29. /* Reserved for future expansion */
  30. uint8_t reserved[3];
  31. /* Checksum (v2 and later only) */
  32. uint8_t crc8;
  33. } __packed rollback_space_kernel;
  34. /*
  35. * These numbers derive from adding the sizes of command fields as shown in
  36. * the TPM commands manual.
  37. */
  38. #define TPM_REQUEST_HEADER_LENGTH 10
  39. #define TPM_RESPONSE_HEADER_LENGTH 10
  40. /* These are the different non-volatile spaces that we emulate */
  41. enum {
  42. NV_GLOBAL_LOCK,
  43. NV_SEQ_FIRMWARE,
  44. NV_SEQ_KERNEL,
  45. NV_SEQ_BACKUP,
  46. NV_SEQ_FWMP,
  47. NV_SEQ_REC_HASH,
  48. NV_SEQ_COUNT,
  49. };
  50. /* Size of each non-volatile space */
  51. #define NV_DATA_SIZE 0x20
  52. struct nvdata_state {
  53. bool present;
  54. u8 data[NV_DATA_SIZE];
  55. };
  56. /*
  57. * Information about our TPM emulation. This is preserved in the sandbox
  58. * state file if enabled.
  59. */
  60. static struct tpm_state {
  61. bool valid;
  62. struct nvdata_state nvdata[NV_SEQ_COUNT];
  63. } g_state;
  64. /**
  65. * sandbox_tpm_read_state() - read the sandbox EC state from the state file
  66. *
  67. * If data is available, then blob and node will provide access to it. If
  68. * not this function sets up an empty TPM.
  69. *
  70. * @blob: Pointer to device tree blob, or NULL if no data to read
  71. * @node: Node offset to read from
  72. */
  73. static int sandbox_tpm_read_state(const void *blob, int node)
  74. {
  75. const char *prop;
  76. int len;
  77. int i;
  78. if (!blob)
  79. return 0;
  80. for (i = 0; i < NV_SEQ_COUNT; i++) {
  81. char prop_name[20];
  82. sprintf(prop_name, "nvdata%d", i);
  83. prop = fdt_getprop(blob, node, prop_name, &len);
  84. if (prop && len == NV_DATA_SIZE) {
  85. memcpy(g_state.nvdata[i].data, prop, NV_DATA_SIZE);
  86. g_state.nvdata[i].present = true;
  87. }
  88. }
  89. g_state.valid = true;
  90. return 0;
  91. }
  92. /**
  93. * cros_ec_write_state() - Write out our state to the state file
  94. *
  95. * The caller will ensure that there is a node ready for the state. The node
  96. * may already contain the old state, in which case it is overridden.
  97. *
  98. * @blob: Device tree blob holding state
  99. * @node: Node to write our state into
  100. */
  101. static int sandbox_tpm_write_state(void *blob, int node)
  102. {
  103. int i;
  104. /*
  105. * We are guaranteed enough space to write basic properties.
  106. * We could use fdt_add_subnode() to put each set of data in its
  107. * own node - perhaps useful if we add access informaiton to each.
  108. */
  109. for (i = 0; i < NV_SEQ_COUNT; i++) {
  110. char prop_name[20];
  111. if (g_state.nvdata[i].present) {
  112. sprintf(prop_name, "nvdata%d", i);
  113. fdt_setprop(blob, node, prop_name,
  114. g_state.nvdata[i].data, NV_DATA_SIZE);
  115. }
  116. }
  117. return 0;
  118. }
  119. SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
  120. sandbox_tpm_write_state);
  121. static int index_to_seq(uint32_t index)
  122. {
  123. switch (index) {
  124. case FIRMWARE_NV_INDEX:
  125. return NV_SEQ_FIRMWARE;
  126. case KERNEL_NV_INDEX:
  127. return NV_SEQ_KERNEL;
  128. case BACKUP_NV_INDEX:
  129. return NV_SEQ_BACKUP;
  130. case FWMP_NV_INDEX:
  131. return NV_SEQ_FWMP;
  132. case REC_HASH_NV_INDEX:
  133. return NV_SEQ_REC_HASH;
  134. case 0:
  135. return NV_GLOBAL_LOCK;
  136. }
  137. printf("Invalid nv index %#x\n", index);
  138. return -1;
  139. }
  140. static void handle_cap_flag_space(u8 **datap, uint index)
  141. {
  142. struct tpm_nv_data_public pub;
  143. /* TPM_NV_PER_PPWRITE */
  144. memset(&pub, '\0', sizeof(pub));
  145. pub.nv_index = __cpu_to_be32(index);
  146. pub.pcr_info_read.pcr_selection.size_of_select = __cpu_to_be16(
  147. sizeof(pub.pcr_info_read.pcr_selection.pcr_select));
  148. pub.permission.attributes = __cpu_to_be32(1);
  149. pub.pcr_info_write = pub.pcr_info_read;
  150. memcpy(*datap, &pub, sizeof(pub));
  151. *datap += sizeof(pub);
  152. }
  153. static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
  154. size_t send_size, uint8_t *recvbuf,
  155. size_t *recv_len)
  156. {
  157. struct tpm_state *tpm = dev_get_priv(dev);
  158. uint32_t code, index, length, type;
  159. uint8_t *data;
  160. int seq;
  161. code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
  162. sizeof(uint32_t));
  163. printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
  164. *recv_len, code);
  165. print_buffer(0, sendbuf, 1, send_size, 0);
  166. switch (code) {
  167. case TPM_CMD_GET_CAPABILITY:
  168. type = get_unaligned_be32(sendbuf + 14);
  169. switch (type) {
  170. case TPM_CAP_FLAG:
  171. index = get_unaligned_be32(sendbuf + 18);
  172. printf("Get flags index %#02x\n", index);
  173. *recv_len = 22;
  174. memset(recvbuf, '\0', *recv_len);
  175. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  176. sizeof(uint32_t);
  177. switch (index) {
  178. case FIRMWARE_NV_INDEX:
  179. break;
  180. case KERNEL_NV_INDEX:
  181. handle_cap_flag_space(&data, index);
  182. *recv_len = data - recvbuf -
  183. TPM_RESPONSE_HEADER_LENGTH -
  184. sizeof(uint32_t);
  185. break;
  186. case TPM_CAP_FLAG_PERMANENT: {
  187. struct tpm_permanent_flags *pflags;
  188. pflags = (struct tpm_permanent_flags *)data;
  189. memset(pflags, '\0', sizeof(*pflags));
  190. put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS,
  191. &pflags->tag);
  192. *recv_len = TPM_HEADER_SIZE + 4 +
  193. sizeof(*pflags);
  194. break;
  195. }
  196. default:
  197. printf(" ** Unknown flags index %x\n", index);
  198. return -ENOSYS;
  199. }
  200. put_unaligned_be32(*recv_len,
  201. recvbuf +
  202. TPM_RESPONSE_HEADER_LENGTH);
  203. break;
  204. case TPM_CAP_NV_INDEX:
  205. index = get_unaligned_be32(sendbuf + 18);
  206. printf("Get cap nv index %#02x\n", index);
  207. put_unaligned_be32(22, recvbuf +
  208. TPM_RESPONSE_HEADER_LENGTH);
  209. break;
  210. default:
  211. printf(" ** Unknown 0x65 command type %#02x\n",
  212. type);
  213. return -ENOSYS;
  214. }
  215. break;
  216. case TPM_CMD_NV_WRITE_VALUE:
  217. index = get_unaligned_be32(sendbuf + 10);
  218. length = get_unaligned_be32(sendbuf + 18);
  219. seq = index_to_seq(index);
  220. if (seq < 0)
  221. return -EINVAL;
  222. printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
  223. memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
  224. tpm->nvdata[seq].present = true;
  225. *recv_len = 12;
  226. memset(recvbuf, '\0', *recv_len);
  227. break;
  228. case TPM_CMD_NV_READ_VALUE: /* nvread */
  229. index = get_unaligned_be32(sendbuf + 10);
  230. length = get_unaligned_be32(sendbuf + 18);
  231. seq = index_to_seq(index);
  232. if (seq < 0)
  233. return -EINVAL;
  234. printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
  235. length, seq);
  236. *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
  237. length;
  238. memset(recvbuf, '\0', *recv_len);
  239. put_unaligned_be32(length, recvbuf +
  240. TPM_RESPONSE_HEADER_LENGTH);
  241. if (seq == NV_SEQ_KERNEL) {
  242. struct rollback_space_kernel rsk;
  243. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  244. sizeof(uint32_t);
  245. memset(&rsk, 0, sizeof(struct rollback_space_kernel));
  246. rsk.struct_version = 2;
  247. rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
  248. rsk.crc8 = crc8(0, (unsigned char *)&rsk,
  249. offsetof(struct rollback_space_kernel,
  250. crc8));
  251. memcpy(data, &rsk, sizeof(rsk));
  252. } else if (!tpm->nvdata[seq].present) {
  253. put_unaligned_be32(TPM_BADINDEX, recvbuf +
  254. sizeof(uint16_t) + sizeof(uint32_t));
  255. } else {
  256. memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  257. sizeof(uint32_t), &tpm->nvdata[seq].data,
  258. length);
  259. }
  260. break;
  261. case TPM_CMD_EXTEND:
  262. *recv_len = 30;
  263. memset(recvbuf, '\0', *recv_len);
  264. break;
  265. case TPM_CMD_NV_DEFINE_SPACE:
  266. case 0x15: /* pcr read */
  267. case 0x5d: /* force clear */
  268. case 0x6f: /* physical enable */
  269. case 0x72: /* physical set deactivated */
  270. case 0x99: /* startup */
  271. case 0x50: /* self test full */
  272. case 0x4000000a: /* assert physical presence */
  273. *recv_len = 12;
  274. memset(recvbuf, '\0', *recv_len);
  275. break;
  276. default:
  277. printf("Unknown tpm command %02x\n", code);
  278. return -ENOSYS;
  279. }
  280. return 0;
  281. }
  282. static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
  283. {
  284. if (size < 15)
  285. return -ENOSPC;
  286. return snprintf(buf, size, "sandbox TPM");
  287. }
  288. static int sandbox_tpm_probe(struct udevice *dev)
  289. {
  290. struct tpm_state *tpm = dev_get_priv(dev);
  291. memcpy(tpm, &g_state, sizeof(*tpm));
  292. return 0;
  293. }
  294. static int sandbox_tpm_open(struct udevice *dev)
  295. {
  296. return 0;
  297. }
  298. static int sandbox_tpm_close(struct udevice *dev)
  299. {
  300. return 0;
  301. }
  302. static const struct tpm_ops sandbox_tpm_ops = {
  303. .open = sandbox_tpm_open,
  304. .close = sandbox_tpm_close,
  305. .get_desc = sandbox_tpm_get_desc,
  306. .xfer = sandbox_tpm_xfer,
  307. };
  308. static const struct udevice_id sandbox_tpm_ids[] = {
  309. { .compatible = "google,sandbox-tpm" },
  310. { }
  311. };
  312. U_BOOT_DRIVER(sandbox_tpm) = {
  313. .name = "sandbox_tpm",
  314. .id = UCLASS_TPM,
  315. .of_match = sandbox_tpm_ids,
  316. .ops = &sandbox_tpm_ops,
  317. .probe = sandbox_tpm_probe,
  318. .priv_auto_alloc_size = sizeof(struct tpm_state),
  319. };