• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  ion.c
3  *
4  * Memory Allocator functions for ion
5  *
6  *   Copyright 2011 Google, Inc
7  *
8  *  Licensed under the Apache License, Version 2.0 (the "License");
9  *  you may not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS,
16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  */
20 #define LOG_TAG "ion"
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <linux/ion.h>
25 #include <stdatomic.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 
33 #include <ion/ion.h>
34 #include "ion_4.12.h"
35 
36 #include <log/log.h>
37 
38 enum ion_version { ION_VERSION_UNKNOWN, ION_VERSION_MODERN, ION_VERSION_LEGACY };
39 
40 static atomic_int g_ion_version = ATOMIC_VAR_INIT(ION_VERSION_UNKNOWN);
41 
ion_is_legacy(int fd)42 int ion_is_legacy(int fd) {
43     int version = atomic_load_explicit(&g_ion_version, memory_order_acquire);
44     if (version == ION_VERSION_UNKNOWN) {
45         /**
46           * Check for FREE IOCTL here; it is available only in the old
47           * kernels, not the new ones.
48           */
49         int err = ion_free(fd, (ion_user_handle_t)NULL);
50         version = (err == -ENOTTY) ? ION_VERSION_MODERN : ION_VERSION_LEGACY;
51         atomic_store_explicit(&g_ion_version, version, memory_order_release);
52     }
53     return version == ION_VERSION_LEGACY;
54 }
55 
ion_open()56 int ion_open() {
57     int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
58     if (fd < 0) ALOGE("open /dev/ion failed!\n");
59 
60     return fd;
61 }
62 
ion_close(int fd)63 int ion_close(int fd) {
64     int ret = close(fd);
65     if (ret < 0) return -errno;
66     return ret;
67 }
68 
ion_ioctl(int fd,int req,void * arg)69 static int ion_ioctl(int fd, int req, void* arg) {
70     int ret = ioctl(fd, req, arg);
71     if (ret < 0) {
72         ALOGE("ioctl %x failed with code %d: %s\n", req, ret, strerror(errno));
73         return -errno;
74     }
75     return ret;
76 }
77 
ion_alloc(int fd,size_t len,size_t align,unsigned int heap_mask,unsigned int flags,ion_user_handle_t * handle)78 int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags,
79               ion_user_handle_t* handle) {
80     int ret = 0;
81 
82     if ((handle == NULL) || (!ion_is_legacy(fd))) return -EINVAL;
83 
84     struct ion_allocation_data data = {
85         .len = len, .align = align, .heap_id_mask = heap_mask, .flags = flags,
86     };
87 
88     ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
89     if (ret < 0) return ret;
90 
91     *handle = data.handle;
92 
93     return ret;
94 }
95 
ion_free(int fd,ion_user_handle_t handle)96 int ion_free(int fd, ion_user_handle_t handle) {
97     struct ion_handle_data data = {
98         .handle = handle,
99     };
100     return ion_ioctl(fd, ION_IOC_FREE, &data);
101 }
102 
ion_map(int fd,ion_user_handle_t handle,size_t length,int prot,int flags,off_t offset,unsigned char ** ptr,int * map_fd)103 int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, int flags, off_t offset,
104             unsigned char** ptr, int* map_fd) {
105     if (!ion_is_legacy(fd)) return -EINVAL;
106     int ret;
107     unsigned char* tmp_ptr;
108     struct ion_fd_data data = {
109         .handle = handle,
110     };
111 
112     if (map_fd == NULL) return -EINVAL;
113     if (ptr == NULL) return -EINVAL;
114 
115     ret = ion_ioctl(fd, ION_IOC_MAP, &data);
116     if (ret < 0) return ret;
117     if (data.fd < 0) {
118         ALOGE("map ioctl returned negative fd\n");
119         return -EINVAL;
120     }
121     tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
122     if (tmp_ptr == MAP_FAILED) {
123         ALOGE("mmap failed: %s\n", strerror(errno));
124         return -errno;
125     }
126     *map_fd = data.fd;
127     *ptr = tmp_ptr;
128     return ret;
129 }
130 
ion_share(int fd,ion_user_handle_t handle,int * share_fd)131 int ion_share(int fd, ion_user_handle_t handle, int* share_fd) {
132     int ret;
133     struct ion_fd_data data = {
134         .handle = handle,
135     };
136 
137     if (!ion_is_legacy(fd)) return -EINVAL;
138     if (share_fd == NULL) return -EINVAL;
139 
140     ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
141     if (ret < 0) return ret;
142     if (data.fd < 0) {
143         ALOGE("share ioctl returned negative fd\n");
144         return -EINVAL;
145     }
146     *share_fd = data.fd;
147     return ret;
148 }
149 
ion_alloc_fd(int fd,size_t len,size_t align,unsigned int heap_mask,unsigned int flags,int * handle_fd)150 int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags,
151                  int* handle_fd) {
152     ion_user_handle_t handle;
153     int ret;
154 
155     if (!ion_is_legacy(fd)) {
156         struct ion_new_allocation_data data = {
157             .len = len,
158             .heap_id_mask = heap_mask,
159             .flags = flags,
160         };
161 
162         ret = ion_ioctl(fd, ION_IOC_NEW_ALLOC, &data);
163         if (ret < 0) return ret;
164         *handle_fd = data.fd;
165     } else {
166         ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
167         if (ret < 0) return ret;
168         ret = ion_share(fd, handle, handle_fd);
169         ion_free(fd, handle);
170     }
171     return ret;
172 }
173 
ion_import(int fd,int share_fd,ion_user_handle_t * handle)174 int ion_import(int fd, int share_fd, ion_user_handle_t* handle) {
175     int ret;
176     struct ion_fd_data data = {
177         .fd = share_fd,
178     };
179 
180     if (!ion_is_legacy(fd)) return -EINVAL;
181 
182     if (handle == NULL) return -EINVAL;
183 
184     ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
185     if (ret < 0) return ret;
186     *handle = data.handle;
187     return ret;
188 }
189 
ion_sync_fd(int fd,int handle_fd)190 int ion_sync_fd(int fd, int handle_fd) {
191     struct ion_fd_data data = {
192         .fd = handle_fd,
193     };
194 
195     if (!ion_is_legacy(fd)) return -EINVAL;
196 
197     return ion_ioctl(fd, ION_IOC_SYNC, &data);
198 }
199 
ion_query_heap_cnt(int fd,int * cnt)200 int ion_query_heap_cnt(int fd, int* cnt) {
201     int ret;
202     struct ion_heap_query query;
203 
204     memset(&query, 0, sizeof(query));
205 
206     ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query);
207     if (ret < 0) return ret;
208 
209     *cnt = query.cnt;
210     return ret;
211 }
212 
ion_query_get_heaps(int fd,int cnt,void * buffers)213 int ion_query_get_heaps(int fd, int cnt, void* buffers) {
214     int ret;
215     struct ion_heap_query query = {
216         .cnt = cnt, .heaps = (uintptr_t)buffers,
217     };
218 
219     ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query);
220     return ret;
221 }
222