Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SRAM protect-exec region helper functions
0004  *
0005  * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
0006  *  Dave Gerlach
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/genalloc.h>
0011 #include <linux/mm.h>
0012 #include <linux/sram.h>
0013 
0014 #include <asm/fncpy.h>
0015 #include <asm/set_memory.h>
0016 
0017 #include "sram.h"
0018 
0019 static DEFINE_MUTEX(exec_pool_list_mutex);
0020 static LIST_HEAD(exec_pool_list);
0021 
0022 int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block,
0023                 struct sram_partition *part)
0024 {
0025     unsigned long base = (unsigned long)part->base;
0026     unsigned long end = base + block->size;
0027 
0028     if (!PAGE_ALIGNED(base) || !PAGE_ALIGNED(end)) {
0029         dev_err(sram->dev,
0030             "SRAM pool marked with 'protect-exec' is not page aligned and will not be created.\n");
0031         return -ENOMEM;
0032     }
0033 
0034     return 0;
0035 }
0036 
0037 int sram_add_protect_exec(struct sram_partition *part)
0038 {
0039     mutex_lock(&exec_pool_list_mutex);
0040     list_add_tail(&part->list, &exec_pool_list);
0041     mutex_unlock(&exec_pool_list_mutex);
0042 
0043     return 0;
0044 }
0045 
0046 /**
0047  * sram_exec_copy - copy data to a protected executable region of sram
0048  *
0049  * @pool: struct gen_pool retrieved that is part of this sram
0050  * @dst: Destination address for the copy, that must be inside pool
0051  * @src: Source address for the data to copy
0052  * @size: Size of copy to perform, which starting from dst, must reside in pool
0053  *
0054  * Return: Address for copied data that can safely be called through function
0055  *     pointer, or NULL if problem.
0056  *
0057  * This helper function allows sram driver to act as central control location
0058  * of 'protect-exec' pools which are normal sram pools but are always set
0059  * read-only and executable except when copying data to them, at which point
0060  * they are set to read-write non-executable, to make sure no memory is
0061  * writeable and executable at the same time. This region must be page-aligned
0062  * and is checked during probe, otherwise page attribute manipulation would
0063  * not be possible. Care must be taken to only call the returned address as
0064  * dst address is not guaranteed to be safely callable.
0065  *
0066  * NOTE: This function uses the fncpy macro to move code to the executable
0067  * region. Some architectures have strict requirements for relocating
0068  * executable code, so fncpy is a macro that must be defined by any arch
0069  * making use of this functionality that guarantees a safe copy of exec
0070  * data and returns a safe address that can be called as a C function
0071  * pointer.
0072  */
0073 void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
0074              size_t size)
0075 {
0076     struct sram_partition *part = NULL, *p;
0077     unsigned long base;
0078     int pages;
0079     void *dst_cpy;
0080     int ret;
0081 
0082     mutex_lock(&exec_pool_list_mutex);
0083     list_for_each_entry(p, &exec_pool_list, list) {
0084         if (p->pool == pool)
0085             part = p;
0086     }
0087     mutex_unlock(&exec_pool_list_mutex);
0088 
0089     if (!part)
0090         return NULL;
0091 
0092     if (!gen_pool_has_addr(pool, (unsigned long)dst, size))
0093         return NULL;
0094 
0095     base = (unsigned long)part->base;
0096     pages = PAGE_ALIGN(size) / PAGE_SIZE;
0097 
0098     mutex_lock(&part->lock);
0099 
0100     ret = set_memory_nx((unsigned long)base, pages);
0101     if (ret)
0102         goto error_out;
0103     ret = set_memory_rw((unsigned long)base, pages);
0104     if (ret)
0105         goto error_out;
0106 
0107     dst_cpy = fncpy(dst, src, size);
0108 
0109     ret = set_memory_ro((unsigned long)base, pages);
0110     if (ret)
0111         goto error_out;
0112     ret = set_memory_x((unsigned long)base, pages);
0113     if (ret)
0114         goto error_out;
0115 
0116     mutex_unlock(&part->lock);
0117 
0118     return dst_cpy;
0119 
0120 error_out:
0121     mutex_unlock(&part->lock);
0122     return NULL;
0123 }
0124 EXPORT_SYMBOL_GPL(sram_exec_copy);