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

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

ion: carveout: Add secure carveout heap type



A secure carveout heap manages memory that may never be accessed by HLOS.
Several pools of differing types of secure memory may be selected from
based on the flags argument to ion_alloc().

Change-Id: Ieb3d043ab7d5a0e88a32042f9ba24b3535a863ec
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent f92b061e
Loading
Loading
Loading
Loading
+31 −0
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ Required properties for Ion heaps
    - "SYSTEM"
    - "SYSTEM"
    - "SYSTEM_CONTIG"
    - "SYSTEM_CONTIG"
    - "CARVEOUT"
    - "CARVEOUT"
    - "SECURE_CARVEOUT"
    - "CHUNK"
    - "CHUNK"
    - "CP"
    - "CP"
    - "DMA"
    - "DMA"
@@ -41,6 +42,7 @@ Optional properties for Ion heaps
  Will set to a reasonable default value (e.g. the maximum heap size)
  Will set to a reasonable default value (e.g. the maximum heap size)
  if this option is not set.
  if this option is not set.



Example:
Example:
	qcom,ion {
	qcom,ion {
                 compatible = "qcom,msm-ion";
                 compatible = "qcom,msm-ion";
@@ -70,3 +72,32 @@ Example:
                         qcom,ion-heap-type = "CARVEOUT";
                         qcom,ion-heap-type = "CARVEOUT";
                 };
                 };
	};
	};

"SECURE_CARVEOUT"

This heap type is expected to contain multiple child nodes. Each child node
shall contain the following required properties:

- memory-regions:
Refer to Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt

- token:
A u32 containing the set of secure domains which will be able to access the
memory-region.

Example:
qcom,ion {
	compatible = "qcom,msm-ion";
	#address-cells = <1>;
	#size-cells = <0>;

	qcom,ion-heap@14 {
		reg = <14>;
		qcom,ion-heap-type = "SECURE_CARVEOUT";

		node1 {
			memory-regions = <&cp_region>;
			token = <ION_FLAG_CP_TOUCH>;
		};
	};
};
+221 −0
Original line number Original line Diff line number Diff line
@@ -206,3 +206,224 @@ void ion_carveout_heap_destroy(struct ion_heap *heap)
	kfree(carveout_heap);
	kfree(carveout_heap);
	carveout_heap = NULL;
	carveout_heap = NULL;
}
}

#include "msm/msm_ion.h"
#include <soc/qcom/secure_buffer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/msm_ion.h>

struct ion_sc_entry {
	struct list_head list;
	struct ion_heap *heap;
	u32 token;
};

struct ion_sc_heap {
	struct ion_heap heap;
	struct device *dev;
	struct list_head children;
};

static struct ion_heap *ion_sc_find_child(struct ion_heap *heap, u32 flags)
{
	struct ion_sc_heap *manager;
	struct ion_sc_entry *entry;

	manager = container_of(heap, struct ion_sc_heap, heap);
	flags = flags & ION_FLAGS_CP_MASK;
	list_for_each_entry(entry, &manager->children, list) {
		if (entry->token == flags)
			return entry->heap;
	}
	return NULL;
}

static int ion_sc_heap_allocate(struct ion_heap *heap,
				struct ion_buffer *buffer, unsigned long len,
				unsigned long align, unsigned long flags) {
	struct ion_heap *child;

	/* cache maintenance is not possible on secure memory */
	flags &= ~((unsigned long)ION_FLAG_CACHED);
	buffer->flags = flags;

	child = ion_sc_find_child(heap, flags);
	if (!child)
		return -EINVAL;

	return ion_carveout_heap_allocate(child, buffer, len, align, flags);
}

static void ion_sc_heap_free(struct ion_buffer *buffer)
{
	struct ion_heap *child;
	struct sg_table *table = buffer->priv_virt;
	struct page *page = sg_page(table->sgl);
	ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));

	child = ion_sc_find_child(buffer->heap, buffer->flags);
	if (!child) {
		WARN(1, "ion_secure_carvout: invalid buffer flags on free. Memory will be leaked\n.");
		return;
	}

	ion_carveout_free(child, paddr, buffer->size);
	sg_free_table(table);
	kfree(table);
}

static struct ion_heap_ops ion_sc_heap_ops = {
	.allocate = ion_sc_heap_allocate,
	.free = ion_sc_heap_free,
	.phys = ion_carveout_heap_phys,
	.map_dma = ion_carveout_heap_map_dma,
	.unmap_dma = ion_carveout_heap_unmap_dma,
};

static int ion_sc_get_dt_token(struct ion_sc_entry *entry,
			       struct device_node *np, u64 base, u64 size)
{
	u32 token;
	u32 *vmids, *modes;
	u32 nr, i;
	int ret = -EINVAL;
	u32 src_vm = VMID_HLOS;

	if (of_property_read_u32(np, "token", &token))
		return -EINVAL;

	nr = count_set_bits(token);
	vmids = kcalloc(nr, sizeof(*vmids), GFP_KERNEL);
	if (!vmids)
		return -ENOMEM;

	modes = kcalloc(nr, sizeof(*modes), GFP_KERNEL);
	if (!modes) {
		kfree(vmids);
		return -ENOMEM;
	}

	if ((token & ~ION_FLAGS_CP_MASK) ||
	    populate_vm_list(token, vmids, nr)) {
		pr_err("secure_carveout_heap: Bad token %x\n", token);
		goto out;
	}

	for (i = 0; i < nr; i++)
		if (vmids[i] == VMID_CP_SEC_DISPLAY)
			modes[i] = PERM_READ;
		else
			modes[i] = PERM_READ | PERM_WRITE;

	ret = hyp_assign_phys(base, size, &src_vm, 1, vmids, modes, nr);
	if (ret)
		pr_err("secure_carveout_heap: Assign token 0x%x failed\n",
		       token);
	else
		entry->token = token;
out:
	kfree(modes);
	kfree(vmids);
	return ret;
}

static int ion_sc_add_child(struct ion_sc_heap *manager,
			    struct device_node *np)
{
	struct device *dev = manager->dev;
	struct ion_platform_heap heap_data = {0};
	struct ion_sc_entry *entry;
	struct device_node *phandle;
	const __be32 *basep;
	u64 base, size;
	int ret;

	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	INIT_LIST_HEAD(&entry->list);

	phandle = of_parse_phandle(np, "memory-region", 0);
	if (!phandle)
		goto out_free;

	basep = of_get_address(phandle,  0, &size, NULL);
	if (!basep)
		goto out_free;

	base = of_translate_address(phandle, basep);
	if (base == OF_BAD_ADDR)
		goto out_free;

	heap_data.priv = dev;
	heap_data.base = base;
	heap_data.size = size;

	/* This will zero memory initially */
	entry->heap = ion_carveout_heap_create(&heap_data);
	if (IS_ERR(entry->heap))
		goto out_free;

	ret = ion_sc_get_dt_token(entry, np, base, size);
	if (ret)
		goto out_free_carveout;

	list_add(&entry->list, &manager->children);
	dev_info(dev, "ion_secure_carveout: creating heap@0x%llx, size 0x%llx\n",
		 base, size);
	return 0;

out_free_carveout:
	ion_carveout_heap_destroy(entry->heap);
out_free:
	kfree(entry);
	return -EINVAL;
}

void ion_secure_carveout_heap_destroy(struct ion_heap *heap)
{
	struct ion_sc_heap *manager =
		container_of(heap, struct ion_sc_heap, heap);
	struct ion_sc_entry *entry, *tmp;

	list_for_each_entry_safe(entry, tmp, &manager->children, list) {
		ion_carveout_heap_destroy(entry->heap);
		kfree(entry);
	}
	kfree(manager);
}

struct ion_heap *ion_secure_carveout_heap_create(
			struct ion_platform_heap *heap_data)
{
	struct device *dev = heap_data->priv;
	int ret;
	struct ion_sc_heap *manager;
	struct device_node *np;

	manager = kzalloc(sizeof(*manager), GFP_KERNEL);
	if (!manager)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&manager->children);
	manager->dev = dev;

	for_each_child_of_node(dev->of_node, np) {
		ret = ion_sc_add_child(manager, np);
		if (ret) {
			dev_err(dev, "Creating child pool %s failed\n",
				np->name);
			goto err;
		}
	}

	manager->heap.ops = &ion_sc_heap_ops;
	manager->heap.type = ION_HEAP_TYPE_SECURE_CARVEOUT;
	return &manager->heap;

err:
	ion_secure_carveout_heap_destroy(&manager->heap);
	return ERR_PTR(-EINVAL);
}
+11 −0
Original line number Original line Diff line number Diff line
@@ -122,6 +122,10 @@ static struct ion_heap_desc ion_heap_meta[] = {
	{
	{
		.id	= ION_SECURE_DISPLAY_HEAP_ID,
		.id	= ION_SECURE_DISPLAY_HEAP_ID,
		.name	= ION_SECURE_DISPLAY_HEAP_NAME,
		.name	= ION_SECURE_DISPLAY_HEAP_NAME,
	},
	{
		.id	= ION_SECURE_CARVEOUT_HEAP_ID,
		.name	= ION_SECURE_CARVEOUT_HEAP_NAME,
	}
	}
};
};
#endif
#endif
@@ -443,6 +447,7 @@ static struct heap_types_info {
	MAKE_HEAP_TYPE_MAPPING(SYSTEM),
	MAKE_HEAP_TYPE_MAPPING(SYSTEM),
	MAKE_HEAP_TYPE_MAPPING(SYSTEM_CONTIG),
	MAKE_HEAP_TYPE_MAPPING(SYSTEM_CONTIG),
	MAKE_HEAP_TYPE_MAPPING(CARVEOUT),
	MAKE_HEAP_TYPE_MAPPING(CARVEOUT),
	MAKE_HEAP_TYPE_MAPPING(SECURE_CARVEOUT),
	MAKE_HEAP_TYPE_MAPPING(CHUNK),
	MAKE_HEAP_TYPE_MAPPING(CHUNK),
	MAKE_HEAP_TYPE_MAPPING(DMA),
	MAKE_HEAP_TYPE_MAPPING(DMA),
	MAKE_HEAP_TYPE_MAPPING(SECURE_DMA),
	MAKE_HEAP_TYPE_MAPPING(SECURE_DMA),
@@ -1021,6 +1026,9 @@ static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data)
	case ION_HEAP_TYPE_HYP_CMA:
	case ION_HEAP_TYPE_HYP_CMA:
		heap = ion_cma_secure_heap_create(heap_data);
		heap = ion_cma_secure_heap_create(heap_data);
		break;
		break;
	case ION_HEAP_TYPE_SECURE_CARVEOUT:
		heap = ion_secure_carveout_heap_create(heap_data);
		break;
	default:
	default:
		heap = ion_heap_create(heap_data);
		heap = ion_heap_create(heap_data);
	}
	}
@@ -1056,6 +1064,9 @@ static void msm_ion_heap_destroy(struct ion_heap *heap)
	case ION_HEAP_TYPE_HYP_CMA:
	case ION_HEAP_TYPE_HYP_CMA:
		ion_cma_secure_heap_destroy(heap);
		ion_cma_secure_heap_destroy(heap);
		break;
		break;
	case ION_HEAP_TYPE_SECURE_CARVEOUT:
		ion_secure_carveout_heap_destroy(heap);
		break;
	default:
	default:
		ion_heap_destroy(heap);
		ion_heap_destroy(heap);
	}
	}
+5 −1
Original line number Original line Diff line number Diff line
@@ -2,7 +2,7 @@
 * drivers/staging/android/ion/msm_ion_priv.h
 * drivers/staging/android/ion/msm_ion_priv.h
 *
 *
 * Copyright (C) 2011 Google, Inc.
 * Copyright (C) 2011 Google, Inc.
 * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
 *
 *
 * This software is licensed under the terms of the GNU General Public
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * License version 2, as published by the Free Software Foundation, and
@@ -40,6 +40,10 @@ int ion_system_secure_heap_drain(struct ion_heap *heap, void *data);
struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *heap);
struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *heap);
void ion_cma_secure_heap_destroy(struct ion_heap *heap);
void ion_cma_secure_heap_destroy(struct ion_heap *heap);


struct ion_heap *ion_secure_carveout_heap_create(
			struct ion_platform_heap *heap);
void ion_secure_carveout_heap_destroy(struct ion_heap *heap);

long msm_ion_custom_ioctl(struct ion_client *client,
long msm_ion_custom_ioctl(struct ion_client *client,
			  unsigned int cmd,
			  unsigned int cmd,
			  unsigned long arg);
			  unsigned long arg);
+3 −0
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@ enum msm_ion_heap_types {
	ION_HEAP_TYPE_SECURE_DMA = ION_HEAP_TYPE_MSM_START,
	ION_HEAP_TYPE_SECURE_DMA = ION_HEAP_TYPE_MSM_START,
	ION_HEAP_TYPE_SYSTEM_SECURE,
	ION_HEAP_TYPE_SYSTEM_SECURE,
	ION_HEAP_TYPE_HYP_CMA,
	ION_HEAP_TYPE_HYP_CMA,
	ION_HEAP_TYPE_SECURE_CARVEOUT,
	/*
	/*
	 * if you add a heap type here you should also add it to
	 * if you add a heap type here you should also add it to
	 * heap_types_info[] in msm_ion.c
	 * heap_types_info[] in msm_ion.c
@@ -32,6 +33,7 @@ enum ion_heap_ids {
	ION_SECURE_DISPLAY_HEAP_ID = 10,
	ION_SECURE_DISPLAY_HEAP_ID = 10,
	ION_CP_MFC_HEAP_ID = 12,
	ION_CP_MFC_HEAP_ID = 12,
	ION_SPSS_HEAP_ID = 13, /* Secure Processor ION heap */
	ION_SPSS_HEAP_ID = 13, /* Secure Processor ION heap */
	ION_SECURE_CARVEOUT_HEAP_ID = 14,
	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
	ION_QSECOM_TA_HEAP_ID = 19,
	ION_QSECOM_TA_HEAP_ID = 19,
	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
@@ -133,6 +135,7 @@ enum cp_mem_usage {
#define ION_IOMMU_HEAP_NAME	"iommu"
#define ION_IOMMU_HEAP_NAME	"iommu"
#define ION_MFC_HEAP_NAME	"mfc"
#define ION_MFC_HEAP_NAME	"mfc"
#define ION_SPSS_HEAP_NAME	"spss"
#define ION_SPSS_HEAP_NAME	"spss"
#define ION_SECURE_CARVEOUT_HEAP_NAME	"secure_carveout"
#define ION_WB_HEAP_NAME	"wb"
#define ION_WB_HEAP_NAME	"wb"
#define ION_MM_FIRMWARE_HEAP_NAME	"mm_fw"
#define ION_MM_FIRMWARE_HEAP_NAME	"mm_fw"
#define ION_PIL1_HEAP_NAME  "pil_1"
#define ION_PIL1_HEAP_NAME  "pil_1"