optee.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2017 Linaro
  4. * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
  5. */
  6. #include <common.h>
  7. #include <fdtdec.h>
  8. #include <image.h>
  9. #include <log.h>
  10. #include <malloc.h>
  11. #include <dm/ofnode.h>
  12. #include <linux/ioport.h>
  13. #include <linux/libfdt.h>
  14. #include <tee/optee.h>
  15. #define optee_hdr_err_msg \
  16. "OPTEE verification error:" \
  17. "\n\thdr=%p image=0x%08lx magic=0x%08x tzdram 0x%08lx-0x%08lx " \
  18. "\n\theader lo=0x%08x hi=0x%08x size=0x%08lx arch=0x%08x" \
  19. "\n\tuimage params 0x%08lx-0x%08lx\n"
  20. int optee_verify_image(struct optee_header *hdr, unsigned long tzdram_start,
  21. unsigned long tzdram_len, unsigned long image_len)
  22. {
  23. unsigned long tzdram_end = tzdram_start + tzdram_len;
  24. uint32_t tee_file_size;
  25. tee_file_size = hdr->init_size + hdr->paged_size +
  26. sizeof(struct optee_header);
  27. if (hdr->magic != OPTEE_MAGIC ||
  28. hdr->version != OPTEE_VERSION ||
  29. hdr->init_load_addr_hi > tzdram_end ||
  30. hdr->init_load_addr_lo < tzdram_start ||
  31. tee_file_size > tzdram_len ||
  32. tee_file_size != image_len ||
  33. (hdr->init_load_addr_lo + tee_file_size) > tzdram_end) {
  34. return -EINVAL;
  35. }
  36. return 0;
  37. }
  38. int optee_verify_bootm_image(unsigned long image_addr,
  39. unsigned long image_load_addr,
  40. unsigned long image_len)
  41. {
  42. struct optee_header *hdr = (struct optee_header *)image_addr;
  43. unsigned long tzdram_start = CONFIG_OPTEE_TZDRAM_BASE;
  44. unsigned long tzdram_len = CONFIG_OPTEE_TZDRAM_SIZE;
  45. int ret;
  46. ret = optee_verify_image(hdr, tzdram_start, tzdram_len, image_len);
  47. if (ret)
  48. goto error;
  49. if (image_load_addr + sizeof(*hdr) != hdr->init_load_addr_lo) {
  50. ret = -EINVAL;
  51. goto error;
  52. }
  53. return ret;
  54. error:
  55. printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic, tzdram_start,
  56. tzdram_start + tzdram_len, hdr->init_load_addr_lo,
  57. hdr->init_load_addr_hi, image_len, hdr->arch, image_load_addr,
  58. image_load_addr + image_len);
  59. return ret;
  60. }
  61. #if defined(CONFIG_OF_LIBFDT)
  62. static int optee_copy_firmware_node(ofnode node, void *fdt_blob)
  63. {
  64. int offs, ret, len;
  65. const void *prop;
  66. offs = fdt_path_offset(fdt_blob, "/firmware");
  67. if (offs < 0) {
  68. offs = fdt_path_offset(fdt_blob, "/");
  69. if (offs < 0)
  70. return offs;
  71. offs = fdt_add_subnode(fdt_blob, offs, "firmware");
  72. if (offs < 0)
  73. return offs;
  74. }
  75. offs = fdt_add_subnode(fdt_blob, offs, "optee");
  76. if (offs < 0)
  77. return offs;
  78. /* copy the compatible property */
  79. prop = ofnode_get_property(node, "compatible", &len);
  80. if (!prop) {
  81. debug("missing OP-TEE compatible property");
  82. return -EINVAL;
  83. }
  84. ret = fdt_setprop(fdt_blob, offs, "compatible", prop, len);
  85. if (ret < 0)
  86. return ret;
  87. /* copy the method property */
  88. prop = ofnode_get_property(node, "method", &len);
  89. if (!prop) {
  90. debug("missing OP-TEE method property");
  91. return -EINVAL;
  92. }
  93. ret = fdt_setprop(fdt_blob, offs, "method", prop, len);
  94. if (ret < 0)
  95. return ret;
  96. return 0;
  97. }
  98. int optee_copy_fdt_nodes(void *new_blob)
  99. {
  100. ofnode node, subnode;
  101. int ret;
  102. struct resource res;
  103. if (fdt_check_header(new_blob))
  104. return -EINVAL;
  105. /* only proceed if there is an /firmware/optee node */
  106. node = ofnode_path("/firmware/optee");
  107. if (!ofnode_valid(node)) {
  108. debug("No OP-TEE firmware node in old fdt, nothing to do");
  109. return 0;
  110. }
  111. /*
  112. * Do not proceed if the target dt already has an OP-TEE node.
  113. * In this case assume that the system knows better somehow,
  114. * so do not interfere.
  115. */
  116. if (fdt_path_offset(new_blob, "/firmware/optee") >= 0) {
  117. debug("OP-TEE Device Tree node already exists in target");
  118. return 0;
  119. }
  120. ret = optee_copy_firmware_node(node, new_blob);
  121. if (ret < 0) {
  122. printf("Failed to add OP-TEE firmware node\n");
  123. return ret;
  124. }
  125. /* optee inserts its memory regions as reserved-memory nodes */
  126. node = ofnode_path("/reserved-memory");
  127. if (ofnode_valid(node)) {
  128. ofnode_for_each_subnode(subnode, node) {
  129. const char *name = ofnode_get_name(subnode);
  130. if (!name)
  131. return -EINVAL;
  132. /* only handle optee reservations */
  133. if (strncmp(name, "optee", 5))
  134. continue;
  135. /* check if this subnode has a reg property */
  136. ret = ofnode_read_resource(subnode, 0, &res);
  137. if (!ret) {
  138. struct fdt_memory carveout = {
  139. .start = res.start,
  140. .end = res.end,
  141. };
  142. char *oldname, *nodename, *tmp;
  143. oldname = strdup(name);
  144. if (!oldname)
  145. return -ENOMEM;
  146. tmp = oldname;
  147. nodename = strsep(&tmp, "@");
  148. if (!nodename) {
  149. free(oldname);
  150. return -EINVAL;
  151. }
  152. ret = fdtdec_add_reserved_memory(new_blob,
  153. nodename,
  154. &carveout,
  155. NULL, true);
  156. free(oldname);
  157. if (ret < 0)
  158. return ret;
  159. }
  160. }
  161. }
  162. return 0;
  163. }
  164. #endif