Skip to content

Commit a70a4e6

Browse files
committed
py/emitglue: Always flush caches when assigning native ARM code.
Prior to this commit, cache flushing for ARM native code was done only in the assembler code asm_thumb_end_pass()/asm_arm_end_pass(), at the last pass of the assembler. But this misses flushing the cache when loading native code from an .mpy file, ie in persistentcode.c. The change here makes sure the cache is always flushed/cleaned/invalidated when assigning native code on ARM architectures. This problem was found running tests/micropython/import_mpy_native_gc.py on the mimxrt port. Signed-off-by: Damien George <damien@micropython.org>
1 parent fad0efd commit a70a4e6

5 files changed

Lines changed: 31 additions & 36 deletions

File tree

py/asmarm.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,6 @@
3838

3939
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
4040

41-
void asm_arm_end_pass(asm_arm_t *as) {
42-
if (as->base.pass == MP_ASM_PASS_EMIT) {
43-
#if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
44-
char *start = mp_asm_base_get_code(&as->base);
45-
char *end = start + mp_asm_base_get_code_size(&as->base);
46-
__builtin___clear_cache(start, end);
47-
#elif defined(__arm__)
48-
// flush I- and D-cache
49-
asm volatile (
50-
"0:"
51-
"mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
52-
"bne 0b\n"
53-
"mov r0, #0\n"
54-
"mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
55-
: : : "r0", "cc");
56-
#endif
57-
}
58-
}
59-
6041
// Insert word into instruction flow
6142
STATIC void emit(asm_arm_t *as, uint op) {
6243
uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);

py/asmarm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ typedef struct _asm_arm_t {
7272
uint stack_adjust;
7373
} asm_arm_t;
7474

75-
void asm_arm_end_pass(asm_arm_t *as);
75+
static inline void asm_arm_end_pass(asm_arm_t *as) {
76+
(void)as;
77+
}
7678

7779
void asm_arm_entry(asm_arm_t *as, int num_locals);
7880
void asm_arm_exit(asm_arm_t *as);

py/asmthumb.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
#include "py/mpstate.h"
3737
#include "py/persistentcode.h"
38-
#include "py/mphal.h"
3938
#include "py/asmthumb.h"
4039

4140
#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32)
@@ -62,20 +61,6 @@ static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
6261
return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
6362
}
6463

65-
void asm_thumb_end_pass(asm_thumb_t *as) {
66-
(void)as;
67-
// could check labels are resolved...
68-
69-
#if __ICACHE_PRESENT == 1
70-
if (as->base.pass == MP_ASM_PASS_EMIT) {
71-
// flush D-cache, so the code emitted is stored in memory
72-
MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size);
73-
// invalidate I-cache
74-
SCB_InvalidateICache();
75-
}
76-
#endif
77-
}
78-
7964
/*
8065
STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {
8166
byte *c = asm_thumb_get_cur_to_write_bytes(as, 1);

py/asmthumb.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ typedef struct _asm_thumb_t {
7070
uint32_t stack_adjust;
7171
} asm_thumb_t;
7272

73-
void asm_thumb_end_pass(asm_thumb_t *as);
73+
static inline void asm_thumb_end_pass(asm_thumb_t *as) {
74+
(void)as;
75+
}
7476

7577
void asm_thumb_entry(asm_thumb_t *as, int num_locals);
7678
void asm_thumb_exit(asm_thumb_t *as);

py/emitglue.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,31 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
108108

109109
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
110110

111+
// Some architectures require flushing/invalidation of the I/D caches,
112+
// so that the generated native code which was created in data RAM will
113+
// be available for execution from instruction RAM.
114+
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
115+
#if __ICACHE_PRESENT == 1
116+
// Flush D-cache, so the code emitted is stored in RAM.
117+
MP_HAL_CLEAN_DCACHE(fun_data, fun_len);
118+
// Invalidate I-cache, so the newly-created code is reloaded from RAM.
119+
SCB_InvalidateICache();
120+
#endif
121+
#elif MICROPY_EMIT_ARM
122+
#if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
123+
__builtin___clear_cache(fun_data, (uint8_t *)fun_data + fun_len);
124+
#elif defined(__arm__)
125+
// Flush I-cache and D-cache.
126+
asm volatile (
127+
"0:"
128+
"mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
129+
"bne 0b\n"
130+
"mov r0, #0\n"
131+
"mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
132+
: : : "r0", "cc");
133+
#endif
134+
#endif
135+
111136
rc->kind = kind;
112137
rc->scope_flags = scope_flags;
113138
rc->n_pos_args = n_pos_args;

0 commit comments

Comments
 (0)