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 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 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 63 int ion_close(int fd) { 64 int ret = close(fd); 65 if (ret < 0) return -errno; 66 return ret; 67 } 68 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 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 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 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 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 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 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 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 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 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