mbed-drivers
CThunk.h
1 /*
2  * Copyright (c) 2014-2016, ARM Limited, All Rights Reserved
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may
6  * not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* General C++ Object Thunking class
19  *
20  * - allows direct callbacks to non-static C++ class functions
21  * - keeps track for the corresponding class instance
22  * - supports an optional context parameter for the called function
23  * - ideally suited for class object receiving interrupts (NVIC_SetVector)
24  */
25 
26 #ifndef __CTHUNK_H__
27 #define __CTHUNK_H__
28 
29 #define CTHUNK_ADDRESS 1
30 
31 #if defined(TARGET_LIKE_CORTEX_M3) || defined(TARGET_LIKE_CORTEX_M4)
32 #define CTHUNK_VARIABLES volatile uint32_t code[1]
33 
43 #define CTHUNK_ASSIGMENT m_thunk.code[0] = 0x8007E89F
44 
45 #elif defined(TARGET_LIKE_CORTEX_M0PLUS) || defined(TARGET_LIKE_CORTEX_M0)
46 /*
47 * CTHUNK disassembly for Cortex M0 (thumb):
48 * * push {r0,r1,r2,r3,r4,lr} save touched registers and return address
49 * * movs r4,#4 set up address to load arguments from (immediately following this code block) (1)
50 * * add r4,pc set up address to load arguments from (immediately following this code block) (2)
51 * * ldm r4!,{r0,r1,r2,r3} load arguments for static thunk function
52 * * blx r3 call static thunk function
53 * * pop {r0,r1,r2,r3,r4,pc} restore scratch registers and return from function
54 */
55 #define CTHUNK_VARIABLES volatile uint32_t code[3]
56 #define CTHUNK_ASSIGMENT do { \
57  m_thunk.code[0] = 0x2404B51F; \
58  m_thunk.code[1] = 0xCC0F447C; \
59  m_thunk.code[2] = 0xBD1F4798; \
60  } while (0)
61 
62 #else
63 #error "Target is not currently suported."
64 #endif
65 
66 /* IRQ/Exception compatible thunk entry function */
67 typedef void (*CThunkEntry)(void);
68 
69 template<class T>
70 class CThunk
71 {
72  public:
73  typedef void (T::*CCallbackSimple)(void);
74  typedef void (T::*CCallback)(void* context);
75 
76  inline CThunk(T *instance)
77  {
78  init(instance, NULL, NULL);
79  }
80 
81  inline CThunk(T *instance, CCallback callback)
82  {
83  init(instance, callback, NULL);
84  }
85 
86  ~CThunk() {
87 
88  }
89 
90  inline CThunk(T *instance, CCallbackSimple callback)
91  {
92  init(instance, (CCallback)callback, NULL);
93  }
94 
95  inline CThunk(T &instance, CCallback callback)
96  {
97  init(instance, callback, NULL);
98  }
99 
100  inline CThunk(T &instance, CCallbackSimple callback)
101  {
102  init(instance, (CCallback)callback, NULL);
103  }
104 
105  inline CThunk(T &instance, CCallback callback, void* context)
106  {
107  init(instance, callback, context);
108  }
109 
110  inline void callback(CCallback callback)
111  {
112  m_callback = callback;
113  }
114 
115  inline void callback(CCallbackSimple callback)
116  {
117  m_callback = (CCallback)callback;
118  }
119 
120  inline void context(void* context)
121  {
122  m_thunk.context = (uint32_t)context;
123  }
124 
125  inline void context(uint32_t context)
126  {
127  m_thunk.context = context;
128  }
129 
130  inline uint32_t entry(void)
131  {
132  return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
133  }
134 
135  /* get thunk entry point for connecting rhunk to an IRQ table */
136  inline operator CThunkEntry(void)
137  {
138  return (CThunkEntry)entry();
139  }
140 
141  /* get thunk entry point for connecting rhunk to an IRQ table */
142  inline operator uint32_t(void)
143  {
144  return entry();
145  }
146 
147  /* simple test function */
148  inline void call(void)
149  {
150  (((CThunkEntry)(entry()))());
151  }
152 
153  private:
154  T* m_instance;
155  volatile CCallback m_callback;
156 
157 // TODO: this needs proper fix, to refactor toolchain header file and all its use
158 // PACKED there is not defined properly for IAR
159 #if defined (__ICCARM__)
160  typedef __packed struct
161  {
162  CTHUNK_VARIABLES;
163  volatile uint32_t instance;
164  volatile uint32_t context;
165  volatile uint32_t callback;
166  volatile uint32_t trampoline;
167  } CThunkTrampoline;
168 #else
169  typedef struct
170  {
171  CTHUNK_VARIABLES;
172  volatile uint32_t instance;
173  volatile uint32_t context;
174  volatile uint32_t callback;
175  volatile uint32_t trampoline;
176  } __attribute__((__packed__)) CThunkTrampoline;
177 #endif
178 
179  static void trampoline(T* instance, void* context, CCallback* callback)
180  {
181  if(instance && *callback) {
182  (static_cast<T*>(instance)->**callback)(context);
183  }
184  }
185 
186  volatile CThunkTrampoline m_thunk;
187 
188  inline void init(T *instance, CCallback callback, void* context)
189  {
190  /* remember callback - need to add this level of redirection
191  as pointer size for member functions differs between platforms */
192  m_callback = callback;
193 
194  /* populate thunking trampoline */
195  CTHUNK_ASSIGMENT;
196  m_thunk.context = (uint32_t)context;
197  m_thunk.instance = (uint32_t)instance;
198  m_thunk.callback = (uint32_t)&m_callback;
199  m_thunk.trampoline = (uint32_t)&trampoline;
200 
201  __ISB();
202  __DSB();
203  }
204 };
205 
206 #endif/*__CTHUNK_H__*/
Definition: CThunk.h:70