From d6ce51794a201f6e81060e7168ad46d52376f68c Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 12 Feb 2015 16:16:39 -0800 Subject: [PATCH] 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 [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 --- Documentation/arm/msm/scm-mpu.txt | 36 +++++++++++ arch/arm/mach-msm/Kconfig | 8 +++ arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/scm-mpu.c | 103 ++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 Documentation/arm/msm/scm-mpu.txt create mode 100644 arch/arm/mach-msm/scm-mpu.c diff --git a/Documentation/arm/msm/scm-mpu.txt b/Documentation/arm/msm/scm-mpu.txt new file mode 100644 index 00000000000..988710dd267 --- /dev/null +++ b/Documentation/arm/msm/scm-mpu.txt @@ -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. diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 3721809b917..60f05c6b4ba 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -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. diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index c945b1056d3..c8f46a6f551 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -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 diff --git a/arch/arm/mach-msm/scm-mpu.c b/arch/arm/mach-msm/scm-mpu.c new file mode 100644 index 00000000000..c9eef0a0725 --- /dev/null +++ b/arch/arm/mach-msm/scm-mpu.c @@ -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 +#include +#include +#include +#include + +#include + +#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