plat_spmd_manifest.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <inttypes.h>
  9. #include <libfdt.h>
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <common/bl_common.h>
  13. #include <common/debug.h>
  14. #include <common/fdt_wrappers.h>
  15. #include <lib/xlat_tables/xlat_tables_v2.h>
  16. #include <platform_def.h>
  17. #include <services/spm_core_manifest.h>
  18. #define ATTRIBUTE_ROOT_NODE_STR "attribute"
  19. /*******************************************************************************
  20. * SPMC attribute node parser
  21. ******************************************************************************/
  22. static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
  23. const void *fdt,
  24. int node)
  25. {
  26. uint32_t val32;
  27. int rc;
  28. assert((attr != NULL) && (fdt != NULL));
  29. rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
  30. if (rc != 0) {
  31. ERROR("Missing FFA %s version in SPM Core manifest.\n",
  32. "major");
  33. return rc;
  34. }
  35. rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
  36. if (rc != 0) {
  37. ERROR("Missing FFA %s version in SPM Core manifest.\n",
  38. "minor");
  39. return rc;
  40. }
  41. rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
  42. if (rc != 0) {
  43. ERROR("Missing SPMC ID in manifest.\n");
  44. return rc;
  45. }
  46. attr->spmc_id = val32 & 0xffff;
  47. rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
  48. if (rc != 0) {
  49. NOTICE("%s not specified in SPM Core manifest.\n",
  50. "Execution state");
  51. }
  52. rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
  53. if (rc != 0) {
  54. NOTICE("%s not specified in SPM Core manifest.\n",
  55. "Binary size");
  56. }
  57. rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
  58. if (rc != 0) {
  59. NOTICE("%s not specified in SPM Core manifest.\n",
  60. "Load address");
  61. }
  62. rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
  63. if (rc != 0) {
  64. NOTICE("%s not specified in SPM Core manifest.\n",
  65. "Entry point");
  66. }
  67. VERBOSE("SPM Core manifest attribute section:\n");
  68. VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version);
  69. VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id);
  70. VERBOSE(" binary_size: 0x%x\n", attr->binary_size);
  71. VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address);
  72. VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint);
  73. return 0;
  74. }
  75. /*******************************************************************************
  76. * Root node handler
  77. ******************************************************************************/
  78. static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
  79. const void *fdt,
  80. int root)
  81. {
  82. int node;
  83. assert(manifest != NULL);
  84. node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
  85. sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
  86. if (node < 0) {
  87. ERROR("Root node doesn't contain subnode '%s'\n",
  88. ATTRIBUTE_ROOT_NODE_STR);
  89. return node;
  90. }
  91. return manifest_parse_attribute(manifest, fdt, node);
  92. }
  93. /*******************************************************************************
  94. * Platform handler to parse a SPM Core manifest.
  95. ******************************************************************************/
  96. int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
  97. const void *pm_addr)
  98. {
  99. int rc, unmap_ret;
  100. uintptr_t pm_base, pm_base_align;
  101. size_t mapped_size;
  102. assert(manifest != NULL);
  103. assert(pm_addr != NULL);
  104. /*
  105. * Assume TOS_FW_CONFIG is not necessarily aligned to a page
  106. * boundary, thus calculate the remaining space between SPMC
  107. * manifest start address and upper page limit.
  108. *
  109. */
  110. pm_base = (uintptr_t)pm_addr;
  111. pm_base_align = page_align(pm_base, UP);
  112. if (pm_base == pm_base_align) {
  113. /* Page aligned */
  114. mapped_size = PAGE_SIZE;
  115. } else {
  116. mapped_size = pm_base_align - pm_base;
  117. }
  118. /* Check space within the page at least maps the FDT header */
  119. if (mapped_size < sizeof(struct fdt_header)) {
  120. ERROR("Error while mapping SPM Core manifest.\n");
  121. return -EINVAL;
  122. }
  123. /* Map first SPMC manifest page in the SPMD translation regime */
  124. pm_base_align = page_align(pm_base, DOWN);
  125. rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
  126. pm_base_align,
  127. PAGE_SIZE,
  128. MT_RO_DATA | EL3_PAS);
  129. if (rc != 0) {
  130. ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
  131. return rc;
  132. }
  133. rc = fdt_check_header(pm_addr);
  134. if (rc != 0) {
  135. ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
  136. goto exit_unmap;
  137. }
  138. /* Check SPMC manifest fits within the upper mapped page boundary */
  139. if (mapped_size < fdt_totalsize(pm_addr)) {
  140. ERROR("SPM Core manifest too large.\n");
  141. rc = -EINVAL;
  142. goto exit_unmap;
  143. }
  144. VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
  145. rc = fdt_node_offset_by_compatible(pm_addr, -1,
  146. "arm,ffa-core-manifest-1.0");
  147. if (rc < 0) {
  148. ERROR("Unrecognized SPM Core manifest\n");
  149. goto exit_unmap;
  150. }
  151. rc = manifest_parse_root(manifest, pm_addr, rc);
  152. exit_unmap:
  153. unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
  154. if (unmap_ret != 0) {
  155. ERROR("Error while unmapping SPM Core manifest (%d).\n",
  156. unmap_ret);
  157. if (rc == 0) {
  158. rc = unmap_ret;
  159. }
  160. }
  161. return rc;
  162. }