tpm_tis_sandbox.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 <u-boot/crc.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. #ifdef DEBUG
  164. printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
  165. *recv_len, code);
  166. print_buffer(0, sendbuf, 1, send_size, 0);
  167. #endif
  168. switch (code) {
  169. case TPM_CMD_GET_CAPABILITY:
  170. type = get_unaligned_be32(sendbuf + 14);
  171. switch (type) {
  172. case TPM_CAP_FLAG:
  173. index = get_unaligned_be32(sendbuf + 18);
  174. printf("Get flags index %#02x\n", index);
  175. *recv_len = 22;
  176. memset(recvbuf, '\0', *recv_len);
  177. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  178. sizeof(uint32_t);
  179. switch (index) {
  180. case FIRMWARE_NV_INDEX:
  181. break;
  182. case KERNEL_NV_INDEX:
  183. handle_cap_flag_space(&data, index);
  184. *recv_len = data - recvbuf -
  185. TPM_RESPONSE_HEADER_LENGTH -
  186. sizeof(uint32_t);
  187. break;
  188. case TPM_CAP_FLAG_PERMANENT: {
  189. struct tpm_permanent_flags *pflags;
  190. pflags = (struct tpm_permanent_flags *)data;
  191. memset(pflags, '\0', sizeof(*pflags));
  192. put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS,
  193. &pflags->tag);
  194. *recv_len = TPM_HEADER_SIZE + 4 +
  195. sizeof(*pflags);
  196. break;
  197. }
  198. default:
  199. printf(" ** Unknown flags index %x\n", index);
  200. return -ENOSYS;
  201. }
  202. put_unaligned_be32(*recv_len,
  203. recvbuf +
  204. TPM_RESPONSE_HEADER_LENGTH);
  205. break;
  206. case TPM_CAP_NV_INDEX:
  207. index = get_unaligned_be32(sendbuf + 18);
  208. printf("Get cap nv index %#02x\n", index);
  209. put_unaligned_be32(22, recvbuf +
  210. TPM_RESPONSE_HEADER_LENGTH);
  211. break;
  212. default:
  213. printf(" ** Unknown 0x65 command type %#02x\n",
  214. type);
  215. return -ENOSYS;
  216. }
  217. break;
  218. case TPM_CMD_NV_WRITE_VALUE:
  219. index = get_unaligned_be32(sendbuf + 10);
  220. length = get_unaligned_be32(sendbuf + 18);
  221. seq = index_to_seq(index);
  222. if (seq < 0)
  223. return -EINVAL;
  224. printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
  225. memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
  226. tpm->nvdata[seq].present = true;
  227. *recv_len = 12;
  228. memset(recvbuf, '\0', *recv_len);
  229. break;
  230. case TPM_CMD_NV_READ_VALUE: /* nvread */
  231. index = get_unaligned_be32(sendbuf + 10);
  232. length = get_unaligned_be32(sendbuf + 18);
  233. seq = index_to_seq(index);
  234. if (seq < 0)
  235. return -EINVAL;
  236. printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
  237. length, seq);
  238. *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
  239. length;
  240. memset(recvbuf, '\0', *recv_len);
  241. put_unaligned_be32(length, recvbuf +
  242. TPM_RESPONSE_HEADER_LENGTH);
  243. if (seq == NV_SEQ_KERNEL) {
  244. struct rollback_space_kernel rsk;
  245. data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  246. sizeof(uint32_t);
  247. memset(&rsk, 0, sizeof(struct rollback_space_kernel));
  248. rsk.struct_version = 2;
  249. rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
  250. rsk.crc8 = crc8(0, (unsigned char *)&rsk,
  251. offsetof(struct rollback_space_kernel,
  252. crc8));
  253. memcpy(data, &rsk, sizeof(rsk));
  254. } else if (!tpm->nvdata[seq].present) {
  255. put_unaligned_be32(TPM_BADINDEX, recvbuf +
  256. sizeof(uint16_t) + sizeof(uint32_t));
  257. } else {
  258. memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
  259. sizeof(uint32_t), &tpm->nvdata[seq].data,
  260. length);
  261. }
  262. break;
  263. case TPM_CMD_EXTEND:
  264. *recv_len = 30;
  265. memset(recvbuf, '\0', *recv_len);
  266. break;
  267. case TPM_CMD_NV_DEFINE_SPACE:
  268. case 0x15: /* pcr read */
  269. case 0x5d: /* force clear */
  270. case 0x6f: /* physical enable */
  271. case 0x72: /* physical set deactivated */
  272. case 0x99: /* startup */
  273. case 0x50: /* self test full */
  274. case 0x4000000a: /* assert physical presence */
  275. *recv_len = 12;
  276. memset(recvbuf, '\0', *recv_len);
  277. break;
  278. default:
  279. printf("Unknown tpm command %02x\n", code);
  280. return -ENOSYS;
  281. }
  282. #ifdef DEBUG
  283. printf("tpm: rx recv_len %zd\n", *recv_len);
  284. print_buffer(0, recvbuf, 1, *recv_len, 0);
  285. #endif
  286. return 0;
  287. }
  288. static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
  289. {
  290. if (size < 15)
  291. return -ENOSPC;
  292. return snprintf(buf, size, "sandbox TPM");
  293. }
  294. static int sandbox_tpm_probe(struct udevice *dev)
  295. {
  296. struct tpm_state *tpm = dev_get_priv(dev);
  297. memcpy(tpm, &g_state, sizeof(*tpm));
  298. return 0;
  299. }
  300. static int sandbox_tpm_open(struct udevice *dev)
  301. {
  302. return 0;
  303. }
  304. static int sandbox_tpm_close(struct udevice *dev)
  305. {
  306. return 0;
  307. }
  308. static const struct tpm_ops sandbox_tpm_ops = {
  309. .open = sandbox_tpm_open,
  310. .close = sandbox_tpm_close,
  311. .get_desc = sandbox_tpm_get_desc,
  312. .xfer = sandbox_tpm_xfer,
  313. };
  314. static const struct udevice_id sandbox_tpm_ids[] = {
  315. { .compatible = "google,sandbox-tpm" },
  316. { }
  317. };
  318. U_BOOT_DRIVER(google_sandbox_tpm) = {
  319. .name = "google_sandbox_tpm",
  320. .id = UCLASS_TPM,
  321. .of_match = sandbox_tpm_ids,
  322. .ops = &sandbox_tpm_ops,
  323. .probe = sandbox_tpm_probe,
  324. .priv_auto_alloc_size = sizeof(struct tpm_state),
  325. };