runtime_svc.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <common/debug.h>
  10. #include <common/runtime_svc.h>
  11. /*******************************************************************************
  12. * The 'rt_svc_descs' array holds the runtime service descriptors exported by
  13. * services by placing them in the 'rt_svc_descs' linker section.
  14. * The 'rt_svc_descs_indices' array holds the index of a descriptor in the
  15. * 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call
  16. * type[31] bit in the function id are combined to get an index into the
  17. * 'rt_svc_descs_indices' array. This gives the index of the descriptor in the
  18. * 'rt_svc_descs' array which contains the SMC handler.
  19. ******************************************************************************/
  20. uint8_t rt_svc_descs_indices[MAX_RT_SVCS];
  21. #define RT_SVC_DECS_NUM ((RT_SVC_DESCS_END - RT_SVC_DESCS_START)\
  22. / sizeof(rt_svc_desc_t))
  23. /*******************************************************************************
  24. * Function to invoke the registered `handle` corresponding to the smc_fid in
  25. * AArch32 mode.
  26. ******************************************************************************/
  27. uintptr_t handle_runtime_svc(uint32_t smc_fid,
  28. void *cookie,
  29. void *handle,
  30. unsigned int flags)
  31. {
  32. u_register_t x1, x2, x3, x4;
  33. unsigned int index;
  34. unsigned int idx;
  35. const rt_svc_desc_t *rt_svc_descs;
  36. assert(handle != NULL);
  37. idx = get_unique_oen_from_smc_fid(smc_fid);
  38. assert(idx < MAX_RT_SVCS);
  39. index = rt_svc_descs_indices[idx];
  40. if (index >= RT_SVC_DECS_NUM)
  41. SMC_RET1(handle, SMC_UNK);
  42. rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
  43. get_smc_params_from_ctx(handle, x1, x2, x3, x4);
  44. return rt_svc_descs[index].handle(smc_fid, x1, x2, x3, x4, cookie,
  45. handle, flags);
  46. }
  47. /*******************************************************************************
  48. * Simple routine to sanity check a runtime service descriptor before using it
  49. ******************************************************************************/
  50. static int32_t validate_rt_svc_desc(const rt_svc_desc_t *desc)
  51. {
  52. if (desc == NULL)
  53. return -EINVAL;
  54. if (desc->start_oen > desc->end_oen)
  55. return -EINVAL;
  56. if (desc->end_oen >= OEN_LIMIT)
  57. return -EINVAL;
  58. if ((desc->call_type != SMC_TYPE_FAST) &&
  59. (desc->call_type != SMC_TYPE_YIELD))
  60. return -EINVAL;
  61. /* A runtime service having no init or handle function doesn't make sense */
  62. if ((desc->init == NULL) && (desc->handle == NULL))
  63. return -EINVAL;
  64. return 0;
  65. }
  66. /*******************************************************************************
  67. * This function calls the initialisation routine in the descriptor exported by
  68. * a runtime service. Once a descriptor has been validated, its start & end
  69. * owning entity numbers and the call type are combined to form a unique oen.
  70. * The unique oen is used as an index into the 'rt_svc_descs_indices' array.
  71. * The index of the runtime service descriptor is stored at this index.
  72. ******************************************************************************/
  73. void __init runtime_svc_init(void)
  74. {
  75. int rc = 0;
  76. uint8_t index, start_idx, end_idx;
  77. rt_svc_desc_t *rt_svc_descs;
  78. /* Assert the number of descriptors detected are less than maximum indices */
  79. assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
  80. (RT_SVC_DECS_NUM < MAX_RT_SVCS));
  81. /* If no runtime services are implemented then simply bail out */
  82. if (RT_SVC_DECS_NUM == 0U)
  83. return;
  84. /* Initialise internal variables to invalid state */
  85. (void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
  86. rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
  87. for (index = 0U; index < RT_SVC_DECS_NUM; index++) {
  88. rt_svc_desc_t *service = &rt_svc_descs[index];
  89. /*
  90. * An invalid descriptor is an error condition since it is
  91. * difficult to predict the system behaviour in the absence
  92. * of this service.
  93. */
  94. rc = validate_rt_svc_desc(service);
  95. if (rc != 0) {
  96. ERROR("Invalid runtime service descriptor %p\n",
  97. (void *) service);
  98. panic();
  99. }
  100. /*
  101. * The runtime service may have separate rt_svc_desc_t
  102. * for its fast smc and yielding smc. Since the service itself
  103. * need to be initialized only once, only one of them will have
  104. * an initialisation routine defined. Call the initialisation
  105. * routine for this runtime service, if it is defined.
  106. */
  107. if (service->init != NULL) {
  108. rc = service->init();
  109. if (rc != 0) {
  110. ERROR("Error initializing runtime service %s\n",
  111. service->name);
  112. continue;
  113. }
  114. }
  115. /*
  116. * Fill the indices corresponding to the start and end
  117. * owning entity numbers with the index of the
  118. * descriptor which will handle the SMCs for this owning
  119. * entity range.
  120. */
  121. start_idx = (uint8_t)get_unique_oen(service->start_oen,
  122. service->call_type);
  123. end_idx = (uint8_t)get_unique_oen(service->end_oen,
  124. service->call_type);
  125. assert(start_idx <= end_idx);
  126. assert(end_idx < MAX_RT_SVCS);
  127. for (; start_idx <= end_idx; start_idx++)
  128. rt_svc_descs_indices[start_idx] = index;
  129. }
  130. }