Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * arch/arm/include/asm/fncpy.h - helper macros for function body copying
0004  *
0005  * Copyright (C) 2011 Linaro Limited
0006  */
0007 
0008 /*
0009  * These macros are intended for use when there is a need to copy a low-level
0010  * function body into special memory.
0011  *
0012  * For example, when reconfiguring the SDRAM controller, the code doing the
0013  * reconfiguration may need to run from SRAM.
0014  *
0015  * NOTE: that the copied function body must be entirely self-contained and
0016  * position-independent in order for this to work properly.
0017  *
0018  * NOTE: in order for embedded literals and data to get referenced correctly,
0019  * the alignment of functions must be preserved when copying.  To ensure this,
0020  * the source and destination addresses for fncpy() must be aligned to a
0021  * multiple of 8 bytes: you will be get a BUG() if this condition is not met.
0022  * You will typically need a ".align 3" directive in the assembler where the
0023  * function to be copied is defined, and ensure that your allocator for the
0024  * destination buffer returns 8-byte-aligned pointers.
0025  *
0026  * Typical usage example:
0027  *
0028  * extern int f(args);
0029  * extern uint32_t size_of_f;
0030  * int (*copied_f)(args);
0031  * void *sram_buffer;
0032  *
0033  * copied_f = fncpy(sram_buffer, &f, size_of_f);
0034  *
0035  * ... later, call the function: ...
0036  *
0037  * copied_f(args);
0038  *
0039  * The size of the function to be copied can't be determined from C:
0040  * this must be determined by other means, such as adding assmbler directives
0041  * in the file where f is defined.
0042  */
0043 
0044 #ifndef __ASM_FNCPY_H
0045 #define __ASM_FNCPY_H
0046 
0047 #include <linux/types.h>
0048 #include <linux/string.h>
0049 
0050 #include <asm/bug.h>
0051 #include <asm/cacheflush.h>
0052 
0053 /*
0054  * Minimum alignment requirement for the source and destination addresses
0055  * for function copying.
0056  */
0057 #define FNCPY_ALIGN 8
0058 
0059 #define fncpy(dest_buf, funcp, size) ({                 \
0060     uintptr_t __funcp_address;                  \
0061     typeof(funcp) __result;                     \
0062                                     \
0063     asm("" : "=r" (__funcp_address) : "0" (funcp));         \
0064                                     \
0065     /*                              \
0066      * Ensure alignment of source and destination addresses,    \
0067      * disregarding the function's Thumb bit:           \
0068      */                             \
0069     BUG_ON((uintptr_t)(dest_buf) & (FNCPY_ALIGN - 1) ||     \
0070         (__funcp_address & ~(uintptr_t)1 & (FNCPY_ALIGN - 1))); \
0071                                     \
0072     memcpy(dest_buf, (void const *)(__funcp_address & ~1), size);   \
0073     flush_icache_range((unsigned long)(dest_buf),           \
0074         (unsigned long)(dest_buf) + (size));            \
0075                                     \
0076     asm("" : "=r" (__result)                    \
0077         : "0" ((uintptr_t)(dest_buf) | (__funcp_address & 1))); \
0078                                     \
0079     __result;                           \
0080 })
0081 
0082 #endif /* !__ASM_FNCPY_H */