Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0d00850 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scm-mpu: Add additional memory protection options"

parents 409f8bfa 05d25ce7
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
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.
+8 −0
Original line number Diff line number Diff line
@@ -635,6 +635,14 @@ config QCOM_NPA_DUMP
	help
	  Read the NPA dump from RPM memory through debugfs.

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.

source "drivers/soc/qcom/memshare/Kconfig"

endif # ARCH_MSM
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o

obj-$(CONFIG_MSM_CACHE_DUMP) += cache_dump.o
obj-$(CONFIG_MSM_CPUSS_DUMP) += cpuss_dump.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_SMD) += smd.o smd_debug.o smd_private.o smd_init_dt.o smsm_debug.o
obj-$(CONFIG_MSM_SMEM) += smem.o smem_debug.o
+97 −0
Original line number Diff line number Diff line
/* 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 <soc/qcom/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 scm_desc desc = {0};

	desc.arginfo = SCM_ARGS(5);
	desc.args[0] = PAGE_ALIGN(start);
	desc.args[1] = PAGE_ALIGN(size);
	/*
	 * Permissions:  Write:         Read
	 * 0x1           TZ             Anyone
	 * 0x2           TZ             Tz, APPS
	 * 0x3           TZ             Tz
	 */
	desc.args[2] = 0x1;
	desc.args[3] = lock;
	desc.args[4] = 0;

	if (!is_scm_armv8())
		ret = -EINVAL;
	else
		ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, TZ_PROTECT_MEMORY),
				&desc);
	if (ret != 0)
		pr_err("Failed 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