145051539SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 25756e9ddSDave Martin /* 35756e9ddSDave Martin * arch/arm/include/asm/fncpy.h - helper macros for function body copying 45756e9ddSDave Martin * 55756e9ddSDave Martin * Copyright (C) 2011 Linaro Limited 65756e9ddSDave Martin */ 75756e9ddSDave Martin 85756e9ddSDave Martin /* 95756e9ddSDave Martin * These macros are intended for use when there is a need to copy a low-level 105756e9ddSDave Martin * function body into special memory. 115756e9ddSDave Martin * 125756e9ddSDave Martin * For example, when reconfiguring the SDRAM controller, the code doing the 135756e9ddSDave Martin * reconfiguration may need to run from SRAM. 145756e9ddSDave Martin * 155756e9ddSDave Martin * NOTE: that the copied function body must be entirely self-contained and 165756e9ddSDave Martin * position-independent in order for this to work properly. 175756e9ddSDave Martin * 185756e9ddSDave Martin * NOTE: in order for embedded literals and data to get referenced correctly, 195756e9ddSDave Martin * the alignment of functions must be preserved when copying. To ensure this, 205756e9ddSDave Martin * the source and destination addresses for fncpy() must be aligned to a 215756e9ddSDave Martin * multiple of 8 bytes: you will be get a BUG() if this condition is not met. 225756e9ddSDave Martin * You will typically need a ".align 3" directive in the assembler where the 235756e9ddSDave Martin * function to be copied is defined, and ensure that your allocator for the 245756e9ddSDave Martin * destination buffer returns 8-byte-aligned pointers. 255756e9ddSDave Martin * 265756e9ddSDave Martin * Typical usage example: 275756e9ddSDave Martin * 285756e9ddSDave Martin * extern int f(args); 295756e9ddSDave Martin * extern uint32_t size_of_f; 305756e9ddSDave Martin * int (*copied_f)(args); 315756e9ddSDave Martin * void *sram_buffer; 325756e9ddSDave Martin * 335756e9ddSDave Martin * copied_f = fncpy(sram_buffer, &f, size_of_f); 345756e9ddSDave Martin * 355756e9ddSDave Martin * ... later, call the function: ... 365756e9ddSDave Martin * 375756e9ddSDave Martin * copied_f(args); 385756e9ddSDave Martin * 395756e9ddSDave Martin * The size of the function to be copied can't be determined from C: 405756e9ddSDave Martin * this must be determined by other means, such as adding assmbler directives 415756e9ddSDave Martin * in the file where f is defined. 425756e9ddSDave Martin */ 435756e9ddSDave Martin 445756e9ddSDave Martin #ifndef __ASM_FNCPY_H 455756e9ddSDave Martin #define __ASM_FNCPY_H 465756e9ddSDave Martin 475756e9ddSDave Martin #include <linux/types.h> 485756e9ddSDave Martin #include <linux/string.h> 495756e9ddSDave Martin 505756e9ddSDave Martin #include <asm/bug.h> 515756e9ddSDave Martin #include <asm/cacheflush.h> 525756e9ddSDave Martin 535756e9ddSDave Martin /* 545756e9ddSDave Martin * Minimum alignment requirement for the source and destination addresses 555756e9ddSDave Martin * for function copying. 565756e9ddSDave Martin */ 575756e9ddSDave Martin #define FNCPY_ALIGN 8 585756e9ddSDave Martin 595756e9ddSDave Martin #define fncpy(dest_buf, funcp, size) ({ \ 605756e9ddSDave Martin uintptr_t __funcp_address; \ 615756e9ddSDave Martin typeof(funcp) __result; \ 625756e9ddSDave Martin \ 635756e9ddSDave Martin asm("" : "=r" (__funcp_address) : "0" (funcp)); \ 645756e9ddSDave Martin \ 655756e9ddSDave Martin /* \ 665756e9ddSDave Martin * Ensure alignment of source and destination addresses, \ 675756e9ddSDave Martin * disregarding the function's Thumb bit: \ 685756e9ddSDave Martin */ \ 695756e9ddSDave Martin BUG_ON((uintptr_t)(dest_buf) & (FNCPY_ALIGN - 1) || \ 705756e9ddSDave Martin (__funcp_address & ~(uintptr_t)1 & (FNCPY_ALIGN - 1))); \ 715756e9ddSDave Martin \ 725756e9ddSDave Martin memcpy(dest_buf, (void const *)(__funcp_address & ~1), size); \ 735756e9ddSDave Martin flush_icache_range((unsigned long)(dest_buf), \ 745756e9ddSDave Martin (unsigned long)(dest_buf) + (size)); \ 755756e9ddSDave Martin \ 765756e9ddSDave Martin asm("" : "=r" (__result) \ 775756e9ddSDave Martin : "0" ((uintptr_t)(dest_buf) | (__funcp_address & 1))); \ 785756e9ddSDave Martin \ 795756e9ddSDave Martin __result; \ 805756e9ddSDave Martin }) 815756e9ddSDave Martin 825756e9ddSDave Martin #endif /* !__ASM_FNCPY_H */ 83