summaryrefslogtreecommitdiff
path: root/lib/armflush.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/armflush.c')
-rw-r--r--lib/armflush.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/lib/armflush.c b/lib/armflush.c
new file mode 100644
index 0000000..eae3260
--- /dev/null
+++ b/lib/armflush.c
@@ -0,0 +1,58 @@
+/* armflush.c - flush the instruction cache
+
+ __clear_cache is used in tccrun.c, It is a built-in
+ intrinsic with gcc. However tcc in order to compile
+ itself needs this function */
+
+#ifdef __TINYC__
+
+/* syscall wrapper */
+unsigned syscall(unsigned syscall_nr, ...);
+
+/* arm-tcc supports only fake asm currently */
+__asm__(
+ ".global syscall\n"
+ "syscall:\n"
+ ".int 0xe92d4080\n" // push {r7, lr}
+ ".int 0xe1a07000\n" // mov r7, r0
+ ".int 0xe1a00001\n" // mov r0, r1
+ ".int 0xe1a01002\n" // mov r1, r2
+ ".int 0xe1a02003\n" // mov r2, r3
+ ".int 0xef000000\n" // svc 0x00000000
+ ".int 0xe8bd8080\n" // pop {r7, pc}
+ );
+
+/* from unistd.h: */
+#if defined(__thumb__) || defined(__ARM_EABI__)
+# define __NR_SYSCALL_BASE 0x0
+#else
+# define __NR_SYSCALL_BASE 0x900000
+#endif
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+
+#else
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+
+#endif
+
+/* Flushing for tccrun */
+void __clear_cache(void *beginning, void *end)
+{
+/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
+ * However, there is no ARM asm parser in tcc so we use it for now */
+#if 1
+ syscall(__ARM_NR_cacheflush, beginning, end, 0);
+#else
+ __asm__ ("push {r7}\n\t"
+ "mov r7, #0xf0002\n\t"
+ "mov r2, #0\n\t"
+ "swi 0\n\t"
+ "pop {r7}\n\t"
+ "ret");
+#endif
+}