optee.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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" \
  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. #if defined(CONFIG_OPTEE_IMAGE)
  21. static int optee_verify_image(struct optee_header *hdr, unsigned long image_len)
  22. {
  23. uint32_t tee_file_size;
  24. tee_file_size = hdr->init_size + hdr->paged_size +
  25. sizeof(struct optee_header);
  26. if (hdr->magic != OPTEE_MAGIC ||
  27. hdr->version != OPTEE_VERSION ||
  28. tee_file_size != image_len) {
  29. return -EINVAL;
  30. }
  31. return 0;
  32. }
  33. int optee_verify_bootm_image(unsigned long image_addr,
  34. unsigned long image_load_addr,
  35. unsigned long image_len)
  36. {
  37. struct optee_header *hdr = (struct optee_header *)image_addr;
  38. int ret;
  39. ret = optee_verify_image(hdr, image_len);
  40. if (ret)
  41. goto error;
  42. if (image_load_addr + sizeof(*hdr) != hdr->init_load_addr_lo) {
  43. ret = -EINVAL;
  44. goto error;
  45. }
  46. return ret;
  47. error:
  48. printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic,
  49. hdr->init_load_addr_lo,
  50. hdr->init_load_addr_hi, image_len, hdr->arch, image_load_addr,
  51. image_load_addr + image_len);
  52. return ret;
  53. }
  54. #endif
  55. #if defined(CONFIG_OF_LIBFDT)
  56. static int optee_copy_firmware_node(ofnode node, void *fdt_blob)
  57. {
  58. int offs, ret, len;
  59. const void *prop;
  60. offs = fdt_path_offset(fdt_blob, "/firmware");
  61. if (offs < 0) {
  62. offs = fdt_path_offset(fdt_blob, "/");
  63. if (offs < 0)
  64. return offs;
  65. offs = fdt_add_subnode(fdt_blob, offs, "firmware");
  66. if (offs < 0)
  67. return offs;
  68. }
  69. offs = fdt_add_subnode(fdt_blob, offs, "optee");
  70. if (offs < 0)
  71. return offs;
  72. /* copy the compatible property */
  73. prop = ofnode_get_property(node, "compatible", &len);
  74. if (!prop) {
  75. debug("missing OP-TEE compatible property");
  76. return -EINVAL;
  77. }
  78. ret = fdt_setprop(fdt_blob, offs, "compatible", prop, len);
  79. if (ret < 0)
  80. return ret;
  81. /* copy the method property */
  82. prop = ofnode_get_property(node, "method", &len);
  83. if (!prop) {
  84. debug("missing OP-TEE method property");
  85. return -EINVAL;
  86. }
  87. ret = fdt_setprop(fdt_blob, offs, "method", prop, len);
  88. if (ret < 0)
  89. return ret;
  90. return 0;
  91. }
  92. int optee_copy_fdt_nodes(void *new_blob)
  93. {
  94. ofnode node, subnode;
  95. int ret;
  96. struct resource res;
  97. if (fdt_check_header(new_blob))
  98. return -EINVAL;
  99. /* only proceed if there is an /firmware/optee node */
  100. node = ofnode_path("/firmware/optee");
  101. if (!ofnode_valid(node)) {
  102. debug("No OP-TEE firmware node in old fdt, nothing to do");
  103. return 0;
  104. }
  105. /*
  106. * Do not proceed if the target dt already has an OP-TEE node.
  107. * In this case assume that the system knows better somehow,
  108. * so do not interfere.
  109. */
  110. if (fdt_path_offset(new_blob, "/firmware/optee") >= 0) {
  111. debug("OP-TEE Device Tree node already exists in target");
  112. return 0;
  113. }
  114. ret = optee_copy_firmware_node(node, new_blob);
  115. if (ret < 0) {
  116. printf("Failed to add OP-TEE firmware node\n");
  117. return ret;
  118. }
  119. /* optee inserts its memory regions as reserved-memory nodes */
  120. node = ofnode_path("/reserved-memory");
  121. if (ofnode_valid(node)) {
  122. ofnode_for_each_subnode(subnode, node) {
  123. const char *name = ofnode_get_name(subnode);
  124. if (!name)
  125. return -EINVAL;
  126. /* only handle optee reservations */
  127. if (strncmp(name, "optee", 5))
  128. continue;
  129. /* check if this subnode has a reg property */
  130. ret = ofnode_read_resource(subnode, 0, &res);
  131. if (!ret) {
  132. struct fdt_memory carveout = {
  133. .start = res.start,
  134. .end = res.end,
  135. };
  136. unsigned long flags = FDTDEC_RESERVED_MEMORY_NO_MAP;
  137. char *oldname, *nodename, *tmp;
  138. oldname = strdup(name);
  139. if (!oldname)
  140. return -ENOMEM;
  141. tmp = oldname;
  142. nodename = strsep(&tmp, "@");
  143. if (!nodename) {
  144. free(oldname);
  145. return -EINVAL;
  146. }
  147. ret = fdtdec_add_reserved_memory(new_blob,
  148. nodename,
  149. &carveout,
  150. NULL, 0,
  151. NULL, flags);
  152. free(oldname);
  153. if (ret < 0)
  154. return ret;
  155. }
  156. }
  157. }
  158. return 0;
  159. }
  160. #endif