drtm_dma_prot.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (c) 2022 Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * DRTM DMA protection.
  7. *
  8. * Authors:
  9. * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
  10. *
  11. */
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <common/debug.h>
  15. #include <drivers/arm/smmu_v3.h>
  16. #include "drtm_dma_prot.h"
  17. #include "drtm_main.h"
  18. #include "drtm_remediation.h"
  19. #include <plat/common/platform.h>
  20. #include <smccc_helpers.h>
  21. /*
  22. * ________________________ LAUNCH success ________________________
  23. * | Initial | -------------------> | Prot engaged |
  24. * |````````````````````````| |````````````````````````|
  25. * | request.type == NONE | | request.type != NONE |
  26. * | | <------------------- | |
  27. * `________________________' UNPROTECT_MEM `________________________'
  28. *
  29. * Transitions that are not shown correspond to ABI calls that do not change
  30. * state and result in an error being returned to the caller.
  31. */
  32. static struct dma_prot active_prot = {
  33. .type = PROTECT_NONE,
  34. };
  35. /* Version-independent type. */
  36. typedef struct drtm_dl_dma_prot_args_v1 struct_drtm_dl_dma_prot_args;
  37. /*
  38. * This function checks that platform supports complete DMA protection.
  39. * and returns false - if the platform supports complete DMA protection.
  40. * and returns true - if the platform does not support complete DMA protection.
  41. */
  42. bool drtm_dma_prot_init(void)
  43. {
  44. bool must_init_fail = false;
  45. const uintptr_t *smmus;
  46. size_t num_smmus = 0;
  47. unsigned int total_smmus;
  48. /* Warns presence of non-host platforms */
  49. if (plat_has_non_host_platforms()) {
  50. WARN("DRTM: the platform includes trusted DMA-capable devices"
  51. " (non-host platforms)\n");
  52. }
  53. /*
  54. * DLME protection is uncertain on platforms with peripherals whose
  55. * DMA is not managed by an SMMU. DRTM doesn't work on such platforms.
  56. */
  57. if (plat_has_unmanaged_dma_peripherals()) {
  58. ERROR("DRTM: this platform does not provide DMA protection\n");
  59. must_init_fail = true;
  60. }
  61. /*
  62. * Check that the platform reported all SMMUs.
  63. * It is acceptable if the platform doesn't have any SMMUs when it
  64. * doesn't have any DMA-capable devices.
  65. */
  66. total_smmus = plat_get_total_smmus();
  67. plat_enumerate_smmus(&smmus, &num_smmus);
  68. if (num_smmus != total_smmus) {
  69. ERROR("DRTM: could not discover all SMMUs\n");
  70. must_init_fail = true;
  71. }
  72. return must_init_fail;
  73. }
  74. /*
  75. * Checks that the DMA protection arguments are valid and that the given
  76. * protected regions are covered by DMA protection.
  77. */
  78. enum drtm_retc drtm_dma_prot_check_args(const struct_drtm_dl_dma_prot_args *a,
  79. int a_dma_prot_type,
  80. drtm_mem_region_t p)
  81. {
  82. switch ((enum dma_prot_type)a_dma_prot_type) {
  83. case PROTECT_MEM_ALL:
  84. if (a->dma_prot_table_paddr || a->dma_prot_table_size) {
  85. ERROR("DRTM: invalid launch due to inconsistent"
  86. " DMA protection arguments\n");
  87. return MEM_PROTECT_INVALID;
  88. }
  89. /*
  90. * Full DMA protection ought to ensure that the DLME and NWd
  91. * DCE regions are protected, no further checks required.
  92. */
  93. return SUCCESS;
  94. default:
  95. ERROR("DRTM: invalid launch due to unsupported DMA protection type\n");
  96. return MEM_PROTECT_INVALID;
  97. }
  98. }
  99. enum drtm_retc drtm_dma_prot_engage(const struct_drtm_dl_dma_prot_args *a,
  100. int a_dma_prot_type)
  101. {
  102. const uintptr_t *smmus;
  103. size_t num_smmus = 0;
  104. if (active_prot.type != PROTECT_NONE) {
  105. ERROR("DRTM: launch denied as previous DMA protection"
  106. " is still engaged\n");
  107. return DENIED;
  108. }
  109. if (a_dma_prot_type == PROTECT_NONE) {
  110. return SUCCESS;
  111. /* Only PROTECT_MEM_ALL is supported currently. */
  112. } else if (a_dma_prot_type != PROTECT_MEM_ALL) {
  113. ERROR("%s(): unimplemented DMA protection type\n", __func__);
  114. panic();
  115. }
  116. /*
  117. * Engage SMMUs in accordance with the request we have previously received.
  118. * Only PROTECT_MEM_ALL is implemented currently.
  119. */
  120. plat_enumerate_smmus(&smmus, &num_smmus);
  121. for (const uintptr_t *smmu = smmus; smmu < smmus+num_smmus; smmu++) {
  122. /*
  123. * TODO: Invalidate SMMU's Stage-1 and Stage-2 TLB entries. This ensures
  124. * that any outstanding device transactions are completed, see Section
  125. * 3.21.1, specification IHI_0070_C_a for an approximate reference.
  126. */
  127. int rc = smmuv3_ns_set_abort_all(*smmu);
  128. if (rc != 0) {
  129. ERROR("DRTM: SMMU at PA 0x%lx failed to engage DMA protection"
  130. " rc=%d\n", *smmu, rc);
  131. return INTERNAL_ERROR;
  132. }
  133. }
  134. /*
  135. * TODO: Restrict DMA from the GIC.
  136. *
  137. * Full DMA protection may be achieved as follows:
  138. *
  139. * With a GICv3:
  140. * - Set GICR_CTLR.EnableLPIs to 0, for each GICR;
  141. * GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
  142. * - Set GITS_CTLR.Enabled to 0;
  143. * GITS_CTLR.Quiescent == 1 must be the case before finishing.
  144. *
  145. * In addition, with a GICv4:
  146. * - Set GICR_VPENDBASER.Valid to 0, for each GICR;
  147. * GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
  148. *
  149. * Alternatively, e.g. if some bit values cannot be changed at runtime,
  150. * this procedure should return an error if the LPI Pending and
  151. * Configuration tables overlap the regions being protected.
  152. */
  153. active_prot.type = a_dma_prot_type;
  154. return SUCCESS;
  155. }
  156. /*
  157. * Undo what has previously been done in drtm_dma_prot_engage(), or enter
  158. * remediation if it is not possible.
  159. */
  160. enum drtm_retc drtm_dma_prot_disengage(void)
  161. {
  162. const uintptr_t *smmus;
  163. size_t num_smmus = 0;
  164. const char *err_str = "cannot undo PROTECT_MEM_ALL SMMU config";
  165. if (active_prot.type == PROTECT_NONE) {
  166. return SUCCESS;
  167. /* Only PROTECT_MEM_ALL is supported currently. */
  168. } else if (active_prot.type != PROTECT_MEM_ALL) {
  169. ERROR("%s(): unimplemented DMA protection type\n", __func__);
  170. panic();
  171. }
  172. /*
  173. * For PROTECT_MEM_ALL, undo the SMMU configuration for "abort all" mode
  174. * done during engage().
  175. */
  176. /* Simply enter remediation for now. */
  177. (void)smmus;
  178. (void)num_smmus;
  179. drtm_enter_remediation(1ULL, err_str);
  180. /* TODO: Undo GIC DMA restrictions. */
  181. active_prot.type = PROTECT_NONE;
  182. return SUCCESS;
  183. }
  184. uint64_t drtm_unprotect_mem(void *ctx)
  185. {
  186. enum drtm_retc ret;
  187. switch (active_prot.type) {
  188. case PROTECT_NONE:
  189. ERROR("DRTM: invalid UNPROTECT_MEM, no DMA protection has"
  190. " previously been engaged\n");
  191. ret = DENIED;
  192. break;
  193. case PROTECT_MEM_ALL:
  194. /*
  195. * UNPROTECT_MEM is a no-op for PROTECT_MEM_ALL: DRTM must not touch
  196. * the NS SMMU as it is expected that the DLME has configured it.
  197. */
  198. active_prot.type = PROTECT_NONE;
  199. ret = SUCCESS;
  200. break;
  201. default:
  202. ret = drtm_dma_prot_disengage();
  203. break;
  204. }
  205. SMC_RET1(ctx, ret);
  206. }
  207. void drtm_dma_prot_serialise_table(uint8_t *dst, size_t *size_out)
  208. {
  209. if (active_prot.type == PROTECT_NONE) {
  210. return;
  211. } else if (active_prot.type != PROTECT_MEM_ALL) {
  212. ERROR("%s(): unimplemented DMA protection type\n", __func__);
  213. panic();
  214. }
  215. struct __packed descr_table_1 {
  216. drtm_memory_region_descriptor_table_t header;
  217. drtm_mem_region_t regions[1];
  218. } prot_table = {
  219. .header = {
  220. .revision = 1,
  221. .num_regions = sizeof(((struct descr_table_1 *)NULL)->regions) /
  222. sizeof(((struct descr_table_1 *)NULL)->regions[0])
  223. },
  224. .regions = {
  225. {.region_address = 0, PAGES_AND_TYPE(UINT64_MAX, 0x3)},
  226. }
  227. };
  228. memcpy(dst, &prot_table, sizeof(prot_table));
  229. *size_out = sizeof(prot_table);
  230. }