* [PATCH v3 0/1] ARM: Thumb-2: Symbol manipulation macros for function body copying
@ 2011-01-13 22:41 Dave Martin
2011-01-13 22:41 ` [PATCH v3 1/1] " Dave Martin
0 siblings, 1 reply; 3+ messages in thread
From: Dave Martin @ 2011-01-13 22:41 UTC (permalink / raw)
To: linux-arm-kernel
For at least one board (omap3), some functions are copied from
their link-time location into other memory at run-time.
This is a plausible thing to do if, for example, the board
might need to do something like manipulating the SDRAM
controller configuration during power management operations.
Such code may not be able to execute from the SDRAM itself.
In Thumb-2, copying function bodies is not straightforward:
for Thumb symbols, bit 0 is set by the toolchain, and so
a function symbol can't be used directly as a base address
for memcpy: this leads to an off-by-one error, resulting in
garbage instructions in the destination buffer.
The obvious solution is to mask off this bit when calling
memcpy() and then insert the bit into the address of the
target buffer, in order to derive a pointer which can be
used to call the copied function in the correct instruction
set. However, in practice the compiler may optimise this
operation away. This seems wrong, but having discussed this
with compiler folks I believe it's not a compiler bug: rather,
C doesn't specifiy what happens when casting function pointers
and attempting to do arithmetic on them. So some surprising
optimisations can happen.
To make it easier to deal with cases like this, I've had a
go at writing some macros to make copying function bodies
easier, while being robust for ARM and Thumb-2.
In particular, the required type-casts are implemented as
empty asm() blocks, to ensure that the compiler makes no
assumptions about the result.
This patch provides a fncpy() macro which resembles memcpy().
It can be used as in this example:
extern int scary_function(int a, char *b);
extern const int size_of_scary_function;
extern void *scary_memory_buf;
int (*runtime_scary_function)(int a, char *b);
runtime_scary_function = fncpy(scary_memory_buf,
&scary_function,
size_of_scary_function);
This is quite a lot more readable than the explicit code,
and should give the correct result.
fncpy() calls flush_icache_range() as necessary.
It's not possible to determine the size of a function from
C code. This must be done by other means, such as adding
extra symbols in the assembler code where scary_function is
defined.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
KernelVersion: v2.6.37
Dave Martin (1):
ARM: Thumb-2: Symbol manipulation macros for function body copying
arch/arm/include/asm/fncpy.h | 110 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/include/asm/fncpy.h
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v3 1/1] ARM: Thumb-2: Symbol manipulation macros for function body copying
2011-01-13 22:41 [PATCH v3 0/1] ARM: Thumb-2: Symbol manipulation macros for function body copying Dave Martin
@ 2011-01-13 22:41 ` Dave Martin
2011-01-14 14:53 ` Jean Pihet
0 siblings, 1 reply; 3+ messages in thread
From: Dave Martin @ 2011-01-13 22:41 UTC (permalink / raw)
To: linux-arm-kernel
In low-level board support code, there is sometimes a need to
copy a function body to another location at run-time.
A straightforward call to memcpy doesn't work in Thumb-2,
because bit 0 of external Thumb function symbols is set to 1,
indicating that the function is Thumb. Without corrective
measures, this will cause an off-by-one copy, and the copy
may be called using the wrong instruction set.
This patch adds macros to help with such cases.
Particular care is needed, because C doesn't guarantee any
defined behaviour when casting a function pointer to any other
type. This has been observed to lead to strange optimisation
side-effects when doing the arithmetic which is required in
order to copy/move function bodies correctly in Thumb-2.
Thanks to Russell King and Nicolas Pitre for their input.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
KernelVersion: v2.6.37
arch/arm/include/asm/fncpy.h | 110 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/include/asm/fncpy.h
diff --git a/arch/arm/include/asm/fncpy.h b/arch/arm/include/asm/fncpy.h
new file mode 100644
index 0000000..6399265
--- /dev/null
+++ b/arch/arm/include/asm/fncpy.h
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/include/asm/fncpy.h - helper macros for function body copying
+ *
+ * Copyright (C) 2011 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * These macros are intended for use when there is a need to copy a low-level
+ * function body into special memory.
+ *
+ * For example, when reconfiguring the SDRAM controller, the code doing the
+ * reconfiguration may need to run from SRAM.
+ *
+ * NOTE: that the copied function body must be entirely self-contained and
+ * position-independent in order for this to work properly.
+ *
+ *
+ * Typical usage example:
+ *
+ * extern int f(args);
+ * extern uint32_t size_of_f;
+ * int (*copied_f)(args);
+ * void *sram_buffer;
+ *
+ * copied_f = fncpy(sram_buffer, &f, size_of_f);
+ *
+ * ... do any required D-side/I-side synchronisation ...
+ *
+ * ... later, call the function: ...
+ *
+ * copied_f(args);
+ *
+ * The size of the function to be copied can't be determined from C:
+ * this must be determined by other means, such as adding assmbler directives
+ * in the file where f is defined.
+ */
+
+#ifndef __ASM_FNCPY_H
+#define __ASM_FNCPY_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/cacheflush.h>
+
+/* Function pointer casting macros */
+
+/* Cast function pointer to integer: */
+#define __funcp_to_uint(funcp) ({ \
+ uintptr_t __result; \
+ \
+ asm("" : "=r" (__result) : "0" (funcp)); \
+ __result; \
+ })
+
+/* Cast integer to function pointer with type matching funcp: */
+#define __uint_to_funcp(i, funcp) ({ \
+ typeof(funcp) __result; \
+ \
+ asm("" : "=r" (__result) : "0" (i)); \
+ __result; \
+ })
+
+
+/* Function symbol manipulation macros */
+
+/*
+ * FSYM_REBASE: Determine the correct function pointer for funcp,
+ * after the function has been copied to dest_buf:
+ */
+#define FSYM_REBASE(funcp, dest_buf) \
+ __uint_to_funcp((uintptr_t)(dest_buf) | FSYM_TYPE(funcp), funcp)
+
+/*
+ * FSYM_BASE: Determine the base address in memory of the function funcp
+ * FSYM_TYPE: Determine the instruction set type (ARM/Thumb) of funcp
+ * (both defined below)
+ */
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define FSYM_BASE(funcp) ((void *)(__funcp_to_uint(funcp) & ~(uintptr_t)1))
+#define FSYM_TYPE(funcp) (__funcp_to_uint(funcp) & 1)
+#else /* !CONFIG_THUMB2_KERNEL */
+#define FSYM_BASE(funcp) ((void *)__funcp_to_uint(funcp))
+#define FSYM_TYPE(funcp) 0
+#endif /* !CONFIG_THUMB2_KERNEL */
+
+/* Function copy helper */
+#define fncpy(dest_buf, funcp, size) ({ \
+ memcpy(dest_buf, FSYM_BASE(funcp), size); \
+ flush_icache_range((unsigned long)(dest_buf), \
+ (unsigned long)(dest_buf) + (size)); \
+ \
+ FSYM_REBASE(funcp, dest_buf); \
+ })
+
+#endif /* !__ASM_FNCPY_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH v3 1/1] ARM: Thumb-2: Symbol manipulation macros for function body copying
2011-01-13 22:41 ` [PATCH v3 1/1] " Dave Martin
@ 2011-01-14 14:53 ` Jean Pihet
0 siblings, 0 replies; 3+ messages in thread
From: Jean Pihet @ 2011-01-14 14:53 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Jan 13, 2011 at 11:41 PM, Dave Martin <dave.martin@linaro.org> wrote:
> In low-level board support code, there is sometimes a need to
> copy a function body to another location at run-time.
>
> A straightforward call to memcpy doesn't work in Thumb-2,
> because bit 0 of external Thumb function symbols is set to 1,
> indicating that the function is Thumb. ?Without corrective
> measures, this will cause an off-by-one copy, and the copy
> may be called using the wrong instruction set.
>
> This patch adds macros to help with such cases.
>
> Particular care is needed, because C doesn't guarantee any
> defined behaviour when casting a function pointer to any other
> type. ?This has been observed to lead to strange optimisation
> side-effects when doing the arithmetic which is required in
> order to copy/move function bodies correctly in Thumb-2.
>
> Thanks to Russell King and Nicolas Pitre for their input.
>
> Signed-off-by: Dave Martin <dave.martin@linaro.org>
Tested OK on OMAP3 in low power modes (RET/OFF) with !CONFIG_THUMB2_KERNEL.
Tested-by: Jean Pihet <j-pihet@ti.com>
> ---
> KernelVersion: v2.6.37
>
> ?arch/arm/include/asm/fncpy.h | ?110 ++++++++++++++++++++++++++++++++++++++++++
> ?1 files changed, 110 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/include/asm/fncpy.h
>
> diff --git a/arch/arm/include/asm/fncpy.h b/arch/arm/include/asm/fncpy.h
> new file mode 100644
> index 0000000..6399265
> --- /dev/null
> +++ b/arch/arm/include/asm/fncpy.h
> @@ -0,0 +1,110 @@
> +/*
> + * arch/arm/include/asm/fncpy.h - helper macros for function body copying
> + *
> + * Copyright (C) 2011 Linaro Limited
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +/*
> + * These macros are intended for use when there is a need to copy a low-level
> + * function body into special memory.
> + *
> + * For example, when reconfiguring the SDRAM controller, the code doing the
> + * reconfiguration may need to run from SRAM.
> + *
> + * NOTE: that the copied function body must be entirely self-contained and
> + * position-independent in order for this to work properly.
> + *
> + *
> + * Typical usage example:
> + *
> + * extern int f(args);
> + * extern uint32_t size_of_f;
> + * int (*copied_f)(args);
> + * void *sram_buffer;
> + *
> + * copied_f = fncpy(sram_buffer, &f, size_of_f);
> + *
> + * ... do any required D-side/I-side synchronisation ...
> + *
> + * ... later, call the function: ...
> + *
> + * copied_f(args);
> + *
> + * The size of the function to be copied can't be determined from C:
> + * this must be determined by other means, such as adding assmbler directives
> + * in the file where f is defined.
> + */
> +
> +#ifndef __ASM_FNCPY_H
> +#define __ASM_FNCPY_H
> +
> +#include <linux/types.h>
> +#include <linux/string.h>
> +
> +#include <asm/cacheflush.h>
> +
> +/* Function pointer casting macros */
> +
> +/* Cast function pointer to integer: */
> +#define __funcp_to_uint(funcp) ({ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ? ? ? ? ? uintptr_t __result; ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? asm("" : "=r" (__result) : "0" (funcp)); ? ? ? ?\
> + ? ? ? ? ? ? ? __result; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? })
> +
> +/* Cast integer to function pointer with type matching funcp: */
> +#define __uint_to_funcp(i, funcp) ({ ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? typeof(funcp) __result; ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? asm("" : "=r" (__result) : "0" (i)); ? ?\
> + ? ? ? ? ? ? ? __result; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? })
> +
> +
> +/* Function symbol manipulation macros */
> +
> +/*
> + * FSYM_REBASE: Determine the correct function pointer for funcp,
> + * after the function has been copied to dest_buf:
> + */
> +#define FSYM_REBASE(funcp, dest_buf) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? __uint_to_funcp((uintptr_t)(dest_buf) | FSYM_TYPE(funcp), funcp)
> +
> +/*
> + * FSYM_BASE: Determine the base address in memory of the function funcp
> + * FSYM_TYPE: Determine the instruction set type (ARM/Thumb) of funcp
> + * (both defined below)
> + */
> +
> +#ifdef CONFIG_THUMB2_KERNEL
> +#define FSYM_BASE(funcp) ((void *)(__funcp_to_uint(funcp) & ~(uintptr_t)1))
> +#define FSYM_TYPE(funcp) (__funcp_to_uint(funcp) & 1)
> +#else /* !CONFIG_THUMB2_KERNEL */
> +#define FSYM_BASE(funcp) ((void *)__funcp_to_uint(funcp))
> +#define FSYM_TYPE(funcp) 0
> +#endif /* !CONFIG_THUMB2_KERNEL */
> +
> +/* Function copy helper */
> +#define fncpy(dest_buf, funcp, size) ({ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ? ? ? ? ? memcpy(dest_buf, FSYM_BASE(funcp), size); ? ? ? \
> + ? ? ? ? ? ? ? flush_icache_range((unsigned long)(dest_buf), ? \
> + ? ? ? ? ? ? ? ? ? ? ? (unsigned long)(dest_buf) + (size)); ? ?\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? FSYM_REBASE(funcp, dest_buf); ? ? ? ? ? ? ? ? ? \
> + ? ? ? })
> +
> +#endif /* !__ASM_FNCPY_H */
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-01-14 14:53 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-13 22:41 [PATCH v3 0/1] ARM: Thumb-2: Symbol manipulation macros for function body copying Dave Martin
2011-01-13 22:41 ` [PATCH v3 1/1] " Dave Martin
2011-01-14 14:53 ` Jean Pihet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).