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