18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/include/asm/fncpy.h - helper macros for function body copying 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Linaro Limited 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * These macros are intended for use when there is a need to copy a low-level 108c2ecf20Sopenharmony_ci * function body into special memory. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * For example, when reconfiguring the SDRAM controller, the code doing the 138c2ecf20Sopenharmony_ci * reconfiguration may need to run from SRAM. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * NOTE: that the copied function body must be entirely self-contained and 168c2ecf20Sopenharmony_ci * position-independent in order for this to work properly. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * NOTE: in order for embedded literals and data to get referenced correctly, 198c2ecf20Sopenharmony_ci * the alignment of functions must be preserved when copying. To ensure this, 208c2ecf20Sopenharmony_ci * the source and destination addresses for fncpy() must be aligned to a 218c2ecf20Sopenharmony_ci * multiple of 8 bytes: you will be get a BUG() if this condition is not met. 228c2ecf20Sopenharmony_ci * You will typically need a ".align 3" directive in the assembler where the 238c2ecf20Sopenharmony_ci * function to be copied is defined, and ensure that your allocator for the 248c2ecf20Sopenharmony_ci * destination buffer returns 8-byte-aligned pointers. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Typical usage example: 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * extern int f(args); 298c2ecf20Sopenharmony_ci * extern uint32_t size_of_f; 308c2ecf20Sopenharmony_ci * int (*copied_f)(args); 318c2ecf20Sopenharmony_ci * void *sram_buffer; 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * copied_f = fncpy(sram_buffer, &f, size_of_f); 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * ... later, call the function: ... 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * copied_f(args); 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * The size of the function to be copied can't be determined from C: 408c2ecf20Sopenharmony_ci * this must be determined by other means, such as adding assmbler directives 418c2ecf20Sopenharmony_ci * in the file where f is defined. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#ifndef __ASM_FNCPY_H 458c2ecf20Sopenharmony_ci#define __ASM_FNCPY_H 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <linux/types.h> 488c2ecf20Sopenharmony_ci#include <linux/string.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <asm/bug.h> 518c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Minimum alignment requirement for the source and destination addresses 558c2ecf20Sopenharmony_ci * for function copying. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci#define FNCPY_ALIGN 8 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define fncpy(dest_buf, funcp, size) ({ \ 608c2ecf20Sopenharmony_ci uintptr_t __funcp_address; \ 618c2ecf20Sopenharmony_ci typeof(funcp) __result; \ 628c2ecf20Sopenharmony_ci \ 638c2ecf20Sopenharmony_ci asm("" : "=r" (__funcp_address) : "0" (funcp)); \ 648c2ecf20Sopenharmony_ci \ 658c2ecf20Sopenharmony_ci /* \ 668c2ecf20Sopenharmony_ci * Ensure alignment of source and destination addresses, \ 678c2ecf20Sopenharmony_ci * disregarding the function's Thumb bit: \ 688c2ecf20Sopenharmony_ci */ \ 698c2ecf20Sopenharmony_ci BUG_ON((uintptr_t)(dest_buf) & (FNCPY_ALIGN - 1) || \ 708c2ecf20Sopenharmony_ci (__funcp_address & ~(uintptr_t)1 & (FNCPY_ALIGN - 1))); \ 718c2ecf20Sopenharmony_ci \ 728c2ecf20Sopenharmony_ci memcpy(dest_buf, (void const *)(__funcp_address & ~1), size); \ 738c2ecf20Sopenharmony_ci flush_icache_range((unsigned long)(dest_buf), \ 748c2ecf20Sopenharmony_ci (unsigned long)(dest_buf) + (size)); \ 758c2ecf20Sopenharmony_ci \ 768c2ecf20Sopenharmony_ci asm("" : "=r" (__result) \ 778c2ecf20Sopenharmony_ci : "0" ((uintptr_t)(dest_buf) | (__funcp_address & 1))); \ 788c2ecf20Sopenharmony_ci \ 798c2ecf20Sopenharmony_ci __result; \ 808c2ecf20Sopenharmony_ci}) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#endif /* !__ASM_FNCPY_H */ 83