我是靠谱客的博主 灵巧水壶,最近开发中收集的这篇文章主要介绍The Android ION memory allocator,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

https://lwn.net/Articles/480055/


Back in December 2011, LWN reviewed the list of Android kernel patches in the linux-next staging directory. The merging of these drivers, one of which is a memory allocator called PMEM, holds the promise that the mainline kernel release can one day boot an Android user space. Since then, it has become clear that PMEM is considered obsolete andwill be replaced by the ION memory manager. ION is a generalized memory manager that Google introduced in the Android 4.0 ICS (Ice Cream Sandwich) release to address the issue of fragmented memory management interfaces across different Android devices. There are at least three, probably more, PMEM-like interfaces. On Android devices using NVIDIA Tegra, there is "NVMAP"; on Android devices using TI OMAP, there is "CMEM"; and on Android devices using Qualcomm MSM, there is "PMEM" . All three SoC vendors are in the process of switching to ION.

This article takes a look at ION, summarizing its interfaces to user space and to kernel-space drivers. Besides being a memory pool manager, ION also enables its clients to share buffers, hence it treads the same ground as  the DMA buffer sharing framework from Linaro (DMABUF). This article will end with a comparison of the two buffer sharing schemes.

ION heaps

Like its PMEM-like predecessors, ION manages one or more memory pools, some of which are set aside at boot time to combat fragmentation or to serve special hardware needs. GPUs, display controllers, and cameras are some of the hardware blocks that may have special memory requirements. ION presents its memory pools as ION heaps. Each type of Android device can be provisioned with a different set of ION heaps according to the memory requirements of the device. The provider of an ION heap must implement the following set of callbacks:
   struct ion_heap_ops {
	int (*allocate) (struct ion_heap *heap,
			 struct ion_buffer *buffer, unsigned long len,
			 unsigned long align, unsigned long flags);
	void (*free) (struct ion_buffer *buffer);
	int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
		     ion_phys_addr_t *addr, size_t *len);
	struct scatterlist *(*map_dma) (struct ion_heap *heap,
			 struct ion_buffer *buffer);
	void (*unmap_dma) (struct ion_heap *heap, 
	         struct ion_buffer *buffer);
	void * (*map_kernel) (struct ion_heap *heap, 
	         struct ion_buffer *buffer);
	void (*unmap_kernel) (struct ion_heap *heap, 
	         struct ion_buffer *buffer);
	int (*map_user) (struct ion_heap *heap, struct ion_buffer *buffer,
			 struct vm_area_struct *vma);
   };
Briefly,  allocate() and  free() obtain or release an  ion_buffer object from the heap. A call to  phys() will return the physical address and length of the buffer, but only for physically-contiguous buffers. If the heap does not provide physically contiguous buffers, it does not have to provide this callback. Here  ion_phys_addr_t is a typedef of  unsigned long, and will, someday, be replaced by  phys_addr_t in  include/linux/types.h. The  map_dma() and  unmap_dma() callbacks cause the buffer to be prepared (or unprepared) for DMA. The  map_kernel() and  unmap_kernel() callbacks map (or unmap) the physical memory into the kernel virtual address space. A call to  map_user() will map the memory to user space. There is no  unmap_user() because the mapping is represented as a file descriptor in user space. The closing of that file descriptor will cause the memory to be unmapped from the calling process.

The default ION driver (which can be cloned from here) offers three heaps as listed below:

   ION_HEAP_TYPE_SYSTEM:        memory allocated via vmalloc_user().
   ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kzalloc.
   ION_HEAP_TYPE_CARVEOUT:	carveout memory is physically contiguous and set aside at boot.
Developers may choose to add more ION heaps. For example,  this NVIDIA patch was submitted to add ION_HEAP_TYPE_IOMMU for hardware blocks equipped with an IOMMU.

Using ION from user space

Typically, user space device access libraries will use ION to allocate large contiguous media buffers. For example, the still camera library may allocate a capture buffer to be used by the camera device. Once the buffer is fully populated with video data, the library can pass the buffer to the kernel to be processed by a JPEG encoder hardware block.

A user space C/C++ program must have been granted access to the /dev/ion device before it can allocate memory from ION. A call to open("/dev/ion", O_RDONLY) returns a file descriptor as a handle representing an ION client. Yes, one can allocate writable memory with an O_RDONLY open. There can be no more than one client per user process. To allocate a buffer, the client needs to fill in all the fields except the handle field in this data structure:

   struct ion_allocation_data {
        size_t len;
        size_t align;
        unsigned int flags;
        struct ion_handle *handle;
   }
The  handle field is the output parameter, while the first three fields specify the alignment, length and flags as input parameters. The  flags field is a bit mask indicating one or more ION heaps to allocate from, with the fallback ordered according to which ION heap was first added via calls to  ion_device_add_heap()during boot.  In the default implementation,  ION_HEAP_TYPE_CARVEOUT is added before  ION_HEAP_TYPE_CONTIG. The flags of  ION_HEAP_TYPE_CONTIG | ION_HEAP_TYPE_CARVEOUTindicate the intention to allocate from  ION_HEAP_TYPE_CARVEOUT with fallback to  ION_HEAP_TYPE_CONTIG.

User-space clients interact with ION using the ioctl() system call interface. To allocate a buffer, the client makes this call:

   int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)
This call returns a buffer represented by  ion_handle which is not a CPU-accessible buffer pointer. The handle can only be used to obtain a file descriptor for buffer sharing as follows:
   int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data);
Here  client_fd is the file descriptor corresponding to  /dev/ion, and  fd_data is a data structure with an input  handle field and an output  fd field, as defined below:
   struct ion_fd_data {
        struct ion_handle *handle;
        int fd;
   }
The  fd field is the file descriptor that can be passed around for sharing. On Android devices the  BINDER IPC mechanism may be used to send  fd to another process for sharing. To obtain the shared buffer, the second user process must obtain a client handle first via the  open("/dev/ion", O_RDONLY) system call. ION tracks its user space clients by the PID of the process (specifically, the PID of the thread that is the "group leader" in the process). Repeating the open("/dev/ion", O_RDONLY) call in the same process will get back another file descriptor corresponding to the same client structure in the kernel.

To free the buffer, the second client needs to undo the effect of mmap() with a call to munmap(), and the first client needs to close the file descriptor it obtained via ION_IOC_SHARE, and call ION_IOC_FREE as follows:

     int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data);
Here  ion_handle_data holds the handle as shown below:
     struct ion_handle_data {
	     struct ion_handle *handle;
     }
The  ION_IOC_FREE command causes the handle's reference counter to be decremented by one. When this reference counter reaches zero, the  ion_handle object gets destroyed and the affected ION bookkeeping data structure is updated.

User processes can also share ION buffers with a kernel driver, as explained in the next section.

Sharing ION buffers in the kernel

In the kernel, ION supports multiple clients, one for each driver that uses the ION functionality. A kernel driver calls the following function to obtain an ION client handle:

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

The first argument, dev, is the global ION device associated with /dev/ion; why a global device is needed, and why it must be passed as a parameter, is not entirely clear. The second argument, heap_mask, selects one or more ION heaps in the same way as the ion_allocation_data. The flags field was covered in the previous section. For smart phone use cases involving multimedia middleware, the user process typically allocates the buffer from ION, obtains a file descriptor using the ION_IOC_SHARE command, then passes the file desciptor to a kernel driver. The kernel driver calls ion_import_fd() which converts the file descriptor to an ion_handle object, as shown below:

    struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user);
The  ion_handle object is the driver's client-local reference to the shared buffer. The  ion_import_fd() call looks up the physical address of the buffer to see whether the client has obtained a handle to the same buffer before, and if it has, this call simply increments the reference counter of the existing handle.

Some hardware blocks can only operate on physically-contiguous buffers with physical addresses, so affected drivers need to convert ion_handle to a physical buffer via this call:

   int ion_phys(struct ion_client *client, struct ion_handle *handle,
	       ion_phys_addr_t *addr, size_t *len)

Needless to say, if the buffer is not physically contiguous, this call will fail.

When handling calls from a client, ION always validates the input file descriptor, client and handle arguments. For example, when importing a file descriptor, ION ensures the file descriptor was indeed created by an ION_IOC_SHARE command. When ion_phys() is called, ION validates whether the buffer handle belongs to the list of handles the client is allowed to access, and returns error if the handle is not on the list. This validation mechanism reduces the likelihood of unwanted accesses and inadvertent resource leaks.

ION provides debug visibility through debugfs. It organizes debug information under /sys/kernel/debug/ion, with bookkeeping information in stored files associated with heaps and clients identified by symbolic names or PIDs.

Comparing ION and DMABUF

ION and DMABUF share some common concepts. The dma_buf concept is similar to ion_buffer, while dma_buf_attachment serves a similar purpose as ion_handle. Both ION and DMABUF use anonymous file descriptors as the objects that can be passed around to provide reference-counted access to shared buffers. On the other hand, ION focuses on allocating and freeing memory from provisioned memory pools in a manner that can be shared and tracked, while DMABUF focuses more on buffer importing, exporting and synchronization in a manner that is consistent with buffer sharing solutions on non-ARM architectures.

The following table presents a feature comparison between ION and DMABUF:

FeatureIONDMABUF
Memory Manager RoleION replaces PMEM as the manager of provisioned memory pools. The list of ION heaps can be extended per device.DMABUF is a buffer sharing framework, designed to integrate with the memory allocators in DMA mapping frameworks, like the work-in-progress DMA-contiguous allocator, also known as the Contiguous Memory Allocator (CMA). DMABUF exporters have the option to implement custom allocators.
User Space Access ControlION offers the /dev/ion interface for user-space programs to allocate and share buffers. Any user program with ION access can cripple the system by depleting the ION heaps. Android checks user and group IDs to block unauthorized access to ION heaps.DMABUF offers only kernel APIs. Access control is a function of the permissions on the devices using the DMABUF feature.
Global Client and Buffer DatabaseION contains a device driver associated with /dev/ion. The device structure contains a database that tracks the allocated ION buffers, handles and file descriptors, all grouped by user clients and kernel clients. ION validates all client calls according to the rules of the database. For example, there is a rule that a client cannot have two handles to the same buffer.The DMA debug facility implements a global hashtable, dma_entry_hash, to track DMA buffers, but only when the kernel was built with the CONFIG_DMA_API_DEBUG option.
Cross-architecture UsageION usage today is limited to architectures that run the Android kernel.DMABUF usage is cross-architecture. The DMA mapping redesign preparation patchset modified the DMA mapping code in 9 architectures besides the ARM architecture.
Buffer SynchronizationION considers buffer synchronization to be an orthogonal problem.DMABUF provides a pair of APIs for synchronization. The buffer-user calls dma_buf_map_attachment() whenever it wants to use the buffer for DMA . Once the DMA for the current buffer-user is over, it signals 'end-of-DMA' to the exporter via a call to dma_buf_unmap_attachment() .
Delayed Buffer AllocationION allocates the physical memory before the buffer is shared.DMABUF can defer the allocation until the first call todma_buf_map_attachment(). The exporter of DMA buffer has the opportunity to scan all client attachments, collate their buffer constraints, then choose the appropriate backing storage.

ION and DMABUF can be separately integrated into multimedia applications written using the Video4Linux2 API. In the case of ION, these multimedia programs tend to use PMEM now on Android devices, so switching to ION from PMEM should have a relatively small impact.

Integrating DMABUF into Video4Linux2 is another story. It has taken ten patches to integrate the videobuf2 mechanism with DMABUF; in fairness, many of these revisions were the result of changes to DMABUF as that interface stabilized. The effort should pay dividends in the long run because the DMABUF-based sharing mechanism is designed with DMA mapping hooks for CMA and IOMMU. CMA and IOMMU hold the promise to reduce the amount of carveout memory that it takes to build an Android smart phone. In this email, Andrew Morton was urging the completion of the patch review process so that CMA can get through the 3.4 merge window.

Even though ION and DMABUF serve similar purposes, the two are not mutually exclusive. The Linaro Unified Memory Management team has started to integrate CMA into ION. To reach the state where a release of the mainline kernel can boot the Android user space, the /dev/ion interface to user space must obviously be preserved. In the kernel though, ION drivers may be able to use some of the DMABUF APIs to hook into CMA and IOMMU to take advantage of the capabilities offered by those subsystems. Conversely, DMABUF might be able to leverage ION to present a unified interface to user space, especially to the Android user space. DMABUF may also benefit from adopting some of the ION heap debugging features in order to become more developer friendly. Thus far, many signs indicate that Linaro, Google, and the kernel community are working together to bring the combined strength of ION and DMABUF to the mainline kernel.


( Log in to post comments)

The Android ION memory allocator

Posted Feb 9, 2012 9:31 UTC (Thu) by blackwood (subscriber, #44174) [Link]

Small correction on the dma_buf attach/detach functions: They're just used to reconfigure the pipeline - the exporter is allowed to delay the allocation up to map time and needs to because only by then all devices will be attached. Similarly it's map/unmap that should enforce cache coherency and synchronization and not attach/detach. We'll likely add an extension to allow streaming dma with persistent device mappings.

Also note that map/unmap doesn't synchronize hw access in the sense of gl sync objects. Imo that's an orthogonal issue to buffer sharing and dma buffer allocation. But something we might need to support in the kernel, too, because some SoC have hw-based semaphores and mailboxes to sync up different blocks without the cpu being woken up.

The Android ION memory allocator

Posted Feb 22, 2012 1:42 UTC (Wed) by zengtm (subscriber, #74989) [Link]

In the article it does say that map/unmap is the place to handle cache coherency and buffer synchronization. Did I have wording to indicate attach/detach is for synchronization?

And I agree that the persistent device mappings seem to be the more common smart phone use cases. 

Integration with dma_buf

Posted Feb 11, 2012 16:24 UTC (Sat) by arnd (subscriber, #8866) [Link]

It should not be too hard to modify the ion code so it becomes a provider of dma_buf file descriptors and integrates into that framework.

When we discussed the design for dma_buf, it was intentionally made possible to have arbitrary subsystems provide interfaces that hand out dma_buf file descriptors to user space, although the focus so far was on having drm provide descriptors for buffers that it already manages. If I understand the article correctly, the design of ion is that you always have to know in advance how to allocate your buffer through the ion ioctl but then can pass it into any driver using it.

We should probably look into unifying the in-kernel interfaces for the two, because they are already very similar. and make ION_IOC_SHARE return a dma_buf descriptor that can be passed into any dma_buf enabled driver. The ion_import_fd function can then be replaced with the more abstract dma_buf equivalent.

Integration with dma_buf

Posted Feb 22, 2012 1:44 UTC (Wed) by zengtm (subscriber, #74989) [Link]

"the design of ion is that you always have to know in advance how to allocate your buffer": the answer is yes, based on the ION implementations that I have the chance to study in the current Android 4.0.x release. 

Integration with dma_buf

Posted May 19, 2013 6:54 UTC (Sun) by abai (guest, #91041) [Link]

If user space change the ion memory content, how to flush cache to memery in user space?
I see ION_IOC_SYNC only used for kernel space, it cannot flush user cache, right?

The Android ION memory allocator

Posted Feb 29, 2012 20:43 UTC (Wed) by cliveb (guest, #83236) [Link]

How can I get a physical address for the allocated memory from user space?

The Android ION memory allocator

Posted Mar 14, 2012 17:01 UTC (Wed) by zengtm (subscriber, #74989) [Link]

You cannot get physical address from user space: not secure if you think about it.

The Android ION memory allocator

Posted Jan 4, 2013 13:29 UTC (Fri) by vkkashyap (guest, #88623) [Link]

Thanks for nice article.

- What type of security risks do you foresee?
- Any other reason(s) you see for limiting physical addresses api to kernel space?

The Android ION memory allocator

Posted Jul 5, 2016 0:37 UTC (Tue) by simonwan (guest, #109625) [Link]

Thanks for the article, it's really helpful for me to understand the ION. 

Now I'm writing one simple test program for better understanding the ION device but I always got error -19 when I was trying to allocate the memory. Do you meet this error before? 

I'm considering this is caused by missing permission but I'm not sure. I noticed that the article mentioned that the program should be granted the permission before allocating but I don't know how to do this, could you give me some advice?

Thank you.

The Android ION memory allocator

Posted Jul 5, 2016 13:24 UTC (Tue) by excors (subscriber, #95769) [Link]

The only necessary permission should be read access to /dev/ion, and if you didn't have that permission you wouldn't even be able to open the device.

Error -19 is -ENODEV, and I think ion_alloc can only return that if there are no heaps that match the heap_id_mask in your allocation request, so you should check you're setting that correctly. /sys/kernel/debug/ion/heaps/ should list the heaps available on your device (though you probably need to read the kernel headers to find the enum definitions for them).

Also check that you're calling the right version of the kernel API - lots of details have changed since this article was written (e.g. the heap mask is now a separate field in ion_allocation_data, not part of flags), so you should use libion or read the kernel source from your particular device.

The Android ION memory allocator

Posted Jul 6, 2016 0:59 UTC (Wed) by simonwan (guest, #109625) [Link]

Hi excors,

Thank you for the reply. I tested the program on Android and I checked the /ion/heaps while I get the results as "adsp, audio, kmalloc, mm, qsecom, system" but I don't know where I could find the enum definitions, could you please give me some advice?

Sincerely,
Simon

The Android ION memory allocator

Posted Jul 6, 2016 17:39 UTC (Wed) by excors (subscriber, #95769) [Link]

That looks like a Qualcomm device, so I think you want the ion_heap_ids from msm_ion.h

(The definitions might vary on different versions and different devices - ideally you should find the kernel source for your specific device. Probably most similar-generation Qualcomm devices will be compatible, though.)

If you're using libion, call ion_alloc with heap_mask set to e.g. (1 << ION_SYSTEM_HEAP_ID) to use the system heap. (If you're not using libion, look at its implementation to see how to call the ioctls directly.)

If you want to share the ion buffer with non-CPU bits of hardware (e.g. the GPU or camera), you might need to use one of the other heaps, but the restrictions are not documented anywhere so you'll have to guess.

On non-Qualcomm devices, you might need to set heap_mask to e.g. (1 << ION_HEAP_TYPE_SYSTEM) instead, because some other vendors use those HEAP_TYPE enums as the heap IDs instead of inventing a whole new set of IDs - there are no common standards here. The heap configuration is either hard-coded into the kernel source or loaded from Device Tree, so you'll have to look there if you want to find out the details for other devices.

The Android ION memory allocator

Posted Dec 9, 2016 12:17 UTC (Fri) by avi141 (guest, #112868) [Link]

Hi!

From memory statistics side, i wish to know how many pages are allocated for ion memory.
In structure(ion_buffer) there is a member variable 'pages' , 

Did it hold all pages allocated for ion memory ; and after iterating list we will get exhaustive list of pages for ion memory in system ?
Please guide if any one tried it ; or if understanding is correct.
===========================================

struct page **pages;

63 * @pages: flat array of pages in the buffer -- used by fault
64 * handler and only valid for buffers that are faulted in
71*/

72struct ion_buffer {
73 struct kref ref;
74 union {
75 struct rb_node node;
76 struct list_head list;
77 };
78 struct ion_device *dev;
79 struct ion_heap *heap;
80 unsigned long flags;
81 unsigned long private_flags;
82 size_t size;
83 union {
84 void *priv_virt;
85 ion_phys_addr_t priv_phys;
86 };
87 struct mutex lock;
88 int kmap_cnt;
89 void *vaddr;
90 struct sg_table *sg_table;
91 struct page **pages;
92 struct list_head vmas;
93 /* used to track orphaned buffers */
94 int handle_count;
95 char task_comm[TASK_COMM_LEN];
96 pid_t pid;
97};
=========================================

Regards,
Avinash Jain

最后

以上就是灵巧水壶为你收集整理的The Android ION memory allocator的全部内容,希望文章能够帮你解决The Android ION memory allocator所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部