ION基本概念介绍

chipset: MSM8X25Q

codebase: Android 4.1


ION概念:

 ION是Google的下一代内存管理器,用来支持不同的内存分配机制,如CARVOUT(PMEM),物理连续内存(kmalloc), 虚拟地址连续但物理不连续内存(vmalloc), IOMMU等。

用户空间和内核空间都可以使用ION,用户空间是通过/dev/ion来创建client的。

说到client, 顺便看下ION相关比较重要的几个概念。

 Heap: 用来表示内存分配的相关信息,包括id, type, name等。用struct ion_heap表示。

Client: Ion的使用者,用户空间和内核控件要使用ION的buffer,必须先创建一个client,一个client可以有多个buffer,用struct ion_buffer表示。

Handle: 将buffer该抽象出来,可以认为ION用handle来管理buffer,一般用户直接拿到的是handle,而不是buffer。 用struct ion_handle表示。

heap类型:

由于ION可以使用多种memory分配机制,例如物理连续和不连续的,所以ION使用enum ion_heap_type表示。

/**
 * enum ion_heap_types - list of all possible types of heaps
 * @ION_HEAP_TYPE_SYSTEM:	 memory allocated via vmalloc
 * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
 * @ION_HEAP_TYPE_CARVEOUT:	 memory allocated from a prereserved
 * 				 carveout heap, allocations are physically
 * 				 contiguous
 * @ION_HEAP_TYPE_IOMMU: IOMMU memory
 * @ION_HEAP_TYPE_CP:	 memory allocated from a prereserved
 *				carveout heap, allocations are physically
 *				contiguous. Used for content protection.
 * @ION_HEAP_TYPE_DMA:          memory allocated via DMA API
 * @ION_HEAP_END:		helper for iterating over heaps
 */
enum ion_heap_type {
	ION_HEAP_TYPE_SYSTEM,
	ION_HEAP_TYPE_SYSTEM_CONTIG,
	ION_HEAP_TYPE_CARVEOUT,
	ION_HEAP_TYPE_IOMMU,
	ION_HEAP_TYPE_CP,
	ION_HEAP_TYPE_DMA,
	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
				 are at the end of this enum */
	ION_NUM_HEAPS,
};

代码中的注释很明确地说明了哪种type对应的是分配哪种memory。不同type的heap需要不同的method去分配,不过都是用struction_heap_ops来表示的。如以下例子:

static struct ion_heap_ops carveout_heap_ops = {
	.allocate = ion_carveout_heap_allocate,
	.free = ion_carveout_heap_free,
	.phys = ion_carveout_heap_phys,
	.map_user = ion_carveout_heap_map_user,
	.map_kernel = ion_carveout_heap_map_kernel,
	.unmap_user = ion_carveout_heap_unmap_user,
	.unmap_kernel = ion_carveout_heap_unmap_kernel,
	.map_dma = ion_carveout_heap_map_dma,
	.unmap_dma = ion_carveout_heap_unmap_dma,
	.cache_op = ion_carveout_cache_ops,
	.print_debug = ion_carveout_print_debug,
	.map_iommu = ion_carveout_heap_map_iommu,
	.unmap_iommu = ion_carveout_heap_unmap_iommu,
};

static struct ion_heap_ops kmalloc_ops = {
	.allocate = ion_system_contig_heap_allocate,
	.free = ion_system_contig_heap_free,
	.phys = ion_system_contig_heap_phys,
	.map_dma = ion_system_contig_heap_map_dma,
	.unmap_dma = ion_system_heap_unmap_dma,
	.map_kernel = ion_system_heap_map_kernel,
	.unmap_kernel = ion_system_heap_unmap_kernel,
	.map_user = ion_system_contig_heap_map_user,
	.cache_op = ion_system_contig_heap_cache_ops,
	.print_debug = ion_system_contig_print_debug,
	.map_iommu = ion_system_contig_heap_map_iommu,
	.unmap_iommu = ion_system_heap_unmap_iommu,
};

Heap ID:

同一种type的heap上当然可以分为若该干个chunk供用户使用,所以ION又使用ID来区分了。例如在type为ION_HEAP_TYPE_CARVEOUT的heap上,audio和display部分都需要使用,ION就用ID来区分。

Heap id用enumion_heap_ids表示。

/**
 * These are the only ids that should be used for Ion heap ids.
 * The ids listed are the order in which allocation will be attempted
 * if specified. Don't swap the order of heap ids unless you know what
 * you are doing!
 * Id's are spaced by purpose to allow new Id's to be inserted in-between (for
 * possible fallbacks)
 */

enum ion_heap_ids {
	INVALID_HEAP_ID = -1,
	ION_CP_MM_HEAP_ID = 8,
	ION_CP_MFC_HEAP_ID = 12,
	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
	ION_SF_HEAP_ID = 24,
	ION_IOMMU_HEAP_ID = 25,
	ION_QSECOM_HEAP_ID = 26,
	ION_AUDIO_HEAP_BL_ID = 27,
	ION_AUDIO_HEAP_ID = 28,

	ION_MM_FIRMWARE_HEAP_ID = 29,
	ION_SYSTEM_HEAP_ID = 30,

	ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
};

Heap 定义:

       了解了heaptype和id,看看如何被用到了,本平台使用的文件为board-qrd7627a.c,有如下定义:
/**
 * These heaps are listed in the order they will be allocated.
 * Don't swap the order unless you know what you are doing!
 */
struct ion_platform_heap msm7627a_heaps[] = {
		{
			.id	= ION_SYSTEM_HEAP_ID,
			.type	= ION_HEAP_TYPE_SYSTEM,
			.name	= ION_VMALLOC_HEAP_NAME,
		},
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
		/* PMEM_ADSP = CAMERA */
		{
			.id	= ION_CAMERA_HEAP_ID,
			.type	= CAMERA_HEAP_TYPE,
			.name	= ION_CAMERA_HEAP_NAME,
			.memory_type = ION_EBI_TYPE,
			.extra_data = (void *)&co_mm_ion_pdata,
			.priv	= (void *)&ion_cma_device.dev,
		},
		/* AUDIO HEAP 1*/
		{
			.id	= ION_AUDIO_HEAP_ID,
			.type	= ION_HEAP_TYPE_CARVEOUT,
			.name	= ION_AUDIO_HEAP_NAME,
			.memory_type = ION_EBI_TYPE,
			.extra_data = (void *)&co_ion_pdata,
		},
		/* PMEM_MDP = SF */
		{
			.id	= ION_SF_HEAP_ID,
			.type	= ION_HEAP_TYPE_CARVEOUT,
			.name	= ION_SF_HEAP_NAME,
			.memory_type = ION_EBI_TYPE,
			.extra_data = (void *)&co_ion_pdata,
		},
		/* AUDIO HEAP 2*/
		{
			.id    = ION_AUDIO_HEAP_BL_ID,
			.type  = ION_HEAP_TYPE_CARVEOUT,
			.name  = ION_AUDIO_BL_HEAP_NAME,
			.memory_type = ION_EBI_TYPE,
			.extra_data = (void *)&co_ion_pdata,
			.base = BOOTLOADER_BASE_ADDR,
		},

#endif
};

ION Handle:

当Ion client分配buffer时,相应的一个唯一的handle也会被指定,当然client可以多次申请ion buffer。申请好buffer之后,返回的是一个ion handle, 不过要知道Ion buffer才和实际的内存相关,包括size, address等信息。Struct ion_handle和struct ion_buffer如下:

/**
 * ion_handle - a client local reference to a buffer
 * @ref:		reference count
 * @client:		back pointer to the client the buffer resides in
 * @buffer:		pointer to the buffer
 * @node:		node in the client's handle rbtree
 * @kmap_cnt:		count of times this client has mapped to kernel
 * @dmap_cnt:		count of times this client has mapped for dma
 *
 * Modifications to node, map_cnt or mapping should be protected by the
 * lock in the client.  Other fields are never changed after initialization.
 */
struct ion_handle {
	struct kref ref;
	struct ion_client *client;
	struct ion_buffer *buffer;
	struct rb_node node;
	unsigned int kmap_cnt;
	unsigned int iommu_map_cnt;
};

/**
 * struct ion_buffer - metadata for a particular buffer
 * @ref:		refernce count
 * @node:		node in the ion_device buffers tree
 * @dev:		back pointer to the ion_device
 * @heap:		back pointer to the heap the buffer came from
 * @flags:		buffer specific flags
 * @size:		size of the buffer
 * @priv_virt:		private data to the buffer representable as
 *			a void *
 * @priv_phys:		private data to the buffer representable as
 *			an ion_phys_addr_t (and someday a phys_addr_t)
 * @lock:		protects the buffers cnt fields
 * @kmap_cnt:		number of times the buffer is mapped to the kernel
 * @vaddr:		the kenrel mapping if kmap_cnt is not zero
 * @dmap_cnt:		number of times the buffer is mapped for dma
 * @sg_table:		the sg table for the buffer if dmap_cnt is not zero
*/
struct ion_buffer {
	struct kref ref;
	struct rb_node node;
	struct ion_device *dev;
	struct ion_heap *heap;
	unsigned long flags;
	size_t size;
	union {
		void *priv_virt;
		ion_phys_addr_t priv_phys;
	};
	struct mutex lock;
	int kmap_cnt;
	void *vaddr;
	int dmap_cnt;
	struct sg_table *sg_table;
	int umap_cnt;
	unsigned int iommu_map_cnt;
	struct rb_root iommu_maps;
	int marked;
};

ION Client:

         用户空间和内核空间都可以成为client,不过创建的方法稍稍有点区别,先了解下基本的操作流程吧。

 内核空间:

先创建client:

struct ion_client *ion_client_create(struct ion_device *dev,
				     unsigned int heap_mask,
				     const char *name)

heap_mask: 可以分配的heap type,如carveout,system heap, iommu等。

高通使用msm_ion_client_create函数封装了下。

 有了client之后就可以分配内存:

struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
			     size_t align, unsigned int flags)

flags: 分配的heap id.

 有了handle也就是buffer之后就准备使用了,不过还是物理地址,需要map:

void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
			unsigned long flags)

用户空间:

         用户空间如果想使用ION,也必须先要创建client,不过它是打开/dev/ion,实际上它最终也会调用ion_client_create。

         不过和内核空间创建client的一点区别是,用户空间不能选择heap type,但是内核空间却可以。

         另外,用户空间是通过IOCTL来分配内存的,cmd为ION_IOC_ALLOC.

ion_fd = open("/dev/ion", O_ RDONLY | O_SYNC); 
ioctl(ion_fd, ION_IOC_ALLOC, alloc); 

alloc为struct ion_allocation_data,len是申请buffer的长度,flags是heap id。

/**
 * struct ion_allocation_data - metadata passed from userspace for allocations
 * @len:	size of the allocation
 * @align:	required alignment of the allocation
 * @flags:	flags passed to heap
 * @handle:	pointer that will be populated with a cookie to use to refer
 *		to this allocation
 *
 * Provided by userspace as an argument to the ioctl
 */
struct ion_allocation_data {
	size_t len;
	size_t align;
	unsigned int flags;
	struct ion_handle *handle;
};

分配好了buffer之后,如果用户空间想使用buffer,先需要mmap. ION是通过先调用IOCTL中的ION_IOC_SHARE/ION_IOC_MAP来得到可以mmap的fd,然后再执行mmap得到bufferaddress.

         然后,你也可以将此fd传给另一个进程,如通过binder传递。在另一个进程中通过ION_IOC_IMPORT这个IOCTL来得到这块共享buffer了。

 来看一个例子:

进程A:
int ionfd = open("/dev/ion", O_RDONLY | O_DSYNC); 
alloc_data.len = 0x1000; 
alloc_data.align = 0x1000; 
alloc_data.flags = ION_HEAP(ION_CP_MM_HEAP_ID);  
rc = ioctl(ionfd,ION_IOC_ALLOC, &alloc_data); 
fd_data.handle = alloc_data.handle;  
rc = ioctl(ionfd,ION_IOC_SHARE,&fd_data);  
shared_fd = fd_data.fd; 

进程B:
fd_data.fd = shared_fd; 
rc = ioctl(ionfd,ION_IOC_IMPORT,&fd_data); 

2013/02/18

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值