scm-mpu: Add additional memory protection options

Add support for a scm call to protect a contiguous physical address range.
Add a config option to use this api to protect the kernel text section.
Otherwise, the user may specify the region through module parameters.

CRs-Fixed: 797891
Change-Id: Ie751ec72deb1a1692093559fe8c6784e8bf912a2
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
[schikk@codeaurora.org: 3.4 kernel doesn't have
drivers/soc/qcom folder, new file scm-mpu.c has
been added in arch/arm/mach-msm/.
3.4 kernel doesn't support function scm_call2 ,
so replaced the function call with scm_call which
is supported in 3.4 kernel ]
Signed-off-by: Swetha Chikkaboraiah <schikk@codeaurora.org>
This commit is contained in:
Patrick Daly 2015-02-12 16:16:39 -08:00 committed by Swetha Chikkaboraiah
parent 8aeb0925bc
commit d6ce51794a
4 changed files with 148 additions and 1 deletions

View File

@ -0,0 +1,36 @@
Introduction
============
The scm-mpu driver allows enabling xpu protection of arbitrary physical memory
addresses as a debug mechanism.
Software description
====================
Several methods of controlling this feature are provided.
* CONFIG_KERNEL_TEXT_MPU_PROT - Enables protection of the kernel code and
read-only sections by default.
* kernel command line
scm_mpu.mpu_start=0x0
scm_mpu.mpu_size=0x1000
* /sys/module/scm_mpu/parameters
echo 0x0 > mpu_start
echo 0x1000 > mpu_size
echo 0x11 > mpu_enable
The sysfs interface may also be used to unlock previously defined regions.
echo 0x0 > mpu_start
echo 0x1000 > mpu_size
echo 0x10 > mpu_enable
Limitations
===========
The number of distinct regions allowed is limited by available resources.
No provisions are made for "carving out" or otherwise removing xpu protected
regions from the linux memory map.
XPU protection currently uses 4K alignment.

View File

@ -3044,3 +3044,11 @@ config KRAIT_REGULATOR
regulators running in ganged mode inside the PMIC. Enable
this option to support such configurations.
endif
config KERNEL_TEXT_MPU_PROT
bool "Enable xpu protection of kernel r/o sections"
help
Enables xpu protection of kernel code and read-only data
sections early in boot. Read access is permitted to
all masters; Write access is only permited to the
secure world.

View File

@ -76,7 +76,7 @@ $(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o smd_init_dt.o smd_init_plat.o
obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o scm-mpu.o
obj-$(CONFIG_MSM_XPU_ERR_FATAL) += scm-xpu.o
obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
obj-$(CONFIG_MSM_PIL) += peripheral-loader.o

103
arch/arm/mach-msm/scm-mpu.c Normal file
View File

@ -0,0 +1,103 @@
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <mach/scm.h>
#include <linux/mm.h>
#include <asm/sections.h>
#define TZ_PROTECT_MEMORY 0x1
/* filesystem parameters */
#define MPU_MAGIC_LOCK 0x11
#define MPU_MAGIC_UNLOCK 0x10
static ulong mpu_start;
static ulong mpu_size;
static u32 mpu_enable;
module_param(mpu_start, ulong, 0644);
module_param(mpu_size, ulong, 0644);
static void mem_prot_region(u64 start, u64 size, bool lock);
static int set_enabled(const char *val, const struct kernel_param *kp)
{
int ret = 0;
ret = param_set_int(val, kp);
if (mpu_enable == MPU_MAGIC_LOCK)
mem_prot_region(mpu_start, mpu_size, true);
else if (mpu_enable == MPU_MAGIC_UNLOCK)
mem_prot_region(mpu_start, mpu_size, false);
return ret;
}
static struct kernel_param_ops mpu_ops = {
.set = set_enabled,
.get = param_get_int,
};
module_param_cb(mpu_enable, &mpu_ops, &mpu_enable, 0644);
static void mem_prot_region(u64 start, u64 size, bool lock)
{
int ret;
struct req_cmd {
u32 address;
u32 size;
u32 permission;
u32 lock;
u32 arg;
} request;
request.address = PAGE_ALIGN(start);
request.size = PAGE_ALIGN(size);
/*
* Permissions: Write: Read
* 0x1 TZ Anyone
* 0x2 TZ Tz, APPS
* 0x3 TZ Tz
*/
request.permission = 0x1;
request.lock = lock;
request.arg = 0;
ret = scm_call(SCM_SVC_MP, TZ_PROTECT_MEMORY,
&request, sizeof(request), &ret, sizeof(ret));
if (ret != 0)
pr_err("Failed to %s region %llx - %llx\n",
lock ? "protect" : "unlock", start, start + size);
else
pr_debug("SUCCESS to %s region %llx - %llx\n",
lock ? "protect" : "unlock", start, start + size);
}
#ifdef CONFIG_KERNEL_TEXT_MPU_PROT
static int __init mem_prot_init(void)
{
phys_addr_t phys = virt_to_phys(_stext);
mem_prot_region((u64)phys, (u64)(_etext - _stext), true);
return 0;
}
late_initcall(mem_prot_init);
#else
static int __init mem_prot_init(void)
{
if (mpu_start && mpu_size)
mem_prot_region(mpu_start, mpu_size, true);
return 0;
}
late_initcall(mem_prot_init);
#endif