The Android ION memory allocator
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); }; |
위의 callback 들을 간략 요약하면, allocate() 와 free()는 각각 ion_buffer object 를 heap으로 부터 할당 하고 해제한다. phys()는 ion 에 할당된 buffer 의 physical address와 length를 반환한다. 하지만 연속적인 영역에서만 사용 가능하다. (ION_HEAP_TYPE_SYSTEM 의 경우는 불가). 만약 특정 heap type 이 물리적으로 연속적인 공간을 할당 해줄 수 없다면 이 interface는 제공할 필요 없다. 현재 phys()는 physical address 를 ion_phys_addr_t 로 제공이 되는데(이는 unsigned long의 typedef임) 향후 phys_addr_t 로 대체될 예정이다.(include/linux/typs.h). map_dma() 와 unmap_dma() callback 은 DMA를 위해 준비되는 buffer 를 만든다. map_kernel(), unmap_kernel() 은 physical memory 를 kernel virtual address로 map(or unmap) 한다. map_user()는 map_kernel() 과 다르게 user space에 map 한다. unmap_user() 는 없는데 이 mapping 이 user space 에서는 file descriptor 형태로 표현되기 때문이다. 그래서 user 에서는 이 file descritor를 closing 하면 자동으로 unmap 된다는 것이다.
기본적인 ION driver 가 제공하는 3가지 heap type은,
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. |
위에서 ION_HEAP_TYPE_SYSTEM이 vmalloc interface 로 할당되는 것으로 나와 있으나 최근 code를 보면 alloc_page를 통해 할당되도록 수정 되어 있다.
또한 개발자들은 새로운 ION heap type을 추가 할 수 있다. 예를 들면 NVIDIA 에서는 ION_HEAP_TYPE_IOMMU 라는 type을 추가 하여 사용한다.
Using ION from user space
전형적으로, user space device 는 연속적인 media buffer 를 할당하기 위해 ION을 사용할 것이다. 예를 들면, camera library는 camera device에서 사용가능한 하나의 capture buffer 를 할당 할 것이다. 일단 이 buffer 에 video data 가 가득 차게 되면, library는 kernel을 통해 이 buffer를 JPEG encoder H/W 에 전달하여 처리하도록 한다.
하나의 user space C/C++ program은 ION을 통해 memory 할당을 하기 위해서는 "/dev/ion"을 open하여 접근권한을 얻어야 한다. user program에서 open("/dev/ion", O_RDONLY); 하게 되면 하나의 ION client를 표현하는 handle인 file descriptor 를 반환한다. open 할 때, O_RDONLY로 open 하더라도 쓰기 가능한 memory 를 얻을 수 있다. user program에서 buffer 를 할당 받기 위해서는 아래의 data struct 에서 handle을 제외하고 나머지는 채워줘야 한다.
struct ion_allocation_data { size_t len; size_t align; unsigned int flags; struct ion_handle *handle;} |
handle 항목은 output parameter 가 되며, len, align, flags 는 input parameter 가 된다. 여기서 flags는 위에서 살펴 본 type의 mask 값들이(물론 추가적으로 들어간 type을 포함) 하나 혹은 하나 이상의 값으로 들어간다. 하나 이상으로 들어간 flag 중, booting 때 ion_device_add_heap() 을 통해 추가되었던 순서대로 먼저 할당이 된다. 기본 구현은 ION_HEAP_TYPE_CARVEOUT 은 ION_HEAP_TYPE_SYSTEM_CONTIG 전에 추가된다. ION_HEAP_TYPE_SYSTEM_CONTIG | ION_HEAP_TYPE_CARVEOUT 로 flag를 지정 시, ION_HEAP_TYPE_SYSTEM_CONTIG 보다 ION_HEAP_TYPE_CARVEOUT에서 먼저 할당할 의도로 보인다.
User-space client 는 ioctl system call로 ion 관련 control 한다. Buffer를 할당 하기 위해 아래와 같이 쓴다.
int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data) |
이 호출은, CPU 가 접근할 수 있는 buffer pointer 가 아닌 ion_handle로 전달된다.(ion_allocation_data struct 내부에 넣어져 전달됨) 그 handle은 단지 buffer sharing을 위한 file desciprtor를 얻어 사용되기 위함이다.
int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data); |
여기서 client_fd 는 /dev/ion 에 대응되는 file descriptor 이다. 그리고 fd_data structure는 handle(ion_handle) 을 input으로 받고 fd 를 output으로 준다.
struct ion_fd_data {struct ion_handle *handle; int fd; } |
fd 는 sharing을 위해 전달된 file descriptor 이다. Android 에서는 Binder IPC 메커니즘을 이용해서 다른 process 와 공유하기 위해 fd 를 전달 하여 사용할 수 있다. 여기서 shared buffer를 얻으려면, second user process 에서 일단 open("/dev/ion", O_RDONLY) 를 통해 client를 얻어야 한다. ION은 process의 PID 를 갖고 user space의 client를 tracking 할 수 있다. 만약 같은 process 에서 open("/dev/ion", O_RDONLY)를 반복해서 호출하면 커널에 갖고 있는 같은 client struct 에 대응하는 다른 서로 다른 file descriptor 를 제공할 것이다.
buffer 를 free하기 위해서는 second process 에서 munmap() 호출로 mmap() 을 되돌리는 것이 요구된다. 그리고 첫 ION_IOC_SHARE를 통해 file decriptor를 얻었던 process 에서 close를 해주어야 한다.
int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data); |
여기서 ion_handle_data는 handle을 갖고 있어야 한다.
struct ion_handle_data {struct ion_handle *handle; } |
ION_IOC_FREE command로 kernel에서 이 handle의 reference count 를 감소만 시킨다. 만약 이 reference count가 0이 되면 ion_handle object 를 free한다. 그리고 ION 을 reserve하고 있는 data structure를 업데이트 해준다.
이 일련의 과정을 예제 application으로 linaro git에 있는 것을 찾았다. 하지만 이것은 사용법에 준하는 소스 code이며 process 간 공유하는 예제는 아니라서 조금 아쉽다.
일단은 처음 client를 만드는 process에서 어떻게 ion ioctl을 하는지 flow만큼은 볼 수 있을 것이다.
Sharing ION buffers in the kernel
kernel 에서 ION 은 multiple client를 지원한다. Kernel driver 는 ION clien handle을 얻기 위해 아래의 함수를 호출한다.
struct ion_client *ion_client_create(struct ion_device *dev, unsigned int heap_mask, const char *debug_name) |
첫번째 argument "dev"는 /dev/ion 에 연결되어 있는 global ION device 이다. 왜 이 global device 가 필요하고 parameter로 넘겨줘야 하는지 명백하진 않다. 두 번째는 heap_mask 인데 ion_allocation_data를 사용하여 채워줬던 것 처럼 heap의 type을 하나 혹은 그 이상을 지정해서 넣어준다. (flags에 넣너준것이다.) 스마트 폰의 경우 multimedia middleware를 포함하여 사용되는 경우처럼 user process는 전형적으로 ION을 통해 buffer를 할당 하고 ION_IOC_SHARE로 file desciptor를 얻은 후 kernel로 file descriptor를 넘겨준다. 하지만 kernel은 ion_import_fd()함수를 이용해 file descriptro를 ion_handle object로 변경한다.
struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user); |
ion_handle object 는 driver 의 shared buffer를 참조하는 client 이다. ion_import_fd() 호출은 이 parameter로 들어온 client가 기존에 이미 할당되고 다른 곳에서 사용되는지 확인한다. 확인하여 기존에 이미 사용되고 있는 handle이라면 단순히 reference count만 증가시킬 것이다.
어떤 H/W는 물리적으로 연속적인 memory를 갖고(CARVEOUT type) 사용되어 질 수 있다. 그럴 경우에 ion_handle을 통해 physicall buffer 를 얻어올 수 있다.
int ion_phys(struct ion_client *client, struct ion_handle *handle,ion_phys_addr_t *addr, size_t *len) |
만약 물리적으로 연속적인 memory가 아니라면, 이 ion_phys() 호출은 실패 할 것이다.
client로 부터 hadling을 호출 할때, ION은 항상 input file descriptor, client 와 handle argument를 확인한다. 예를 들어 file descriptor를 import 할 때, ION은 ION_IOC_SHARE command에 의해 생성된 file descriptor인지 확인한다. ion_phys() 호출 때는 buffer handle이 갖고 있는 접근 가능한 client handle의 list에 들어있는지 확인하고 없다면 error를 return한다.
ION은 debugging을 위해 debugfs도 제공한다. debug 정보는 /sys/kernel/debug/ion에 있으며 이 정보는 연관된 heap 과 client 등이 있다. (PID 나 symbolic name으로 표시된다)
다음에는 driver와 user process 에서 ion buffer 를 sharing 하는 방법을 알아보도록 한다.
'Linux Kernel Study' 카테고리의 다른 글
[번역] The Kernel Boot Process - 32bit X86 (2) | 2013.04.01 |
---|---|
[ION] Sharing a buffer between kernel-space and user-space (0) | 2013.03.28 |
[번역] How Computers Boot Up (0) | 2013.03.13 |
lists.infradead.org Mailing Lists (0) | 2011.09.28 |
Professional Linux Kernel Architecture - Chapter 2, 2.3.3 (0) | 2011.07.28 |