Skip to content

Commit 0fe6369

Browse files
author
Cruz Monrreal
authored
Merge pull request #8488 from c1728p9/cthunk_overhaul
Rewrite CThunk so it does not execute from ram
2 parents 96191e2 + 5a87276 commit 0fe6369

File tree

4 files changed

+260
-113
lines changed

4 files changed

+260
-113
lines changed

platform/CThunk.h

Lines changed: 35 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -38,53 +38,15 @@
3838
#ifndef __CTHUNK_H__
3939
#define __CTHUNK_H__
4040

41-
#define CTHUNK_ADDRESS 1
42-
#define CTHUNK_VARIABLES volatile uint32_t code[2]
43-
44-
#if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__CORTEX_M7) || defined(__CORTEX_A9) \
45-
|| defined(__CORTEX_M33))
46-
/**
47-
* CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2):
48-
* * adr r0, #4
49-
* * ldm r0, {r0, r1, r2, pc}
50-
*
51-
* This instruction loads the arguments for the static thunking function to r0-r2, and
52-
* branches to that function by loading its address into PC.
53-
*
54-
* This is safe for both regular calling and interrupt calling, since it only touches scratch registers
55-
* which should be saved by the caller, and are automatically saved as part of the IRQ context switch.
56-
*/
57-
#define CTHUNK_ASSIGMENT do { \
58-
m_thunk.code[0] = 0xE890A001; \
59-
m_thunk.code[1] = 0x00008007; \
60-
} while (0)
61-
62-
#elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0) || defined(__CORTEX_M23))
63-
/*
64-
* CTHUNK disassembly for Cortex M0/M0+ (thumb):
65-
* * adr r0, #4
66-
* * ldm r0, {r0, r1, r2, r3}
67-
* * bx r3
68-
*/
69-
#define CTHUNK_ASSIGMENT do { \
70-
m_thunk.code[0] = 0xC80FA001; \
71-
m_thunk.code[1] = 0x00004718; \
72-
} while (0)
73-
74-
#else
75-
#error "Target is not currently suported."
76-
#endif
77-
78-
/* IRQ/Exception compatible thunk entry function */
79-
typedef void (*CThunkEntry)(void);
41+
#include "CThunkBase.h"
8042

8143
/**
8244
* Class for created a pointer with data bound to it
8345
*
8446
* @note Synchronization level: Not protected
8547
*/
8648
template<class T>
87-
class CThunk {
49+
class CThunk: public CThunkBase {
8850
public:
8951
typedef void (T::*CCallbackSimple)(void);
9052
typedef void (T::*CCallback)(void *context);
@@ -101,7 +63,8 @@ class CThunk {
10163

10264
~CThunk()
10365
{
104-
66+
cthunk_free(_entry);
67+
_entry = NULL;
10568
}
10669

10770
inline CThunk(T *instance, CCallbackSimple callback)
@@ -126,27 +89,30 @@ class CThunk {
12689

12790
inline void callback(CCallback callback)
12891
{
129-
m_callback = callback;
92+
_callback = callback;
13093
}
13194

13295
inline void callback(CCallbackSimple callback)
13396
{
134-
m_callback = (CCallback)callback;
97+
_callback_simple = callback;
13598
}
13699

137100
inline void context(void *context)
138101
{
139-
m_thunk.context = (uint32_t)context;
102+
_context = context;
140103
}
141104

142105
inline void context(uint32_t context)
143106
{
144-
m_thunk.context = context;
107+
_context = (void*)context;
145108
}
146109

147110
inline uint32_t entry(void)
148111
{
149-
return (((uint32_t)&m_thunk) | CTHUNK_ADDRESS);
112+
if (_entry == NULL) {
113+
_entry = cthunk_alloc(this);
114+
}
115+
return (uint32_t)_entry;
150116
}
151117

152118
/* get thunk entry point for connecting rhunk to an IRQ table */
@@ -168,78 +134,34 @@ class CThunk {
168134
}
169135

170136
private:
171-
T *m_instance;
172-
volatile CCallback m_callback;
173-
174-
// TODO: this needs proper fix, to refactor toolchain header file and all its use
175-
// PACKED there is not defined properly for IAR
176-
#if defined (__ICCARM__)
177-
typedef __packed struct {
178-
CTHUNK_VARIABLES;
179-
volatile uint32_t instance;
180-
volatile uint32_t context;
181-
volatile uint32_t callback;
182-
volatile uint32_t trampoline;
183-
} CThunkTrampoline;
184-
#else
185-
typedef struct {
186-
CTHUNK_VARIABLES;
187-
volatile uint32_t instance;
188-
volatile uint32_t context;
189-
volatile uint32_t callback;
190-
volatile uint32_t trampoline;
191-
} __attribute__((__packed__)) CThunkTrampoline;
192-
#endif
193-
194-
static void trampoline(T *instance, void *context, CCallback *callback)
195-
{
196-
if (instance && *callback) {
197-
(static_cast<T *>(instance)->**callback)(context);
137+
T *_instance;
138+
void *_context;
139+
union {
140+
CCallbackSimple _callback_simple;
141+
CCallback _callback;
142+
};
143+
144+
CThunkEntry _entry;
145+
146+
static void trampoline(CThunkBase *base)
147+
{
148+
CThunk<T> *self = static_cast<CThunk<T>*>(base);
149+
T *instance = self->_instance;
150+
void *context = self->_context;
151+
CCallback callback = self->_callback;
152+
153+
if (instance && callback) {
154+
(instance->*callback)(context);
198155
}
199156
}
200157

201-
volatile CThunkTrampoline m_thunk;
202-
203158
inline void init(T *instance, CCallback callback, void *context)
204159
{
205-
/* remember callback - need to add this level of redirection
206-
as pointer size for member functions differs between platforms */
207-
m_callback = callback;
208-
209-
/* populate thunking trampoline */
210-
CTHUNK_ASSIGMENT;
211-
m_thunk.context = (uint32_t)context;
212-
m_thunk.instance = (uint32_t)instance;
213-
m_thunk.callback = (uint32_t)&m_callback;
214-
m_thunk.trampoline = (uint32_t)&trampoline;
215-
216-
#if defined(__CORTEX_A9)
217-
/* Data cache clean */
218-
/* Cache control */
219-
{
220-
uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0;
221-
uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk);
222-
uint32_t addr;
223-
224-
/* Data cache clean and invalid */
225-
for (addr = start_addr; addr < end_addr; addr += 0x20) {
226-
L1C_CleanInvalidateDCacheMVA((void *)addr);
227-
}
228-
/* Instruction cache invalid */
229-
L1C_InvalidateICacheAll();
230-
MMU_InvalidateTLB();
231-
L1C_InvalidateBTAC();
232-
}
233-
#endif
234-
#if defined(__CORTEX_M7)
235-
/* Data cache clean and invalid */
236-
SCB_CleanInvalidateDCache();
237-
238-
/* Instruction cache invalid */
239-
SCB_InvalidateICache();
240-
#endif
241-
__ISB();
242-
__DSB();
160+
_instance = instance;
161+
_context = context;
162+
_callback = callback;
163+
_trampoline = &trampoline;
164+
_entry = 0;
243165
}
244166
};
245167

platform/CThunkBase.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "platform/platform.h"
18+
#include "platform/mbed_critical.h"
19+
#include "platform/mbed_assert.h"
20+
#include "platform/mbed_error.h"
21+
22+
23+
#include "CThunkBase.h"
24+
25+
MBED_STATIC_ASSERT(MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX < 256, "MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX must be less than 256");
26+
MBED_STATIC_ASSERT(MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX > 0, "MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX must be greater than 0");
27+
28+
#define ENABLE_N(N) ((MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX & N) ? 1 : 0)
29+
30+
#define START_128 0
31+
#define START_64 (START_128 + ENABLE_N(128) * 128)
32+
#define START_32 (START_64 + ENABLE_N(64) * 64)
33+
#define START_16 (START_32 + ENABLE_N(32) * 32)
34+
#define START_8 (START_16 + ENABLE_N(16) * 16)
35+
#define START_4 (START_8 + ENABLE_N(8) * 8)
36+
#define START_2 (START_4 + ENABLE_N(4) * 4)
37+
#define START_1 (START_2 + ENABLE_N(2) * 2)
38+
39+
#define DECLARE_THUNK128(start) \
40+
DECLARE_THUNK64(start), \
41+
DECLARE_THUNK64(start + 64)
42+
#define DECLARE_THUNK64(start) \
43+
DECLARE_THUNK32(start), \
44+
DECLARE_THUNK32(start + 32)
45+
#define DECLARE_THUNK32(start) \
46+
DECLARE_THUNK16(start), \
47+
DECLARE_THUNK16(start + 16)
48+
#define DECLARE_THUNK16(start) \
49+
DECLARE_THUNK8(start), \
50+
DECLARE_THUNK8(start + 8)
51+
#define DECLARE_THUNK8(start) \
52+
DECLARE_THUNK4(start), \
53+
DECLARE_THUNK4(start + 4)
54+
#define DECLARE_THUNK4(start) \
55+
DECLARE_THUNK2(start), \
56+
DECLARE_THUNK2(start + 2)
57+
#define DECLARE_THUNK2(start) \
58+
DECLARE_THUNK1(start), \
59+
DECLARE_THUNK1(start + 1)
60+
#define DECLARE_THUNK1(index) &CThunkBase::thunk_entry<index>
61+
62+
const CThunkEntry CThunkBase::_thunk_table[MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX] = {
63+
#if ENABLE_N(128)
64+
DECLARE_THUNK128(START_128),
65+
#endif
66+
#if ENABLE_N(64)
67+
DECLARE_THUNK64(START_64),
68+
#endif
69+
#if ENABLE_N(32)
70+
DECLARE_THUNK32(START_32),
71+
#endif
72+
#if ENABLE_N(16)
73+
DECLARE_THUNK16(START_16),
74+
#endif
75+
#if ENABLE_N(8)
76+
DECLARE_THUNK8(START_8),
77+
#endif
78+
#if ENABLE_N(4)
79+
DECLARE_THUNK4(START_4),
80+
#endif
81+
#if ENABLE_N(2)
82+
DECLARE_THUNK2(START_2),
83+
#endif
84+
#if ENABLE_N(1)
85+
DECLARE_THUNK1(START_1)
86+
#endif
87+
};
88+
89+
CThunkBase *CThunkBase::_thunk_storage[MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX];
90+
91+
CThunkBase::CthunkFree CThunkBase::_cthunk_free_real = NULL;
92+
93+
CThunkEntry CThunkBase::cthunk_alloc(CThunkBase *cthunk)
94+
{
95+
// Atomically allocate one entry
96+
core_util_critical_section_enter();
97+
CThunkEntry entry = NULL;
98+
for (int i = 0; i < MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX; i++) {
99+
if (_thunk_storage[i] == NULL) {
100+
_thunk_storage[i] = cthunk;
101+
entry = _thunk_table[i];
102+
break;
103+
}
104+
}
105+
core_util_critical_section_exit();
106+
107+
if (entry == NULL) {
108+
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_RESOURCES), "Ran out of CThunk entries. Increase MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX to fix this error");
109+
}
110+
111+
// Set function pointer on first use. This allows _thunk_table
112+
// and _thunk_storage to get removed by the linker if
113+
// cthunk_alloc is never used.
114+
_cthunk_free_real = &cthunk_free_real;
115+
116+
return entry;
117+
}
118+
119+
void CThunkBase::cthunk_free(CThunkEntry item)
120+
{
121+
if (_cthunk_free_real) {
122+
_cthunk_free_real(item);
123+
}
124+
}
125+
126+
void CThunkBase::cthunk_free_real(CThunkEntry item)
127+
{
128+
bool found = false;
129+
130+
core_util_critical_section_enter();
131+
for (int i = 0; i < MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX; i++) {
132+
if (_thunk_table[i] == item) {
133+
_thunk_storage[i] = NULL;
134+
found = true;
135+
break;
136+
}
137+
}
138+
core_util_critical_section_exit();
139+
140+
if (!found) {
141+
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT), "Tried to free invalid CThunkEntry");
142+
}
143+
144+
}

0 commit comments

Comments
 (0)