CThunk.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /** \addtogroup platform */
  2. /** @{*/
  3. /**
  4. * \defgroup platform_CThunk CThunk class
  5. * @{
  6. */
  7. /* General C++ Object Thunking class
  8. *
  9. * - allows direct callbacks to non-static C++ class functions
  10. * - keeps track for the corresponding class instance
  11. * - supports an optional context parameter for the called function
  12. * - ideally suited for class object receiving interrupts (NVIC_SetVector)
  13. *
  14. * Copyright (c) 2014-2015 ARM Limited
  15. *
  16. * Licensed under the Apache License, Version 2.0 (the "License");
  17. * you may not use this file except in compliance with the License.
  18. * You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. */
  28. /* General C++ Object Thunking class
  29. *
  30. * - allows direct callbacks to non-static C++ class functions
  31. * - keeps track for the corresponding class instance
  32. * - supports an optional context parameter for the called function
  33. * - ideally suited for class object receiving interrupts (NVIC_SetVector)
  34. */
  35. #ifndef __CTHUNK_H__
  36. #define __CTHUNK_H__
  37. #define CTHUNK_ADDRESS 1
  38. #define CTHUNK_VARIABLES volatile uint32_t code[2]
  39. #if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__CORTEX_M7) || defined(__CORTEX_A9) \
  40. || defined(__CORTEX_M33))
  41. /**
  42. * CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2):
  43. * * adr r0, #4
  44. * * ldm r0, {r0, r1, r2, pc}
  45. *
  46. * This instruction loads the arguments for the static thunking function to r0-r2, and
  47. * branches to that function by loading its address into PC.
  48. *
  49. * This is safe for both regular calling and interrupt calling, since it only touches scratch registers
  50. * which should be saved by the caller, and are automatically saved as part of the IRQ context switch.
  51. */
  52. #define CTHUNK_ASSIGMENT do { \
  53. m_thunk.code[0] = 0xE890A001; \
  54. m_thunk.code[1] = 0x00008007; \
  55. } while (0)
  56. #elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0) || defined(__CORTEX_M23))
  57. /*
  58. * CTHUNK disassembly for Cortex M0/M0+ (thumb):
  59. * * adr r0, #4
  60. * * ldm r0, {r0, r1, r2, r3}
  61. * * bx r3
  62. */
  63. #define CTHUNK_ASSIGMENT do { \
  64. m_thunk.code[0] = 0xC80FA001; \
  65. m_thunk.code[1] = 0x00004718; \
  66. } while (0)
  67. #else
  68. #error "Target is not currently suported."
  69. #endif
  70. /* IRQ/Exception compatible thunk entry function */
  71. typedef void (*CThunkEntry)(void);
  72. /**
  73. * Class for created a pointer with data bound to it
  74. *
  75. * @note Synchronization level: Not protected
  76. */
  77. template<class T>
  78. class CThunk {
  79. public:
  80. typedef void (T::*CCallbackSimple)(void);
  81. typedef void (T::*CCallback)(void *context);
  82. inline CThunk(T *instance)
  83. {
  84. init(instance, NULL, NULL);
  85. }
  86. inline CThunk(T *instance, CCallback callback)
  87. {
  88. init(instance, callback, NULL);
  89. }
  90. ~CThunk()
  91. {
  92. }
  93. inline CThunk(T *instance, CCallbackSimple callback)
  94. {
  95. init(instance, (CCallback)callback, NULL);
  96. }
  97. inline CThunk(T &instance, CCallback callback)
  98. {
  99. init(instance, callback, NULL);
  100. }
  101. inline CThunk(T &instance, CCallbackSimple callback)
  102. {
  103. init(instance, (CCallback)callback, NULL);
  104. }
  105. inline CThunk(T &instance, CCallback callback, void *context)
  106. {
  107. init(instance, callback, context);
  108. }
  109. inline void callback(CCallback callback)
  110. {
  111. m_callback = callback;
  112. }
  113. inline void callback(CCallbackSimple callback)
  114. {
  115. m_callback = (CCallback)callback;
  116. }
  117. inline void context(void *context)
  118. {
  119. m_thunk.context = (uint32_t)context;
  120. }
  121. inline void context(uint32_t context)
  122. {
  123. m_thunk.context = context;
  124. }
  125. inline uint32_t entry(void)
  126. {
  127. return (((uint32_t)&m_thunk) | CTHUNK_ADDRESS);
  128. }
  129. /* get thunk entry point for connecting rhunk to an IRQ table */
  130. inline operator CThunkEntry(void)
  131. {
  132. return (CThunkEntry)entry();
  133. }
  134. /* get thunk entry point for connecting rhunk to an IRQ table */
  135. inline operator uint32_t(void)
  136. {
  137. return entry();
  138. }
  139. /* simple test function */
  140. inline void call(void)
  141. {
  142. (((CThunkEntry)(entry()))());
  143. }
  144. private:
  145. T *m_instance;
  146. volatile CCallback m_callback;
  147. // TODO: this needs proper fix, to refactor toolchain header file and all its use
  148. // PACKED there is not defined properly for IAR
  149. #if defined (__ICCARM__)
  150. typedef __packed struct {
  151. CTHUNK_VARIABLES;
  152. volatile uint32_t instance;
  153. volatile uint32_t context;
  154. volatile uint32_t callback;
  155. volatile uint32_t trampoline;
  156. } CThunkTrampoline;
  157. #else
  158. typedef struct {
  159. CTHUNK_VARIABLES;
  160. volatile uint32_t instance;
  161. volatile uint32_t context;
  162. volatile uint32_t callback;
  163. volatile uint32_t trampoline;
  164. } __attribute__((__packed__)) CThunkTrampoline;
  165. #endif
  166. static void trampoline(T *instance, void *context, CCallback *callback)
  167. {
  168. if (instance && *callback) {
  169. (static_cast<T *>(instance)->**callback)(context);
  170. }
  171. }
  172. volatile CThunkTrampoline m_thunk;
  173. inline void init(T *instance, CCallback callback, void *context)
  174. {
  175. /* remember callback - need to add this level of redirection
  176. as pointer size for member functions differs between platforms */
  177. m_callback = callback;
  178. /* populate thunking trampoline */
  179. CTHUNK_ASSIGMENT;
  180. m_thunk.context = (uint32_t)context;
  181. m_thunk.instance = (uint32_t)instance;
  182. m_thunk.callback = (uint32_t)&m_callback;
  183. m_thunk.trampoline = (uint32_t)&trampoline;
  184. #if defined(__CORTEX_A9)
  185. /* Data cache clean */
  186. /* Cache control */
  187. {
  188. uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0;
  189. uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk);
  190. uint32_t addr;
  191. /* Data cache clean and invalid */
  192. for (addr = start_addr; addr < end_addr; addr += 0x20) {
  193. L1C_CleanInvalidateDCacheMVA((void *)addr);
  194. }
  195. /* Instruction cache invalid */
  196. L1C_InvalidateICacheAll();
  197. MMU_InvalidateTLB();
  198. L1C_InvalidateBTAC();
  199. }
  200. #endif
  201. #if defined(__CORTEX_M7)
  202. /* Data cache clean and invalid */
  203. SCB_CleanInvalidateDCache();
  204. /* Instruction cache invalid */
  205. SCB_InvalidateICache();
  206. #endif
  207. __ISB();
  208. __DSB();
  209. }
  210. };
  211. /**@}*/
  212. /**@}*/
  213. #endif/*__CTHUNK_H__*/