runtime_svc.c 5.1 KB

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