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

Commit c1005d82 authored by Patrick Daly's avatar Patrick Daly
Browse files

msm: ion: Add system secure heap



Add infrastructure to support a new system secure
heap, needed for secure use cases. The new heap
essentially allocates from the system heap, and
assigns the memory to the correct VM before
returning back to the client.

Change-Id: I2cd900e4399eecc3a9510139c4ebea0b713c39fc
Signed-off-by: default avatarNeeti Desai <neetid@codeaurora.org>
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 99e36c1c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
			ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o
			ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o \
			ion_system_secure_heap.o
obj-$(CONFIG_ION_TEST) += ion_test.o
ifdef CONFIG_COMPAT
obj-$(CONFIG_ION) += compat_ion.o
+6 −0
Original line number Diff line number Diff line
@@ -275,6 +275,7 @@ int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);

int msm_ion_heap_high_order_page_zero(struct page *page, int order);
struct ion_heap *get_ion_heap(int heap_id);
int msm_ion_heap_buffer_zero(struct ion_buffer *buffer);
int msm_ion_heap_pages_zero(struct page **pages, int num_pages);
int msm_ion_heap_alloc_pages_mem(struct pages_mem *pages_mem);
@@ -284,6 +285,8 @@ long msm_ion_custom_ioctl(struct ion_client *client,
			  unsigned int cmd,
			  unsigned long arg);

int ion_heap_is_system_secure_heap_type(enum ion_heap_type type);

/**
 * ion_heap_init_shrinker
 * @heap:		the heap
@@ -387,6 +390,9 @@ void ion_chunk_heap_destroy(struct ion_heap *);
struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
void ion_cma_heap_destroy(struct ion_heap *);

struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *heap);
void ion_system_secure_heap_destroy(struct ion_heap *heap);

/**
 * kernel api to allocate/free from carveout -- used when carveout is
 * used to back an architecture specific custom heap
+216 −0
Original line number Diff line number Diff line
/*
 *
 * Copyright (c) 2014,2016 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/slab.h>
#include <linux/msm_ion.h>
#include <soc/qcom/secure_buffer.h>
#include "ion.h"
#include "ion_priv.h"

struct ion_system_secure_heap {
	struct ion_heap *sys_heap;
	struct ion_heap heap;
};

static bool is_cp_flag_present(unsigned long flags)
{
	return flags && (ION_FLAG_CP_TOUCH ||
			ION_FLAG_CP_BITSTREAM ||
			ION_FLAG_CP_PIXEL ||
			ION_FLAG_CP_NON_PIXEL ||
			ION_FLAG_CP_CAMERA);
}

static int get_secure_vmid(unsigned long flags)
{
	if (flags & ION_FLAG_CP_TOUCH)
		return VMID_CP_TOUCH;
	if (flags & ION_FLAG_CP_BITSTREAM)
		return VMID_CP_BITSTREAM;
	if (flags & ION_FLAG_CP_PIXEL)
		return VMID_CP_PIXEL;
	if (flags & ION_FLAG_CP_NON_PIXEL)
		return VMID_CP_NON_PIXEL;
	if (flags & ION_FLAG_CP_CAMERA)
		return VMID_CP_CAMERA;

	return -EINVAL;
}

static void ion_system_secure_heap_free(struct ion_buffer *buffer)
{
	int ret = 0;
	u32 source_vm;
	int dest_vmid;
	int dest_perms;
	struct ion_heap *heap = buffer->heap;
	struct ion_system_secure_heap *secure_heap = container_of(heap,
						struct ion_system_secure_heap,
						heap);

	source_vm = get_secure_vmid(buffer->flags);
	if (source_vm < 0) {
		pr_info("%s: Unable to get secure VMID\n", __func__);
		return;
	}
	dest_vmid = VMID_HLOS;
	dest_perms = PERM_READ | PERM_WRITE;

	ret = hyp_assign_table(buffer->priv_virt, &source_vm, 1,
			       &dest_vmid, &dest_perms, 1);
	if (ret) {
		pr_err("%s: Not freeing memory since assign call failed\n",
		       __func__);
		return;
	}

	buffer->heap = secure_heap->sys_heap;
	secure_heap->sys_heap->ops->free(buffer);
}

static int ion_system_secure_heap_allocate(
					struct ion_heap *heap,
					struct ion_buffer *buffer,
					unsigned long size, unsigned long align,
					unsigned long flags)
{
	int ret = 0;
	u32 source_vm;
	int dest_vmid;
	int dest_perms;
	struct ion_system_secure_heap *secure_heap = container_of(heap,
						struct ion_system_secure_heap,
						heap);

	if (!ion_heap_is_system_secure_heap_type(secure_heap->heap.type) ||
	    !is_cp_flag_present(flags)) {
		pr_info("%s: Incorrect heap type or incorrect flags\n",
			__func__);
		return -EINVAL;
	}

	ret = secure_heap->sys_heap->ops->allocate(secure_heap->sys_heap,
						buffer, size, align, flags);
	if (ret) {
		pr_info("%s: Failed to get allocation for %s, ret = %d\n",
			__func__, heap->name, ret);
		return ret;
	}

	source_vm = VMID_HLOS;
	dest_vmid = get_secure_vmid(flags);
	if (dest_vmid < 0) {
		pr_info("%s: Unable to get secure VMID\n", __func__);
		ret = -EINVAL;
		goto err;
	}
	dest_perms = PERM_READ | PERM_WRITE;

	ret = hyp_assign_table(buffer->priv_virt, &source_vm, 1,
			       &dest_vmid, &dest_perms, 1);
	if (ret) {
		pr_err("%s: Assign call failed\n", __func__);
		goto err;
	}
	return ret;

err:
	ion_system_secure_heap_free(buffer);
	return ret;
}

static struct sg_table *ion_system_secure_heap_map_dma(
			struct ion_heap *heap, struct ion_buffer *buffer)
{
	struct ion_system_secure_heap *secure_heap = container_of(heap,
						struct ion_system_secure_heap,
						heap);

	return secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap,
							buffer);
}

static void ion_system_secure_heap_unmap_dma(struct ion_heap *heap,
					     struct ion_buffer *buffer)
{
	struct ion_system_secure_heap *secure_heap = container_of(heap,
						struct ion_system_secure_heap,
						heap);

	secure_heap->sys_heap->ops->unmap_dma(secure_heap->sys_heap,
							buffer);
}

static void *ion_system_secure_heap_map_kernel(struct ion_heap *heap,
					       struct ion_buffer *buffer)
{
	pr_info("%s: Kernel mapping from secure heap %s disallowed\n",
		__func__, heap->name);
	return ERR_PTR(-EINVAL);
}

static void ion_system_secure_heap_unmap_kernel(struct ion_heap *heap,
						struct ion_buffer *buffer)
{
}

static int ion_system_secure_heap_map_user(struct ion_heap *mapper,
					   struct ion_buffer *buffer,
					   struct vm_area_struct *vma)
{
	pr_info("%s: Mapping from secure heap %s disallowed\n",
		__func__, mapper->name);
	return -EINVAL;
}

static int ion_system_secure_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
					 int nr_to_scan)
{
	struct ion_system_secure_heap *secure_heap = container_of(heap,
						struct ion_system_secure_heap,
						heap);

	return secure_heap->sys_heap->ops->shrink(secure_heap->sys_heap,
						gfp_mask, nr_to_scan);
}

static struct ion_heap_ops system_secure_heap_ops = {
	.allocate = ion_system_secure_heap_allocate,
	.free = ion_system_secure_heap_free,
	.map_dma = ion_system_secure_heap_map_dma,
	.unmap_dma = ion_system_secure_heap_unmap_dma,
	.map_kernel = ion_system_secure_heap_map_kernel,
	.unmap_kernel = ion_system_secure_heap_unmap_kernel,
	.map_user = ion_system_secure_heap_map_user,
	.shrink = ion_system_secure_heap_shrink,
};

struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused)
{
	struct ion_system_secure_heap *heap;

	heap = kzalloc(sizeof(*heap), GFP_KERNEL);
	if (!heap)
		return ERR_PTR(-ENOMEM);
	heap->heap.ops = &system_secure_heap_ops;
	heap->heap.type = ION_HEAP_TYPE_SYSTEM_SECURE;
	heap->sys_heap = get_ion_heap(ION_SYSTEM_HEAP_ID);
	return &heap->heap;
}

void ion_system_secure_heap_destroy(struct ion_heap *heap)
{
	kfree(heap);
}
+31 −0
Original line number Diff line number Diff line
@@ -57,6 +57,10 @@ static struct ion_heap_desc ion_heap_meta[] = {
		.id	= ION_SYSTEM_CONTIG_HEAP_ID,
		.name	= ION_KMALLOC_HEAP_NAME,
	},
	{
		.id	= ION_SECURE_HEAP_ID,
		.name	= ION_SECURE_HEAP_NAME,
	},
	{
		.id	= ION_CP_MM_HEAP_ID,
		.name	= ION_MM_HEAP_NAME,
@@ -372,6 +376,7 @@ static struct heap_types_info {
	MAKE_HEAP_TYPE_MAPPING(CARVEOUT),
	MAKE_HEAP_TYPE_MAPPING(CHUNK),
	MAKE_HEAP_TYPE_MAPPING(DMA),
	MAKE_HEAP_TYPE_MAPPING(SYSTEM_SECURE),
};

static int msm_ion_get_heap_type_from_dt_node(struct device_node *node,
@@ -649,6 +654,11 @@ static int check_vaddr_bounds(unsigned long start, unsigned long end)
	return ret;
}

int ion_heap_is_system_secure_heap_type(enum ion_heap_type type)
{
	return type == ((enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE);
}

int ion_heap_allow_heap_secure(enum ion_heap_type type)
{
	return false;
@@ -880,6 +890,9 @@ static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data)
	struct ion_heap *heap = NULL;

	switch ((int)heap_data->type) {
	case ION_HEAP_TYPE_SYSTEM_SECURE:
		heap = ion_system_secure_heap_create(heap_data);
		break;
	default:
		heap = ion_heap_create(heap_data);
	}
@@ -903,11 +916,29 @@ static void msm_ion_heap_destroy(struct ion_heap *heap)
		return;

	switch ((int)heap->type) {
	case ION_HEAP_TYPE_SYSTEM_SECURE:
		ion_system_secure_heap_destroy(heap);
		break;
	default:
		ion_heap_destroy(heap);
	}
}

struct ion_heap *get_ion_heap(int heap_id)
{
	int i;
	struct ion_heap *heap;

	for (i = 0; i < num_heaps; i++) {
		heap = heaps[i];
		if (heap->id == heap_id)
			return heap;
	}

	pr_err("%s: heap_id %d not found\n", __func__, heap_id);
	return NULL;
}

static int msm_ion_probe(struct platform_device *pdev)
{
	static struct ion_device *new_dev;
+15 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
enum msm_ion_heap_types {
	ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
	ION_HEAP_TYPE_SECURE_DMA = ION_HEAP_TYPE_MSM_START,
	ION_HEAP_TYPE_SYSTEM_SECURE,
	/*
	 * if you add a heap type here you should also add it to
	 * heap_types_info[] in msm_ion.c
@@ -24,6 +25,7 @@ enum msm_ion_heap_types {
enum ion_heap_ids {
	INVALID_HEAP_ID = -1,
	ION_CP_MM_HEAP_ID = 8,
	ION_SECURE_HEAP_ID = 9,
	ION_CP_MFC_HEAP_ID = 12,
	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
@@ -65,6 +67,18 @@ enum cp_mem_usage {
	UNKNOWN = 0x7FFFFFFF,
};

/**
 * Flags to be used when allocating from the secure heap for
 * content protection
 */
#define ION_FLAG_CP_TOUCH ((1 << 17))
#define ION_FLAG_CP_BITSTREAM ((1 << 18))
#define ION_FLAG_CP_PIXEL  ((1 << 19))
#define ION_FLAG_CP_NON_PIXEL ((1 << 20))
#define ION_FLAG_CP_CAMERA ((1 << 21))
#define ION_FLAG_CP_HLOS ((1 << 22))
#define ION_FLAG_CP_HLOS_FREE ((1 << 23))

/**
 * Flag to use when allocating to indicate that a heap is secure.
 * Do NOT use BIT macro since it is defined in #ifdef __KERNEL__
@@ -110,6 +124,7 @@ enum cp_mem_usage {
#define ION_PIL1_HEAP_NAME  "pil_1"
#define ION_PIL2_HEAP_NAME  "pil_2"
#define ION_QSECOM_HEAP_NAME	"qsecom"
#define ION_SECURE_HEAP_NAME	"secure_heap"

#define ION_SET_CACHED(__cache)		((__cache) | ION_FLAG_CACHED)
#define ION_SET_UNCACHED(__cache)	((__cache) & ~ION_FLAG_CACHED)