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

[html] view plain copy print ?
  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. }; 

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

[html] view plain copy print ?
  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. }; 

Heap ID:

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

Heap id用enumion_heap_ids表示。

[html] view plain copy print ?
  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. }; 

Heap 定义:

       了解了heaptype和id,看看如何被用到了,本平台使用的文件为board-qrd7627a.c,有如下定义:
[html] view plain copy print ?
  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. }; 

ION Handle:

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

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

ION Client:

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

内核空间:

先创建client:

[html] view plain copy print ?
  1. struct ion_client *ion_client_create(struct ion_device *dev, 
  2.                      unsigned int heap_mask, 
  3.                      const char *name) 

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

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

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

[html] view plain copy print ?
  1. struct ion_handle *ion_alloc(struct ion_client *client, size_t len, 
  2.                  size_t align, unsigned int flags) 

flags: 分配的heap id.

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

[html] view plain copy print ?
  1. void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle, 
  2.             unsigned long flags) 

用户空间:

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

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

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

[html] view plain copy print ?
  1. ion_fd = open("/dev/ion", O_ RDONLY | O_SYNC);  
  2. ioctl(ion_fd, ION_IOC_ALLOC, alloc);  

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

[html] view plain copy print ?
  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. * Provided by userspace as an argument to the ioctl 
  9. */ 
  10. struct ion_allocation_data { 
  11.     size_t len; 
  12.     size_t align; 
  13.     unsigned int flags; 
  14.     struct ion_handle *handle; 
  15. }; 

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

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

来看一个例子:

[html] view plain copy print ?
  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);  

2013/02/18

你可能感兴趣的:(ION基本概念介绍)