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

Commit 287e9b7a authored by Chintan Pandya's avatar Chintan Pandya
Browse files

iommu: msm: add access_control feature



Some of the peripherals can be tinkered to modify
secure kernel image. Since we anyway have an IOMMU
in front of them, block their accesses in kernel
region and enhance stability and security.

Change-Id: I97ba51146c9035a6c6724368880d296fb54b3f41
Signed-off-by: default avatarChintan Pandya <cpandya@codeaurora.org>
parent 45f1dede
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/export.h>
#include <linux/iommu.h>
#include <linux/qcom_iommu.h>
#include <asm/sections.h>

static DEFINE_MUTEX(iommu_list_lock);
static LIST_HEAD(iommu_list);
@@ -68,6 +69,68 @@ int msm_iommu_bus_register(void)
}
#endif

void msm_access_control(void)
{
	int ret;
	struct device *cb_dev;
	struct iommu_domain *domain;
	unsigned long start, kernel_start, kernel_end, end;

	start = 0;
	kernel_start = ALIGN(__pa(_stext), SZ_2M);
	kernel_end = ALIGN(__pa(_etext), SZ_2M);
	end = 0xFFFFFFFF;

	/*
	 * If a target doesn't have the access control feature
	 * it won't have CB and that's okay
	 */
	cb_dev = msm_iommu_get_ctx("access_control");

	domain = iommu_domain_alloc(msm_iommu_non_sec_bus_type);
	if (!domain) {
		pr_err("Couldn't get domain for access control\n");
		goto err;
	}

	/*
	 * Map the region from start to kernel_start
	 */
	if (start < kernel_start) {
		ret = iommu_map(domain, start, start, kernel_start - start,
				IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE);

		if (ret) {
			pr_err("Mapping failed for region lower than kernel\n");
			goto free_dom;
		}
	}

	/*
	 * Map the region from kernel_end to end of DDR
	 */
	ret = iommu_map(domain, kernel_end, kernel_end, end - kernel_end + 1,
				IOMMU_READ | IOMMU_WRITE);

	if (ret) {
		pr_err("Mapping failed for region above kernel\n");
		goto free_dom;
	}

	ret = iommu_attach_device(domain, cb_dev);
	if (ret) {
		pr_err("Attach of access_control CB failed\n");
		goto free_dom;
	}

	return;

free_dom:
	iommu_domain_free(domain);
err:
	BUG();
}

/**
 * Pass the context bank device here. Based on the context bank
 * device, the bus is chosen and hence the respective IOMMU ops.
+3 −0
Original line number Diff line number Diff line
@@ -666,6 +666,9 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)

		dev_info(&pdev->dev, "context %s using bank %d\n",
			 ctx_drvdata->name, ctx_drvdata->num);

		if (strcmp(ctx_drvdata->name, "access_control") == 0)
			msm_access_control();
	}

	return ret;
+5 −0
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ void msm_iommu_remote_p0_spin_unlock(unsigned int need_lock);
struct device *msm_iommu_get_ctx(const char *ctx_name);
struct bus_type *msm_iommu_get_bus(struct device *dev);
int msm_iommu_bus_register(void);
void msm_access_control(void);
#else
static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
{
@@ -348,6 +349,10 @@ static inline struct bus_type *msm_iommu_get_bus(struct device *dev)
{
	return &platform_bus_type;
}

static inline void msm_access_control(void)
{
}
#endif

/*