arm_dyn_cfg_helpers.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <common/debug.h>
  8. #if MEASURED_BOOT
  9. #include <common/desc_image_load.h>
  10. #endif
  11. #include <common/fdt_wrappers.h>
  12. #include <lib/fconf/fconf.h>
  13. #include <lib/fconf/fconf_dyn_cfg_getter.h>
  14. #include <libfdt.h>
  15. #include <plat/arm/common/arm_dyn_cfg_helpers.h>
  16. #include <plat/arm/common/plat_arm.h>
  17. #define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
  18. #define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
  19. #if MEASURED_BOOT
  20. #ifdef SPD_opteed
  21. /*
  22. * Currently OP-TEE does not support reading DTBs from Secure memory
  23. * and this property should be removed when this feature is supported.
  24. */
  25. #define DTB_PROP_HW_SM_LOG_ADDR "tpm_event_log_sm_addr"
  26. #endif /* SPD_opteed */
  27. #define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr"
  28. #define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size"
  29. #define DTB_PROP_HW_LOG_MAX_SIZE "tpm_event_log_max_size"
  30. #endif /* MEASURED_BOOT */
  31. static size_t event_log_max_size __unused;
  32. /*******************************************************************************
  33. * Validate the tb_fw_config is a valid DTB file and returns the node offset
  34. * to "arm,tb_fw" property.
  35. * Arguments:
  36. * void *dtb - pointer to the TB_FW_CONFIG in memory
  37. * int *node - Returns the node offset to "arm,tb_fw" property if found.
  38. *
  39. * Returns 0 on success and -1 on error.
  40. ******************************************************************************/
  41. int arm_dyn_tb_fw_cfg_init(void *dtb, int *node)
  42. {
  43. assert(dtb != NULL);
  44. assert(node != NULL);
  45. /* Check if the pointer to DT is correct */
  46. if (fdt_check_header(dtb) != 0) {
  47. WARN("Invalid DTB file passed as%s\n", " TB_FW_CONFIG");
  48. return -1;
  49. }
  50. /* Assert the node offset point to "arm,tb_fw" compatible property */
  51. *node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw");
  52. if (*node < 0) {
  53. WARN("The compatible property '%s' not%s", "arm,tb_fw",
  54. " found in the config\n");
  55. return -1;
  56. }
  57. VERBOSE("Dyn cfg: '%s'%s", "arm,tb_fw", " found in the config\n");
  58. return 0;
  59. }
  60. /*
  61. * This function writes the Mbed TLS heap address and size in the DTB. When it
  62. * is called, it is guaranteed that a DTB is available. However it is not
  63. * guaranteed that the shared Mbed TLS heap implementation is used. Thus we
  64. * return error code from here and it's the responsibility of the caller to
  65. * determine the action upon error.
  66. *
  67. * This function is supposed to be called only by BL1.
  68. *
  69. * Returns:
  70. * 0 = success
  71. * -1 = error
  72. */
  73. int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size)
  74. {
  75. int dtb_root;
  76. /*
  77. * Verify that the DTB is valid, before attempting to write to it,
  78. * and get the DTB root node.
  79. */
  80. int err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
  81. if (err < 0) {
  82. ERROR("Invalid%s loaded. Unable to get root node\n",
  83. " TB_FW_CONFIG");
  84. return -1;
  85. }
  86. /*
  87. * Write the heap address and size in the DTB.
  88. *
  89. * NOTE: The variables heap_addr and heap_size are corrupted
  90. * by the "fdtw_write_inplace_cells" function. After the
  91. * function calls they must NOT be reused.
  92. */
  93. err = fdtw_write_inplace_cells(dtb, dtb_root,
  94. DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr);
  95. if (err < 0) {
  96. ERROR("%sDTB property '%s'\n",
  97. "Unable to write ", DTB_PROP_MBEDTLS_HEAP_ADDR);
  98. return -1;
  99. }
  100. err = fdtw_write_inplace_cells(dtb, dtb_root,
  101. DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
  102. if (err < 0) {
  103. ERROR("%sDTB property '%s'\n",
  104. "Unable to write ", DTB_PROP_MBEDTLS_HEAP_SIZE);
  105. return -1;
  106. }
  107. return 0;
  108. }
  109. #if MEASURED_BOOT
  110. #if DICE_PROTECTION_ENVIRONMENT
  111. #include <common/desc_image_load.h>
  112. #define DTB_PROP_DPE_CTX_HANDLE "dpe_ctx_handle"
  113. static int arm_set_dpe_context_handle(uintptr_t config_base,
  114. int *ctx_handle)
  115. {
  116. /* As libfdt uses void *, we can't avoid this cast */
  117. void *dtb = (void *)config_base;
  118. const char *compatible = "arm,dpe_ctx_handle";
  119. int err, node;
  120. /*
  121. * Verify that the DTB is valid, before attempting to write to it,
  122. * and get the DTB root node.
  123. */
  124. /* Check if the pointer to DT is correct */
  125. err = fdt_check_header(dtb);
  126. if (err < 0) {
  127. WARN("Invalid DTB file passed\n");
  128. return err;
  129. }
  130. /* Assert the node offset point to compatible property */
  131. node = fdt_node_offset_by_compatible(dtb, -1, compatible);
  132. if (node < 0) {
  133. WARN("The compatible property '%s' not%s", compatible,
  134. " found in the config\n");
  135. return node;
  136. }
  137. VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
  138. err = fdtw_write_inplace_cells(dtb, node,
  139. DTB_PROP_DPE_CTX_HANDLE, 1, ctx_handle);
  140. if (err < 0) {
  141. ERROR("%sDTB property '%s'\n",
  142. "Unable to write ", DTB_PROP_DPE_CTX_HANDLE);
  143. } else {
  144. /*
  145. * Ensure that the info written to the DTB is visible
  146. * to other images.
  147. */
  148. flush_dcache_range(config_base, fdt_totalsize(dtb));
  149. }
  150. return err;
  151. }
  152. /*
  153. * This function writes the DPE context handle value to the NT_FW_CONFIG DTB.
  154. *
  155. * This function is supposed to be called only by BL2.
  156. *
  157. * Returns:
  158. * 0 = success
  159. * < 0 = error
  160. */
  161. int arm_set_nt_fw_info(int *ctx_handle)
  162. {
  163. uintptr_t config_base;
  164. const bl_mem_params_node_t *cfg_mem_params;
  165. /* Get the config load address and size from NT_FW_CONFIG */
  166. cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
  167. assert(cfg_mem_params != NULL);
  168. config_base = cfg_mem_params->image_info.image_base;
  169. /* Write the context handle value in the DTB */
  170. return arm_set_dpe_context_handle(config_base, ctx_handle);
  171. }
  172. /*
  173. * This function writes the DPE context handle value to the TB_FW_CONFIG DTB.
  174. *
  175. * This function is supposed to be called only by BL1.
  176. *
  177. * Returns:
  178. * 0 = success
  179. * < 0 = error
  180. */
  181. int arm_set_tb_fw_info(int *ctx_handle)
  182. {
  183. /*
  184. * Read tb_fw_config device tree for Event Log properties
  185. * and write the Event Log address and its size in the DTB
  186. */
  187. const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
  188. uintptr_t tb_fw_cfg_dtb;
  189. tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
  190. assert(tb_fw_config_info != NULL);
  191. tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
  192. /* Write the context handle value in the DTB */
  193. return arm_set_dpe_context_handle(tb_fw_cfg_dtb, ctx_handle);
  194. }
  195. /*
  196. * This function reads the initial DPE context handle from TB_FW_CONFIG DTB.
  197. *
  198. * This function is supposed to be called only by BL2.
  199. *
  200. * Returns:
  201. * 0 = success
  202. * < 0 = error
  203. */
  204. int arm_get_tb_fw_info(int *ctx_handle)
  205. {
  206. /* As libfdt uses void *, we can't avoid this cast */
  207. const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
  208. int node, rc;
  209. tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
  210. assert(tb_fw_config_info != NULL);
  211. void *dtb = (void *)tb_fw_config_info->config_addr;
  212. const char *compatible = "arm,dpe_ctx_handle";
  213. /* Assert the node offset point to compatible property */
  214. node = fdt_node_offset_by_compatible(dtb, -1, compatible);
  215. if (node < 0) {
  216. WARN("The compatible property '%s'%s", compatible,
  217. " not specified in TB_FW config.\n");
  218. return node;
  219. }
  220. VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
  221. rc = fdt_read_uint32(dtb, node, DTB_PROP_DPE_CTX_HANDLE, (uint32_t *)ctx_handle);
  222. if (rc != 0) {
  223. ERROR("%s%s", DTB_PROP_DPE_CTX_HANDLE,
  224. " not specified in TB_FW config.\n");
  225. }
  226. return rc;
  227. }
  228. #else
  229. /*
  230. * Write the Event Log address and its size in the DTB.
  231. *
  232. * Returns:
  233. * 0 = success
  234. * < 0 = error
  235. */
  236. static int arm_set_event_log_info(uintptr_t config_base,
  237. #ifdef SPD_opteed
  238. uintptr_t sm_log_addr,
  239. #endif
  240. uintptr_t log_addr, size_t log_size)
  241. {
  242. /* As libfdt uses void *, we can't avoid this cast */
  243. void *dtb = (void *)config_base;
  244. const char *compatible = "arm,tpm_event_log";
  245. int err, node;
  246. /*
  247. * Verify that the DTB is valid, before attempting to write to it,
  248. * and get the DTB root node.
  249. */
  250. /* Check if the pointer to DT is correct */
  251. err = fdt_check_header(dtb);
  252. if (err < 0) {
  253. WARN("Invalid DTB file passed\n");
  254. return err;
  255. }
  256. /* Assert the node offset point to compatible property */
  257. node = fdt_node_offset_by_compatible(dtb, -1, compatible);
  258. if (node < 0) {
  259. WARN("The compatible property '%s' not%s", compatible,
  260. " found in the config\n");
  261. return node;
  262. }
  263. VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
  264. #ifdef SPD_opteed
  265. if (sm_log_addr != 0UL) {
  266. err = fdtw_write_inplace_cells(dtb, node,
  267. DTB_PROP_HW_SM_LOG_ADDR, 2, &sm_log_addr);
  268. if (err < 0) {
  269. ERROR("%sDTB property '%s'\n",
  270. "Unable to write ", DTB_PROP_HW_SM_LOG_ADDR);
  271. return err;
  272. }
  273. }
  274. #endif
  275. err = fdtw_write_inplace_cells(dtb, node,
  276. DTB_PROP_HW_LOG_ADDR, 2, &log_addr);
  277. if (err < 0) {
  278. ERROR("%sDTB property '%s'\n",
  279. "Unable to write ", DTB_PROP_HW_LOG_ADDR);
  280. return err;
  281. }
  282. assert(event_log_max_size != 0U);
  283. err = fdtw_write_inplace_cells(dtb, node,
  284. DTB_PROP_HW_LOG_MAX_SIZE, 1,
  285. &event_log_max_size);
  286. if (err < 0) {
  287. ERROR("%sDTB property '%s'\n",
  288. "Unable to write ", DTB_PROP_HW_LOG_MAX_SIZE);
  289. return err;
  290. }
  291. err = fdtw_write_inplace_cells(dtb, node,
  292. DTB_PROP_HW_LOG_SIZE, 1, &log_size);
  293. if (err < 0) {
  294. ERROR("%sDTB property '%s'\n",
  295. "Unable to write ", DTB_PROP_HW_LOG_SIZE);
  296. } else {
  297. /*
  298. * Ensure that the info written to the DTB is visible
  299. * to other images.
  300. */
  301. flush_dcache_range(config_base, fdt_totalsize(dtb));
  302. }
  303. return err;
  304. }
  305. /*
  306. * This function writes the Event Log address and its size
  307. * in the TOS_FW_CONFIG DTB.
  308. *
  309. * This function is supposed to be called only by BL2.
  310. *
  311. * Returns:
  312. * 0 = success
  313. * < 0 = error
  314. */
  315. int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size)
  316. {
  317. uintptr_t config_base;
  318. const bl_mem_params_node_t *cfg_mem_params;
  319. int err;
  320. assert(log_addr != 0UL);
  321. /* Get the config load address and size of TOS_FW_CONFIG */
  322. cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
  323. assert(cfg_mem_params != NULL);
  324. config_base = cfg_mem_params->image_info.image_base;
  325. /* Write the Event Log address and its size in the DTB */
  326. err = arm_set_event_log_info(config_base,
  327. #ifdef SPD_opteed
  328. 0UL,
  329. #endif
  330. log_addr, log_size);
  331. if (err < 0) {
  332. ERROR("%sEvent Log data to TOS_FW_CONFIG\n",
  333. "Unable to write ");
  334. }
  335. return err;
  336. }
  337. /*
  338. * This function writes the Event Log address and its size
  339. * in the NT_FW_CONFIG DTB.
  340. *
  341. * This function is supposed to be called only by BL2.
  342. *
  343. * Returns:
  344. * 0 = success
  345. * < 0 = error
  346. */
  347. int arm_set_nt_fw_info(
  348. #ifdef SPD_opteed
  349. uintptr_t log_addr,
  350. #endif
  351. size_t log_size, uintptr_t *ns_log_addr)
  352. {
  353. uintptr_t config_base;
  354. uintptr_t ns_addr;
  355. const bl_mem_params_node_t *cfg_mem_params;
  356. int err;
  357. assert(ns_log_addr != NULL);
  358. /* Get the config load address and size from NT_FW_CONFIG */
  359. cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
  360. assert(cfg_mem_params != NULL);
  361. config_base = cfg_mem_params->image_info.image_base;
  362. /* Calculate Event Log address in Non-secure memory */
  363. ns_addr = cfg_mem_params->image_info.image_base +
  364. cfg_mem_params->image_info.image_max_size;
  365. /* Check for memory space */
  366. if ((uint64_t)(ns_addr + log_size) > ARM_NS_DRAM1_END) {
  367. return -1;
  368. }
  369. /* Write the Event Log address and its size in the DTB */
  370. err = arm_set_event_log_info(config_base,
  371. #ifdef SPD_opteed
  372. log_addr,
  373. #endif
  374. ns_addr, log_size);
  375. /* Return Event Log address in Non-secure memory */
  376. *ns_log_addr = (err < 0) ? 0UL : ns_addr;
  377. return err;
  378. }
  379. /*
  380. * This function writes the Event Log address and its size
  381. * in the TB_FW_CONFIG DTB.
  382. *
  383. * This function is supposed to be called only by BL1.
  384. *
  385. * Returns:
  386. * 0 = success
  387. * < 0 = error
  388. */
  389. int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size, size_t log_max_size)
  390. {
  391. /*
  392. * Read tb_fw_config device tree for Event Log properties
  393. * and write the Event Log address and its size in the DTB
  394. */
  395. const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
  396. uintptr_t tb_fw_cfg_dtb;
  397. int err;
  398. tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
  399. assert(tb_fw_config_info != NULL);
  400. tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
  401. event_log_max_size = log_max_size;
  402. err = arm_set_event_log_info(tb_fw_cfg_dtb,
  403. #ifdef SPD_opteed
  404. 0UL,
  405. #endif
  406. log_addr, log_size);
  407. return err;
  408. }
  409. /*
  410. * This function reads the Event Log address and its size
  411. * properties present in TB_FW_CONFIG DTB.
  412. *
  413. * This function is supposed to be called only by BL2.
  414. *
  415. * Returns:
  416. * 0 = success
  417. * < 0 = error
  418. * Alongside returns Event Log address and its size.
  419. */
  420. int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size,
  421. size_t *log_max_size)
  422. {
  423. /* As libfdt uses void *, we can't avoid this cast */
  424. const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
  425. int node, rc;
  426. tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
  427. assert(tb_fw_config_info != NULL);
  428. void *dtb = (void *)tb_fw_config_info->config_addr;
  429. const char *compatible = "arm,tpm_event_log";
  430. /* Assert the node offset point to compatible property */
  431. node = fdt_node_offset_by_compatible(dtb, -1, compatible);
  432. if (node < 0) {
  433. WARN("The compatible property '%s'%s", compatible,
  434. " not specified in TB_FW config.\n");
  435. return node;
  436. }
  437. VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
  438. rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr);
  439. if (rc != 0) {
  440. ERROR("%s%s", DTB_PROP_HW_LOG_ADDR,
  441. " not specified in TB_FW config.\n");
  442. return rc;
  443. }
  444. rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size);
  445. if (rc != 0) {
  446. ERROR("%s%s", DTB_PROP_HW_LOG_SIZE,
  447. " not specified in TB_FW config.\n");
  448. return rc;
  449. }
  450. rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_MAX_SIZE,
  451. (uint32_t *)log_max_size);
  452. if (rc != 0) {
  453. ERROR("%s%s", DTB_PROP_HW_LOG_MAX_SIZE,
  454. " not specified in TB_FW config.\n");
  455. return rc;
  456. } else {
  457. event_log_max_size = *log_max_size;
  458. }
  459. return rc;
  460. }
  461. #endif /* DICE_PROTECTION_ENVIRONMENT */
  462. #endif /* MEASURED_BOOT */