cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sram-exec.c (3901B)


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