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

Commit b290626d authored by Tarun Karra's avatar Tarun Karra
Browse files

msm: kgsl: Secure buffer allocation for A430 content protection



Add support for secure buffer allocation for A430 content protection.
When GPU user mode driver requests kernel to allocate a secure buffer,
allocate the memory and call trustzone to restrict access for
allocated memory. Trustzone makes sure only GPU has access to this
memory. If restricted clients try to access this memory it will
trigger XPU violation.

Change-Id: I331e04fa0216837fb7394757bbeb326ec6b24e64
Signed-off-by: default avatarTarun Karra <tkarra@codeaurora.org>
parent 0024abc9
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -3262,7 +3262,16 @@ _gpumem_alloc(struct kgsl_device_private *dev_priv,
		| KGSL_CACHEMODE_MASK
		| KGSL_MEMTYPE_MASK
		| KGSL_MEMALIGN_MASK
		| KGSL_MEMFLAGS_USE_CPU_MAP;
		| KGSL_MEMFLAGS_USE_CPU_MAP
		| KGSL_MEMFLAGS_SECURE;

	/* If content protection is not enabled force memory to be nonsecure */
	if (!kgsl_mmu_is_secured(&dev_priv->device->mmu) &&
			(flags & KGSL_MEMFLAGS_SECURE)) {
		dev_WARN_ONCE(dev_priv->device->dev, 1,
				"Secure memory not supported");
		return -EINVAL;
	}

	/* Cap the alignment bits to the highest number we can handle */

+2 −0
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ struct kgsl_driver {
		unsigned int page_alloc_max;
		unsigned int coherent;
		unsigned int coherent_max;
		unsigned int secure;
		unsigned int secure_max;
		unsigned int mapped;
		unsigned int mapped_max;
	} stats;
+87 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/kmemleak.h>
#include <linux/highmem.h>
#include <soc/qcom/scm.h>

#include "kgsl.h"
#include "kgsl_sharedmem.h"
@@ -25,6 +26,20 @@

static DEFINE_MUTEX(kernel_map_global_lock);

struct cp2_mem_chunks {
	unsigned int chunk_list;
	unsigned int chunk_list_size;
	unsigned int chunk_size;
} __attribute__ ((__packed__));

struct cp2_lock_req {
	struct cp2_mem_chunks chunks;
	unsigned int mem_usage;
	unsigned int lock;
} __attribute__ ((__packed__));

#define MEM_PROTECT_LOCK_ID2     0x0A

/* An attribute for showing per-process memory statistics */
struct kgsl_mem_entry_attribute {
	struct attribute attr;
@@ -228,6 +243,10 @@ static ssize_t kgsl_drv_memstat_show(struct device *dev,
		val = kgsl_driver.stats.coherent;
	else if (!strncmp(attr->attr.name, "coherent_max", 12))
		val = kgsl_driver.stats.coherent_max;
	else if (!strcmp(attr->attr.name, "secure"))
		val = kgsl_driver.stats.secure;
	else if (!strcmp(attr->attr.name, "secure_max"))
		val = kgsl_driver.stats.secure_max;
	else if (!strncmp(attr->attr.name, "mapped", 6))
		val = kgsl_driver.stats.mapped;
	else if (!strncmp(attr->attr.name, "mapped_max", 10))
@@ -265,6 +284,8 @@ static DEVICE_ATTR(page_alloc, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(page_alloc_max, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(coherent, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(coherent_max, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(secure, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(secure_max, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL);
static DEVICE_ATTR(full_cache_threshold, 0644,
@@ -278,6 +299,8 @@ static const struct device_attribute *drv_attr_list[] = {
	&dev_attr_page_alloc_max,
	&dev_attr_coherent,
	&dev_attr_coherent_max,
	&dev_attr_secure,
	&dev_attr_secure_max,
	&dev_attr_mapped,
	&dev_attr_mapped_max,
	&dev_attr_full_cache_threshold,
@@ -871,3 +894,67 @@ err:
	return result;
}
EXPORT_SYMBOL(kgsl_cma_alloc_coherent);

int kgsl_cma_alloc_secure(struct kgsl_device *device,
			struct kgsl_memdesc *memdesc, size_t size)
{
	int result = 0;
	struct cp2_lock_req request;
	unsigned int resp;
	struct kgsl_pagetable *pagetable = device->mmu.securepagetable;

	if (size == 0)
		return -EINVAL;

	memdesc->size = ALIGN(size, SZ_1M);
	memdesc->pagetable = pagetable;
	memdesc->ops = &kgsl_cma_ops;
	memdesc->dev = device->dev->parent;

	memdesc->hostptr = dma_alloc_coherent(memdesc->dev, size,
					&memdesc->physaddr, GFP_KERNEL);

	if (memdesc->hostptr == NULL) {
		result = -ENOMEM;
		goto err;
	}

	result = memdesc_sg_phys(memdesc, memdesc->physaddr, size);
	if (result)
		goto err;

	/*
	 * Flush the phys addr range before sending the memory to the
	 * secure environment to ensure the data is actually present
	 * in RAM
	 */
	dmac_flush_range((void *)memdesc->physaddr,
			(void *)memdesc->physaddr + memdesc->size);

	request.chunks.chunk_list = memdesc->physaddr;
	request.chunks.chunk_list_size = 1;
	request.chunks.chunk_size = memdesc->size;
	request.mem_usage = 0;
	request.lock = 1;

	kmap_flush_unused();
	kmap_atomic_flush_unused();
	result = scm_call(SCM_SVC_MP, MEM_PROTECT_LOCK_ID2,
			&request, sizeof(request), &resp, sizeof(resp));

	if (result) {
		KGSL_DRV_ERR(device, "Secure buffer allocation failed\n");
		goto err;
	}

	/* Record statistics */
	KGSL_STATS_ADD(size, kgsl_driver.stats.secure,
		       kgsl_driver.stats.secure_max);

err:
	if (result)
		kgsl_sharedmem_free(memdesc);

	return result;
}
EXPORT_SYMBOL(kgsl_cma_alloc_secure);
+5 −1
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ int kgsl_cma_alloc_coherent(struct kgsl_device *device,
			struct kgsl_memdesc *memdesc,
			struct kgsl_pagetable *pagetable, size_t size);

int kgsl_cma_alloc_secure(struct kgsl_device *device,
			struct kgsl_memdesc *memdesc, size_t size);

void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc);

int kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc,
@@ -229,7 +232,8 @@ kgsl_allocate_user(struct kgsl_device *device,
	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE) {
		size = ALIGN(size, PAGE_SIZE);
		ret = kgsl_cma_alloc_coherent(device, memdesc, pagetable, size);
	}
	} else if (flags & KGSL_MEMFLAGS_SECURE)
		ret = kgsl_cma_alloc_secure(device, memdesc, size);
	else
		ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size);