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表示。

  1. /**  
  2.  * enum ion_heap_types - list of all possible types of heaps  
  3.  * @ION_HEAP_TYPE_SYSTEM:    memory allocated via vmalloc  
  4.  * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc  
  5.  * @ION_HEAP_TYPE_CARVEOUT:  memory allocated from a prereserved  
  6.  *               carveout heap, allocations are physically  
  7.  *               contiguous  
  8.  * @ION_HEAP_TYPE_IOMMU: IOMMU memory  
  9.  * @ION_HEAP_TYPE_CP:    memory allocated from a prereserved  
  10.  *              carveout heap, allocations are physically  
  11.  *              contiguous. Used for content protection.  
  12.  * @ION_HEAP_TYPE_DMA:          memory allocated via DMA API  
  13.  * @ION_HEAP_END:       helper for iterating over heaps  
  14.  */  
  15. enum ion_heap_type {  
  16.     ION_HEAP_TYPE_SYSTEM,  
  17.     ION_HEAP_TYPE_SYSTEM_CONTIG,  
  18.     ION_HEAP_TYPE_CARVEOUT,  
  19.     ION_HEAP_TYPE_IOMMU,  
  20.     ION_HEAP_TYPE_CP,  
  21.     ION_HEAP_TYPE_DMA,  
  22.     ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always  
  23.                  are at the end of this enum */  
  24.     ION_NUM_HEAPS,  
  25. };  
/**
 * 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來表示的。如以下例子:

  1. static struct ion_heap_ops carveout_heap_ops = {  
  2.     .allocate = ion_carveout_heap_allocate,  
  3.     .free = ion_carveout_heap_free,  
  4.     .phys = ion_carveout_heap_phys,  
  5.     .map_user = ion_carveout_heap_map_user,  
  6.     .map_kernel = ion_carveout_heap_map_kernel,  
  7.     .unmap_user = ion_carveout_heap_unmap_user,  
  8.     .unmap_kernel = ion_carveout_heap_unmap_kernel,  
  9.     .map_dma = ion_carveout_heap_map_dma,  
  10.     .unmap_dma = ion_carveout_heap_unmap_dma,  
  11.     .cache_op = ion_carveout_cache_ops,  
  12.     .print_debug = ion_carveout_print_debug,  
  13.     .map_iommu = ion_carveout_heap_map_iommu,  
  14.     .unmap_iommu = ion_carveout_heap_unmap_iommu,  
  15. };  
  16.   
  17. static struct ion_heap_ops kmalloc_ops = {  
  18.     .allocate = ion_system_contig_heap_allocate,  
  19.     .free = ion_system_contig_heap_free,  
  20.     .phys = ion_system_contig_heap_phys,  
  21.     .map_dma = ion_system_contig_heap_map_dma,  
  22.     .unmap_dma = ion_system_heap_unmap_dma,  
  23.     .map_kernel = ion_system_heap_map_kernel,  
  24.     .unmap_kernel = ion_system_heap_unmap_kernel,  
  25.     .map_user = ion_system_contig_heap_map_user,  
  26.     .cache_op = ion_system_contig_heap_cache_ops,  
  27.     .print_debug = ion_system_contig_print_debug,  
  28.     .map_iommu = ion_system_contig_heap_map_iommu,  
  29.     .unmap_iommu = ion_system_heap_unmap_iommu,  
  30. };  
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表示。

  1. /**  
  2.  * These are the only ids that should be used for Ion heap ids.  
  3.  * The ids listed are the order in which allocation will be attempted  
  4.  * if specified. Don't swap the order of heap ids unless you know what  
  5.  * you are doing!  
  6.  * Id's are spaced by purpose to allow new Id's to be inserted in-between (for  
  7.  * possible fallbacks)  
  8.  */  
  9.   
  10. enum ion_heap_ids {  
  11.     INVALID_HEAP_ID = -1,  
  12.     ION_CP_MM_HEAP_ID = 8,  
  13.     ION_CP_MFC_HEAP_ID = 12,  
  14.     ION_CP_WB_HEAP_ID = 16, /* 8660 only */  
  15.     ION_CAMERA_HEAP_ID = 20, /* 8660 only */  
  16.     ION_SF_HEAP_ID = 24,  
  17.     ION_IOMMU_HEAP_ID = 25,  
  18.     ION_QSECOM_HEAP_ID = 26,  
  19.     ION_AUDIO_HEAP_BL_ID = 27,  
  20.     ION_AUDIO_HEAP_ID = 28,  
  21.   
  22.     ION_MM_FIRMWARE_HEAP_ID = 29,  
  23.     ION_SYSTEM_HEAP_ID = 30,  
  24.   
  25.     ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */  
  26. };  
/**
 * 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,有如下定義:
  1. /**  
  2.  * These heaps are listed in the order they will be allocated.  
  3.  * Don't swap the order unless you know what you are doing!  
  4.  */  
  5. struct ion_platform_heap msm7627a_heaps[] = {  
  6.         {  
  7.             .id = ION_SYSTEM_HEAP_ID,  
  8.             .type   = ION_HEAP_TYPE_SYSTEM,  
  9.             .name   = ION_VMALLOC_HEAP_NAME,  
  10.         },  
  11. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION  
  12.         /* PMEM_ADSP = CAMERA */  
  13.         {  
  14.             .id = ION_CAMERA_HEAP_ID,  
  15.             .type   = CAMERA_HEAP_TYPE,  
  16.             .name   = ION_CAMERA_HEAP_NAME,  
  17.             .memory_type = ION_EBI_TYPE,  
  18.             .extra_data = (void *)&co_mm_ion_pdata,  
  19.             .priv   = (void *)&ion_cma_device.dev,  
  20.         },  
  21.         /* AUDIO HEAP 1*/  
  22.         {  
  23.             .id = ION_AUDIO_HEAP_ID,  
  24.             .type   = ION_HEAP_TYPE_CARVEOUT,  
  25.             .name   = ION_AUDIO_HEAP_NAME,  
  26.             .memory_type = ION_EBI_TYPE,  
  27.             .extra_data = (void *)&co_ion_pdata,  
  28.         },  
  29.         /* PMEM_MDP = SF */  
  30.         {  
  31.             .id = ION_SF_HEAP_ID,  
  32.             .type   = ION_HEAP_TYPE_CARVEOUT,  
  33.             .name   = ION_SF_HEAP_NAME,  
  34.             .memory_type = ION_EBI_TYPE,  
  35.             .extra_data = (void *)&co_ion_pdata,  
  36.         },  
  37.         /* AUDIO HEAP 2*/  
  38.         {  
  39.             .id    = ION_AUDIO_HEAP_BL_ID,  
  40.             .type  = ION_HEAP_TYPE_CARVEOUT,  
  41.             .name  = ION_AUDIO_BL_HEAP_NAME,  
  42.             .memory_type = ION_EBI_TYPE,  
  43.             .extra_data = (void *)&co_ion_pdata,  
  44.             .base = BOOTLOADER_BASE_ADDR,  
  45.         },  
  46.   
  47. #endif  
  48. };  
/**
 * 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如下:

  1. /**  
  2.  * ion_handle - a client local reference to a buffer  
  3.  * @ref:        reference count  
  4.  * @client:     back pointer to the client the buffer resides in  
  5.  * @buffer:     pointer to the buffer  
  6.  * @node:       node in the client's handle rbtree  
  7.  * @kmap_cnt:       count of times this client has mapped to kernel  
  8.  * @dmap_cnt:       count of times this client has mapped for dma  
  9.  *  
  10.  * Modifications to node, map_cnt or mapping should be protected by the  
  11.  * lock in the client.  Other fields are never changed after initialization.  
  12.  */  
  13. struct ion_handle {  
  14.     struct kref ref;  
  15.     struct ion_client *client;  
  16.     struct ion_buffer *buffer;  
  17.     struct rb_node node;  
  18.     unsigned int kmap_cnt;  
  19.     unsigned int iommu_map_cnt;  
  20. };  
  21.   
  22. /**  
  23.  * struct ion_buffer - metadata for a particular buffer  
  24.  * @ref:        refernce count  
  25.  * @node:       node in the ion_device buffers tree  
  26.  * @dev:        back pointer to the ion_device  
  27.  * @heap:       back pointer to the heap the buffer came from  
  28.  * @flags:      buffer specific flags  
  29.  * @size:       size of the buffer  
  30.  * @priv_virt:      private data to the buffer representable as  
  31.  *          a void *  
  32.  * @priv_phys:      private data to the buffer representable as  
  33.  *          an ion_phys_addr_t (and someday a phys_addr_t)  
  34.  * @lock:       protects the buffers cnt fields  
  35.  * @kmap_cnt:       number of times the buffer is mapped to the kernel  
  36.  * @vaddr:      the kenrel mapping if kmap_cnt is not zero  
  37.  * @dmap_cnt:       number of times the buffer is mapped for dma  
  38.  * @sg_table:       the sg table for the buffer if dmap_cnt is not zero  
  39. */  
  40. struct ion_buffer {  
  41.     struct kref ref;  
  42.     struct rb_node node;  
  43.     struct ion_device *dev;  
  44.     struct ion_heap *heap;  
  45.     unsigned long flags;  
  46.     size_t size;  
  47.     union {  
  48.         void *priv_virt;  
  49.         ion_phys_addr_t priv_phys;  
  50.     };  
  51.     struct mutex lock;  
  52.     int kmap_cnt;  
  53.     void *vaddr;  
  54.     int dmap_cnt;  
  55.     struct sg_table *sg_table;  
  56.     int umap_cnt;  
  57.     unsigned int iommu_map_cnt;  
  58.     struct rb_root iommu_maps;  
  59.     int marked;  
  60. };  
/**
 * 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:

  1. struct ion_client *ion_client_create(struct ion_device *dev,  
  2.                      unsigned int heap_mask,  
  3.                      const char *name)  
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之後就可以分配內存:

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

flags: 分配的heap id.

 有了handle也就是buffer之後就準備使用了,不過還是物理地址,需要map:

  1. void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,  
  2.             unsigned long flags)  
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.

  1. ion_fd = open("/dev/ion", O_ RDONLY | O_SYNC);   
  2. ioctl(ion_fd, ION_IOC_ALLOC, 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。

  1. /**  
  2.  * struct ion_allocation_data - metadata passed from userspace for allocations  
  3.  * @len:    size of the allocation  
  4.  * @align:  required alignment of the allocation  
  5.  * @flags:  flags passed to heap  
  6.  * @handle: pointer that will be populated with a cookie to use to refer  
  7.  *      to this allocation  
  8.  *  
  9.  * Provided by userspace as an argument to the ioctl  
  10.  */  
  11. struct ion_allocation_data {  
  12.     size_t len;  
  13.     size_t align;  
  14.     unsigned int flags;  
  15.     struct ion_handle *handle;  
  16. };  
/**
 * 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了。

 來看一個例子:

  1. 進程A:  
  2. int ionfd = open("/dev/ion", O_RDONLY | O_DSYNC);   
  3. alloc_data.len = 0x1000;   
  4. alloc_data.align = 0x1000;   
  5. alloc_data.flags = ION_HEAP(ION_CP_MM_HEAP_ID);    
  6. rc = ioctl(ionfd,ION_IOC_ALLOC, &alloc_data);   
  7. fd_data.handle = alloc_data.handle;    
  8. rc = ioctl(ionfd,ION_IOC_SHARE,&fd_data);    
  9. shared_fd = fd_data.fd;   
  10.   
  11. 進程B:  
  12. fd_data.fd = shared_fd;   
  13. rc = ioctl(ionfd,ION_IOC_IMPORT,&fd_data);   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章