Re: arm-none-eabi, nested function trampolines and caching

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 5 Dec 2023 at 17:10, Ed Robbins <edd.robbins@xxxxxxxxxxxxxx> wrote:
>
> On Tue, 28 Nov 2023 at 18:00, David Brown <david.brown@xxxxxxxxxxxx> wrote:
> >
> > On 28/11/2023 10:51, Ed Robbins via Gcc-help wrote:
> > > On Tue, 28 Nov 2023 at 07:21, Matthias Pfaller <leo@xxxxxxxx> wrote:
> > >>
> > >> On 2023-11-27 16:16, Ed Robbins via Gcc-help wrote:
> > >>> Hello,
> > >>> I am using gcc-arm-none-eabi with a cortex M7 device, with caches
> > >>> (data/instruction) enabled. Nested function calls result in a usage fault
> > >>> because there is no clear cache call for this platform.
> > >>>
> >
> > >> I have lots of code with nested functions. When switching to gcc-12 I got random
> > >> crashes on my cortex-m7 targets. In order to get that working again I had to patch
> > >> gcc/config/arm/arm.h:
> > >>
> >
> >
> > Can I ask (either or both of you) why you are using are using nested
> > functions like this?  This is possibly the first time I have heard of
> > anyone using them, certainly the first time in embedded development.
> > Even when I programmed in Pascal, where nested functions are part of the
> > language, I did not use them more than a couple of times.
> >
> > What benefit do you see in nested functions in C, compared to having
> > separate functions?  Have you considered moving to C++ and using
> > lambdas, which are more flexible, standard, and can be very much more
> > efficient?
> >
> > This is, of course, straying from the topicality of this mailing list.
> > But I am curious, and I doubt if I am the only one who is.
> >
> > David
> >
>
> In the simplest case you may want to do something like:
>
> struct sometype* find_thing_with_value(struct list *things, uint32_t value) {
>     bool match(void *thing) {
>         return ((struct sometype*)thing)->field == value;
>     }
>     return (struct sometype*)list_find(things, &match);
> }
>
> In general though dependency inversion can be quite powerful. We use
> nested functions that do not access local variables fairly frequently
> in our codebase, mostly as a scoping mechanism. We would like to be
> able to access locals, and are aware of the implications, but only
> very recently decided to address the issue.
>
> I think that rather than switch to C++ lambdas we would be more
> inclined to move to clang blocks and stick with C. But there is no
> impetus for either move: Nested functions are just fine for what we
> need to do, and the syntax is very clean. We have thoughts about a HLL
> shift but it wouldn't be to C++.
>
> Security implications are not an issue for us because there is no way
> for an outsider to communicate with the devices, let alone get a stack
> overflow and code execution.
>
> I think that it would be sensible if there was a -mflush_func option
> for ARM targets, as for MIPS, which would resolve the caching issues
> that require a patched gcc build in this case.
>
> Thanks to Matthias for guidance. I have ended up implementing this a
> bit differently, as in the patch below, as it's then totally
> self-contained. I've tested by rebuilding the toolchain using the
> script from [1] and it is working well.
>

I guess I should have attached that instead of pasting it... second time lucky

Ed
From 569177e29cdc777e84e5e8cf633ebef761e82f83 Mon Sep 17 00:00:00 2001
From: Ed Robbins <edd.robbins@xxxxxxxxx>
Date: Tue, 5 Dec 2023 16:56:36 +0000
Subject: [PATCH] Define CLEAR_INSN_CACHE in arm.h and implement for v7em
 targets

---
 gcc/config/arm/arm.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index f479540812a..666d98611bc 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -2518,4 +2518,37 @@ const char *arm_be8_option (int argc, const char **argv);
    representation for SHF_ARM_PURECODE in GCC.  */
 #define SECTION_ARM_PURECODE SECTION_MACH_DEP
 
+#ifndef CLEAR_INSN_CACHE
+/* When defined CLEAR_INSN_CACHE is called by __clear_cache in libgcc/libgcc2.c
+   It needs to always be _defined_, otherwise maybe_emit_call_builtin___clear_cache
+   from gcc/builtins.cc will not generate a call to __clear_cache, however we
+   only want it _implemented_ for the multilib version of libgcc.a built for
+   v7em targets. */
+#ifdef __ARM_ARCH_7EM__
+#define CLEAR_INSN_CACHE(BEG, END) \
+	{ \
+		const void *scb_base = (const void*)0xe000e000; \
+		const unsigned dccmvac_offset = 0x268; \
+		const unsigned icimvau_offset = 0x258; \
+		const unsigned cache_line_size = 32; \
+		void *addr = (void*)((unsigned)BEG & ~(cache_line_size - 1)); \
+		void *end = (void*)((unsigned)(END + cache_line_size - 1) & ~(cache_line_size - 1)); \
+		__asm__ __volatile__("dsb" : : : "memory"); \
+		while (addr < end) { \
+			*(unsigned**)(scb_base + dccmvac_offset) = addr; \
+			addr += cache_line_size; \
+		} \
+		__asm__ __volatile__("dsb; isb" : : : "memory"); \
+		addr = (void*)((unsigned)BEG & ~(cache_line_size - 1)); \
+		while (addr < end) { \
+			*(unsigned**)(scb_base + icimvau_offset) = addr; \
+			addr += cache_line_size; \
+		} \
+		__asm__ __volatile__("dsb; isb" : : : "memory"); \
+	}
+#else
+#define CLEAR_INSN_CACHE(BEG, END) ;
+#endif
+#endif
+
 #endif /* ! GCC_ARM_H */
-- 
2.34.1


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux