1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SRAM protect-exec region helper functions 4 * 5 * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ 6 * Dave Gerlach 7 */ 8 9 #include <linux/device.h> 10 #include <linux/genalloc.h> 11 #include <linux/mm.h> 12 #include <linux/sram.h> 13 14 #include <asm/fncpy.h> 15 #include <asm/set_memory.h> 16 17 #include "sram.h" 18 19 static DEFINE_MUTEX(exec_pool_list_mutex); 20 static LIST_HEAD(exec_pool_list); 21 22 int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block, 23 struct sram_partition *part) 24 { 25 unsigned long base = (unsigned long)part->base; 26 unsigned long end = base + block->size; 27 28 if (!PAGE_ALIGNED(base) || !PAGE_ALIGNED(end)) { 29 dev_err(sram->dev, 30 "SRAM pool marked with 'protect-exec' is not page aligned and will not be created.\n"); 31 return -ENOMEM; 32 } 33 34 return 0; 35 } 36 37 int sram_add_protect_exec(struct sram_partition *part) 38 { 39 mutex_lock(&exec_pool_list_mutex); 40 list_add_tail(&part->list, &exec_pool_list); 41 mutex_unlock(&exec_pool_list_mutex); 42 43 return 0; 44 } 45 46 /** 47 * sram_exec_copy - copy data to a protected executable region of sram 48 * 49 * @pool: struct gen_pool retrieved that is part of this sram 50 * @dst: Destination address for the copy, that must be inside pool 51 * @src: Source address for the data to copy 52 * @size: Size of copy to perform, which starting from dst, must reside in pool 53 * 54 * Return: Address for copied data that can safely be called through function 55 * pointer, or NULL if problem. 56 * 57 * This helper function allows sram driver to act as central control location 58 * of 'protect-exec' pools which are normal sram pools but are always set 59 * read-only and executable except when copying data to them, at which point 60 * they are set to read-write non-executable, to make sure no memory is 61 * writeable and executable at the same time. This region must be page-aligned 62 * and is checked during probe, otherwise page attribute manipulation would 63 * not be possible. Care must be taken to only call the returned address as 64 * dst address is not guaranteed to be safely callable. 65 * 66 * NOTE: This function uses the fncpy macro to move code to the executable 67 * region. Some architectures have strict requirements for relocating 68 * executable code, so fncpy is a macro that must be defined by any arch 69 * making use of this functionality that guarantees a safe copy of exec 70 * data and returns a safe address that can be called as a C function 71 * pointer. 72 */ 73 void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src, 74 size_t size) 75 { 76 struct sram_partition *part = NULL, *p; 77 unsigned long base; 78 int pages; 79 void *dst_cpy; 80 int ret; 81 82 mutex_lock(&exec_pool_list_mutex); 83 list_for_each_entry(p, &exec_pool_list, list) { 84 if (p->pool == pool) 85 part = p; 86 } 87 mutex_unlock(&exec_pool_list_mutex); 88 89 if (!part) 90 return NULL; 91 92 if (!gen_pool_has_addr(pool, (unsigned long)dst, size)) 93 return NULL; 94 95 base = (unsigned long)part->base; 96 pages = PAGE_ALIGN(size) / PAGE_SIZE; 97 98 mutex_lock(&part->lock); 99 100 ret = set_memory_nx((unsigned long)base, pages); 101 if (ret) 102 goto error_out; 103 ret = set_memory_rw((unsigned long)base, pages); 104 if (ret) 105 goto error_out; 106 107 dst_cpy = fncpy(dst, src, size); 108 109 ret = set_memory_ro((unsigned long)base, pages); 110 if (ret) 111 goto error_out; 112 ret = set_memory_x((unsigned long)base, pages); 113 if (ret) 114 goto error_out; 115 116 mutex_unlock(&part->lock); 117 118 return dst_cpy; 119 120 error_out: 121 mutex_unlock(&part->lock); 122 return NULL; 123 } 124 EXPORT_SYMBOL_GPL(sram_exec_copy); 125