2 * include/asm-generic/fncpy.h - helper macros for function body copying
4 * Copyright (C) 2011 Linaro Limited
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * These macros are intended for use when there is a need to copy a low-level
22 * function body into special memory.
24 * For example, when reconfiguring the SDRAM controller, the code doing the
25 * reconfiguration may need to run from SRAM.
27 * NOTE: that the copied function body must be entirely self-contained and
28 * position-independent in order for this to work properly.
30 * Typical usage example:
33 * extern uint32_t size_of_f;
34 * int (*copied_f)(args);
37 * copied_f = fncpy(sram_buffer, &f, size_of_f);
39 * ... later, call the function: ...
43 * The size of the function to be copied can't be determined from C:
44 * this must be determined by other means, such as adding assmbler directives
45 * in the file where f is defined.
48 #ifndef __ASM_GENERIC_FNCPY_H
49 #define __ASM_GENERIC_FNCPY_H
51 #include <linux/types.h>
52 #include <linux/string.h>
55 #include <asm/cacheflush.h>
58 * Minimum alignment requirement for the source and destination addresses
59 * for function copying.
61 #ifndef ARCH_FNCPY_ALIGN
62 #define ARCH_FNCPY_ALIGN 0
65 #define ARCH_FNCPY_MASK ((1 << (ARCH_FNCPY_ALIGN)) - 1)
68 #define fnptr_to_addr(funcp) ({ \
69 (uintptr_t) (funcp); \
73 #ifndef fnptr_translate
74 #define fnptr_translate(orig_funcp, new_addr) ({ \
75 (typeof(orig_funcp)) (new_addr); \
79 /* Ensure alignment of source and destination addresses */
80 #ifndef fn_dest_invalid
81 #define fn_dest_invalid(funcp, dest_buf) ({ \
82 uintptr_t __funcp_address; \
84 __funcp_address = fnptr_to_addr(funcp); \
86 ((uintptr_t)(dest_buf) & ARCH_FNCPY_MASK) || \
87 (__funcp_address & ARCH_FNCPY_MASK); \
92 #define fncpy(dest_buf, funcp, size) ({ \
93 BUG_ON(fn_dest_invalid(funcp, dest_buf)); \
95 memcpy(dest_buf, (void const *)(funcp), size); \
96 flush_icache_range((unsigned long)(dest_buf), \
97 (unsigned long)(dest_buf) + (size)); \
99 fnptr_translate(funcp, dest_buf); \
103 #endif /* !__ASM_GENERIC_FNCPY_H */