ION框架学习(二)
来源:互联网 发布:直销大师软件 编辑:程序博客网 时间:2024/06/05 18:02
第一章介绍:ION的框架和buffer的分配;
第二章介绍:如何使用ION buffer;
前面一章介绍了ION的整体框架及ION_device,ION_client,ION_heap创建和关系;这章将介绍如使使用操作ION;
(一)ion_alloc
用户层已经通过ion_open创建好了client,这个clinet已经跟ION device绑定,现在可以通过ion_alloc()来申请分配内存:
216 if(ion_alloc(217 mIonDrv,218 pInfo->size,219 0, //32 //alignment220 ION_HEAP_MULTIMEDIA_MASK,221 ion_prot_flags,222 &pIonHandle))
system/core/libion/ion.c: 70 int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, 71 unsigned int flags, ion_user_handle_t *handle) 72 { 73 int ret; 74 struct ion_allocation_data data = { 75 .len = len, 76 .align = align, 77 .heap_id_mask = heap_mask,//指定在那个heap分配; 78 .flags = flags, 79 }; 80 81 if (handle == NULL) 82 return -EINVAL; 83 84 ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); 85 if (ret < 0) 86 return ret; 87 *handle = data.handle;//获取到handle之后,返回回去,这个值还不能进程间共享,只能当前进程访问,因为这是一个虚拟地址。 88 return ret; 89 }
调用kernel这边ion device驱动ioctrl()调用ion_alloc()来完成:
450 struct ion_handle *ion_alloc(struct ion_client *client, size_t len, 451 size_t align, unsigned int heap_id_mask, 452 unsigned int flags) //遍历所有heap找到mask标识的heap,然后通过ion_buffer_create()创建buffer; 488 plist_for_each_entry(heap, &dev->heaps, node) { 489 /* if the caller didn't specify this heap id */ 490 if (!((1 << heap->id) & heap_id_mask)) 491 continue; 492 buffer = ion_buffer_create(heap, dev, len, align, flags); 493 if (!IS_ERR(buffer)) 494 break; 495 } //ion handle: 这里每个ion handle映射到一个buffer中,每个buffer关联一个heap。也就是说一个客户端可以操作多块buffer。 508 handle = ion_handle_create(client, buffer); 510 /* 511 * ion_buffer_create will create a buffer with a ref_cnt of 1, 512 * and ion_handle_create will take a second reference, drop one here 513 */ 514 ion_buffer_put(buffer); 522 ret = ion_handle_add(client, handle);//将创建的ion_handle加入到client的红黑树中; 523 mutex_unlock(&client->lock); 524 if (ret) { 525 ion_handle_put(handle); 526 handle = ERR_PTR(ret); 527 IONMSG("%s ion handle add failed %d.\n", __func__, ret); 528 }
下面看看buffer的创建;
107 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, 108 struct ion_device *dev, 109 unsigned long len, 110 unsigned long align, 111 unsigned long flags) 118 buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL); //alloc 128 ret = heap->ops->allocate(heap, buffer, len, align, flags); //map_dma 144 table = heap->ops->map_dma(heap, buffer); 154 if (ion_buffer_fault_user_mappings(buffer)) { 155 int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; 156 struct scatterlist *sg; 157 int i, j, k = 0; 158 159 buffer->pages = vmalloc(sizeof(struct page *) * num_pages); 160 if (!buffer->pages) { 161 IONMSG("%s vamlloc failed pages is null.\n", __func__); 162 ret = -ENOMEM; 163 goto err; 164 } 165 //scatter/gather lists for DMA I/O operations; 166 for_each_sg(table->sgl, sg, table->nents, i) { 167 struct page *page = sg_page(sg); 168 169 for (j = 0; j < sg->length / PAGE_SIZE; j++) 170 buffer->pages[k++] = page++; 171 } 172 } 198 for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { 199 if ((heap->id == ION_HEAP_TYPE_MULTIMEDIA_MAP_MVA) && (align < PAGE_OFFSET)) { 200 if (align < VMALLOC_START || align > VMALLOC_END) { 201 /*userspace va without vmalloc, has no page struct*/ 202 sg->length = sg_dma_len(sg); 203 continue; 204 } 205 } 206 207 sg_dma_address(sg) = sg_phys(sg); 208 sg_dma_len(sg) = sg->length; 209 } 210 mutex_lock(&dev->buffer_lock); 211 ion_buffer_add(dev, buffer); 212 mutex_unlock(&dev->buffer_lock); 213 return buffer;
MULTIMEDIA类型的heap最终调用该注册的ion_heap_ops->ion_mm_heap_allocate()来实现分配:
192 static int ion_mm_heap_allocate(struct ion_heap *heap, 193 struct ion_buffer *buffer, unsigned long size, unsigned long align, 194 unsigned long flags) 247 248 caller_pid = (unsigned int)current->pid; 249 caller_tid = (unsigned int)current->tgid; 250 251 while (size_remaining > 0) { 252 info = alloc_largest_available(sys_heap, buffer, size_remaining, 253 max_order);//每次申请最大的内存 254 if (!info) {//申请的优先级2k->1K 255 IONMSG("%s alloc largest available failed info is null.\n", __func__); 256 goto err; 257 } 258 list_add_tail(&info->list, &pages);//每次申请到的page首地址都会添加到info->list链表中; 259 size_remaining -= (1 << info->order) * PAGE_SIZE; 260 max_order = info->order; 261 i++; 262 } 271 table = kzalloc(sizeof(*table), GFP_KERNEL); 272 if (!table) { 273 IONMSG("%s kzalloc failed table is null.\n", __func__); 274 goto err; 275 } 276 277 ret = sg_alloc_table(table, i, GFP_KERNEL); 278 if (ret) { 279 IONMSG("%s sg alloc table failed %d.\n", __func__, ret); 280 goto err1; 281 } 282 283 sg = table->sgl; 284 list_for_each_entry_safe(info, tmp_info, &pages, list) { 285 struct page *page = info->page; 286 287 sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, 0); 288 sg = sg_next(sg); 289 list_del(&info->list); 290 kfree(info); 291 }
(二)ion_share
ION 通过handle来管理buffer,驱动需要可以访问到buffer的地址。ION通过下面的函数来达到这个目的:
ion_phys: 返回buffer的物理地址(address)及大小(size); ion_map_kernel: 给指定的buffer创建内核内存映射; ion_unmap_kernel: 销毁指定buffer的内核内存映射; ion_map_dma: 为指定buffer创建dma 映射,返回;sglist(scatter/gather list) ion_unmap_dma: 销毁指定buffer的dma映射;
当我们想进程间共享这个buffer时,就需要使用ioctl(fd,ION_IOC_SHARE, &fd_data)来得到这个buffer的唯一id,其中fd_data就是struct ion_fd_data:
54 struct ion_fd_data { 55 ion_user_handle_t handle; 56 int fd; 57 };
创建文件描述符来实现共享内存,ION_IOC_SHARE 及ION_IOC_IMPORT是基于DMABUF实现的,所以当共享进程获取文件描述符后,可以直接调用mmap来操作共享内存。mmap实现由DMABUF子系统调用ION子系统中mmap回调函数完成。
进程之间共享buffer时,也是通过binder机制将共享ion_buffer发送给对应的进程,然后对应的进程在根据这个fd将该块buffer映射进自己的进程中。
在kernel ion driver中可以发现,上层应用通过系统调用将我们想share的ion_handle传下来(其实就是对应idr),然后通过这个handle找到真正的ion_handle。根据ion_buffer在dma buffer中找到其对应的fd,然后其它进程通过这个fd就可以找到对应的buffer了。
ION是通过handle而非buffer地址来实现驱动间共享内存,用户空间共享内存也是利用同样原理。
ion_share: given a handle, obtain a buffer to pass to other clients
ion_import: given an buffer in another client, import it
ion_import_fd: given an fd obtained via ION_IOC_SHARE ioctl, import it
240 if(ion_share(241 mIonDrv,242 pIonHandle,243 &IonBufFd))244 {245 printf("ion_share fail");246 return -1;247 }
1441 case ION_IOC_SHARE:1442 case ION_IOC_MAP:1443 {1444 struct ion_handle *handle;1445 1446 handle = ion_handle_get_by_id(client, data.handle.handle);1447 if (IS_ERR(handle)) {1448 ret = PTR_ERR(handle);1449 IONMSG("ION_IOC_SHARE handle is invalid. handle = %d, ret = %d.\n", data.handle.handle, ret);1450 return ret;1451 }1452 data.fd.fd = ion_share_dma_buf_fd(client, handle);1453 ion_handle_put(handle);1454 if (data.fd.fd < 0) {1455 IONMSG("ION_IOC_SHARE fd = %d.\n", data.fd.fd);1456 ret = data.fd.fd;1457 }1458 break;1459 }
fd:当我们想共享这个buffer时,使用ION_IOC_SHARE kernel就会给我们返回一个唯一标识这个buffer的fd,并保存到fd域中;
1247 int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)1248 {1249 struct dma_buf *dmabuf;1250 int fd;1254 dmabuf = ion_share_dma_buf(client, handle);1255 if (IS_ERR(dmabuf)) {1256 IONMSG("%s dmabuf is err 0x%p.\n", __func__, dmabuf);1257 return PTR_ERR(dmabuf);1258 }1259 1260 fd = dma_buf_fd(dmabuf, O_CLOEXEC);1266 1267 return fd;1268 }
(三)ion_mmap
通过ion_mmap()来Map FD到一个虚拟地址空间;
mmap系统调用,可以让进程的虚拟地址区间里切分出一块指定大小的虚拟地址区间vma_struct,并返回给用户态进程,被mmap映射返回的虚拟地址,逻辑上被消耗了,直到用户进程调用unmmap才会收回来。
250 pInfo->virtAddr = (MUINTPTR)ion_mmap(mIonDrv,NULL, pInfo->size, PROT_READ|PROT_WRITE, MAP_SHARED, IonBufFd, 0);138void* ion_mmap(int fd, void *addr, size_t length, int prot, int flags, int share_fd, off_t offset)139{140 void *mapping_address = NULL;141142 mapping_address = mmap(addr, length, prot, flags, share_fd, offset);143144 if (mapping_address == MAP_FAILED) {145 ALOGE("ion_mmap failed fd = %d, addr = 0x%p, len = %zu, prot = %d, flags = %d, share_fd = %d, 0x%p: %s\n", fd, addr, length,146 prot, flags, share_fd, mapping_address, strerror(errno));147 }148149 return mapping_address;150}
(四)ion_import
另外一个进程想操作buffer,就可以通过ion_import()来实现,通过传入share已经文件描述符IonBufFd;
370 if(ion_import(371 mIonDrv,372 IonBufFd,373 &pIonHandle))
1460 case ION_IOC_IMPORT:1461 { 1462 struct ion_handle *handle;1463 1464 handle = ion_import_dma_buf(client, data.fd.fd);1465 if (IS_ERR(handle)) {1466 ret = PTR_ERR(handle);1467 IONMSG("ion_import fail: fd=%d, ret=%d\n", data.fd.fd, ret);1468 } else1469 data.handle.handle = handle->id;1470 break;1471 }
1271 struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) 1272 {1273 struct dma_buf *dmabuf;1274 struct ion_buffer *buffer;1275 struct ion_handle *handle;1276 int ret;1277 //根据fd获取dma buffer;1278 dmabuf = dma_buf_get(fd);1283 /* if this memory came from ion */1284 1291 buffer = dmabuf->priv;1292 1293 mutex_lock(&client->lock);1294 /* if a handle exists for this buffer just take a reference to it */1295 handle = ion_handle_lookup(client, buffer);1296 if (!IS_ERR(handle)) {1297 ion_handle_get(handle);1298 mutex_unlock(&client->lock);1299 goto end;1300 } //重新创建一个handle;1303 handle = ion_handle_create(client, buffer);1304 if (IS_ERR(handle)) {1305 mutex_unlock(&client->lock);1306 IONMSG("%s handle is error 0x%p.\n", __func__, handle);1307 goto end;1308 }1309 1310 ret = ion_handle_add(client, handle);1311 mutex_unlock(&client->lock);1312 1325 return handle;1326 }1327 EXPORT_SYMBOL(ion_import_dma_buf);
用户空间另一个进程也得到了对应的buffer Handle,client/buffer/handle之间连接起来了!然后另一个一个进程就也可以使用mmap来操作这块heap buffer了。和一般的进程使用ION区别就是共享的进程之间struct ion_buffer是共享的,而struct ion_handle是各自的。
参考:
Rationalizing scatter/gather chains
Linux内存管理之mmap详解
- ION框架学习(二)
- ION框架学习(一)
- Android的ion相关学习(二)
- ion学习
- Android的ion相关学习(二)附件之<kzalloc 函数详解>
- Android的ion相关学习(一)
- Android联网框架Ion
- spring框架学习(二)
- 集合框架学习(二)
- laravel 框架学习(二)
- Retrofit框架学习(二)
- 学习TP框架(二)
- 学习vue框架(二)
- jhipster框架学习(二)
- Spring框架学习(二)
- ion
- ion
- ION
- LeetCode --Letter Combinations of a Phone Number
- 双链表求倒数第k项
- 匿名函数(拉姆达函数)
- 数字图像处理初学者学习路线
- 苏嵌shell总结
- ION框架学习(二)
- 常见类之Random类
- Flex 学习之二十 Form的使用
- 初学java javamail总结
- 香农熵和划分数据集
- Java之NIO
- java--day06面向对象
- 人类无法创造有意识的AI——新书《生命3.0》解读
- poj1041-John's trip