diff options
Diffstat (limited to 'libion')
-rw-r--r-- | libion/Android.mk | 5 | ||||
-rw-r--r-- | libion/include/ion/ion.h | 46 | ||||
-rw-r--r-- | libion/ion.c | 182 | ||||
-rw-r--r-- | libion/ion_test.c | 443 | ||||
-rw-r--r-- | libion/kernel-headers/linux/ion.h | 78 | ||||
-rw-r--r-- | libion/kernel-headers/linux/ion_test.h | 38 | ||||
-rw-r--r-- | libion/original-kernel-headers/linux/ion.h | 196 | ||||
-rw-r--r-- | libion/original-kernel-headers/linux/ion_test.h | 70 | ||||
-rw-r--r-- | libion/tests/Android.mk | 34 | ||||
-rw-r--r-- | libion/tests/allocate_test.cpp | 145 | ||||
-rw-r--r-- | libion/tests/device_test.cpp | 568 | ||||
-rw-r--r-- | libion/tests/exit_test.cpp | 227 | ||||
-rw-r--r-- | libion/tests/formerly_valid_handle_test.cpp | 63 | ||||
-rw-r--r-- | libion/tests/invalid_values_test.cpp | 186 | ||||
-rw-r--r-- | libion/tests/ion_test_fixture.cpp | 73 | ||||
-rw-r--r-- | libion/tests/ion_test_fixture.h | 46 | ||||
-rw-r--r-- | libion/tests/map_test.cpp | 162 |
17 files changed, 2264 insertions, 298 deletions
diff --git a/libion/Android.mk b/libion/Android.mk index 5121fee..e5d495b 100644 --- a/libion/Android.mk +++ b/libion/Android.mk @@ -5,11 +5,16 @@ LOCAL_SRC_FILES := ion.c LOCAL_MODULE := libion LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := liblog +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := ion.c ion_test.c LOCAL_MODULE := iontest LOCAL_MODULE_TAGS := optional tests +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_EXECUTABLE) + +include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/libion/include/ion/ion.h b/libion/include/ion/ion.h new file mode 100644 index 0000000..f47793d --- /dev/null +++ b/libion/include/ion/ion.h @@ -0,0 +1,46 @@ +/* + * ion.c + * + * Memory Allocator functions for ion + * + * Copyright 2011 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SYS_CORE_ION_H +#define __SYS_CORE_ION_H + +#include <sys/types.h> +#include <linux/ion.h> + +__BEGIN_DECLS + +struct ion_handle; + +int ion_open(); +int ion_close(int fd); +int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, ion_user_handle_t *handle); +int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, int *handle_fd); +int ion_sync_fd(int fd, int handle_fd); +int ion_free(int fd, ion_user_handle_t handle); +int 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); +int ion_share(int fd, ion_user_handle_t handle, int *share_fd); +int ion_import(int fd, int share_fd, ion_user_handle_t *handle); + +__END_DECLS + +#endif /* __SYS_CORE_ION_H */ diff --git a/libion/ion.c b/libion/ion.c index 020c35b..80bdc2a 100644 --- a/libion/ion.c +++ b/libion/ion.c @@ -32,119 +32,139 @@ int ion_open() { - int fd = open("/dev/ion", O_RDWR); - if (fd < 0) - ALOGE("open /dev/ion failed!\n"); - return fd; + int fd = open("/dev/ion", O_RDWR); + if (fd < 0) + ALOGE("open /dev/ion failed!\n"); + return fd; } int ion_close(int fd) { - return close(fd); + int ret = close(fd); + if (ret < 0) + return -errno; + return ret; } static int ion_ioctl(int fd, int req, void *arg) { - int ret = ioctl(fd, req, arg); - if (ret < 0) { - ALOGE("ioctl %x failed with code %d: %s\n", req, - ret, strerror(errno)); - return -errno; - } - return ret; + int ret = ioctl(fd, req, arg); + if (ret < 0) { + ALOGE("ioctl %x failed with code %d: %s\n", req, + ret, strerror(errno)); + return -errno; + } + return ret; } int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, - unsigned int flags, struct ion_handle **handle) + unsigned int flags, ion_user_handle_t *handle) { - int ret; - struct ion_allocation_data data = { - .len = len, - .align = align, - .heap_mask = heap_mask, - .flags = flags, - }; - - ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); - if (ret < 0) - return ret; - *handle = data.handle; + int ret; + struct ion_allocation_data data = { + .len = len, + .align = align, + .heap_id_mask = heap_mask, + .flags = flags, + }; + + if (handle == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); + if (ret < 0) return ret; + *handle = data.handle; + return ret; } -int ion_free(int fd, struct ion_handle *handle) +int ion_free(int fd, ion_user_handle_t handle) { - struct ion_handle_data data = { - .handle = handle, - }; - return ion_ioctl(fd, ION_IOC_FREE, &data); + struct ion_handle_data data = { + .handle = handle, + }; + return ion_ioctl(fd, ION_IOC_FREE, &data); } -int ion_map(int fd, struct ion_handle *handle, size_t length, int prot, +int 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) { - struct ion_fd_data data = { - .handle = handle, - }; - - int ret = ion_ioctl(fd, ION_IOC_MAP, &data); - if (ret < 0) - return ret; - *map_fd = data.fd; - if (*map_fd < 0) { - ALOGE("map ioctl returned negative fd\n"); - return -EINVAL; - } - *ptr = mmap(NULL, length, prot, flags, *map_fd, offset); - if (*ptr == MAP_FAILED) { - ALOGE("mmap failed: %s\n", strerror(errno)); - return -errno; - } + int ret; + struct ion_fd_data data = { + .handle = handle, + }; + + if (map_fd == NULL) + return -EINVAL; + if (ptr == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_MAP, &data); + if (ret < 0) return ret; + *map_fd = data.fd; + if (*map_fd < 0) { + ALOGE("map ioctl returned negative fd\n"); + return -EINVAL; + } + *ptr = mmap(NULL, length, prot, flags, *map_fd, offset); + if (*ptr == MAP_FAILED) { + ALOGE("mmap failed: %s\n", strerror(errno)); + return -errno; + } + return ret; } -int ion_share(int fd, struct ion_handle *handle, int *share_fd) +int ion_share(int fd, ion_user_handle_t handle, int *share_fd) { - int map_fd; - struct ion_fd_data data = { - .handle = handle, - }; - - int ret = ion_ioctl(fd, ION_IOC_SHARE, &data); - if (ret < 0) - return ret; - *share_fd = data.fd; - if (*share_fd < 0) { - ALOGE("share ioctl returned negative fd\n"); - return -EINVAL; - } + int map_fd; + int ret; + struct ion_fd_data data = { + .handle = handle, + }; + + if (share_fd == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_SHARE, &data); + if (ret < 0) return ret; + *share_fd = data.fd; + if (*share_fd < 0) { + ALOGE("share ioctl returned negative fd\n"); + return -EINVAL; + } + return ret; } int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, - unsigned int flags, int *handle_fd) { - struct ion_handle *handle; - int ret; - - ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); - if (ret < 0) - return ret; - ret = ion_share(fd, handle, handle_fd); - ion_free(fd, handle); - return ret; + unsigned int flags, int *handle_fd) { + ion_user_handle_t handle; + int ret; + + ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); + if (ret < 0) + return ret; + ret = ion_share(fd, handle, handle_fd); + ion_free(fd, handle); + return ret; } -int ion_import(int fd, int share_fd, struct ion_handle **handle) +int ion_import(int fd, int share_fd, ion_user_handle_t *handle) { - struct ion_fd_data data = { - .fd = share_fd, - }; - - int ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); - if (ret < 0) - return ret; - *handle = data.handle; + int ret; + struct ion_fd_data data = { + .fd = share_fd, + }; + + if (handle == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); + if (ret < 0) return ret; + *handle = data.handle; + return ret; } int ion_sync_fd(int fd, int handle_fd) diff --git a/libion/ion_test.c b/libion/ion_test.c index 0caaa2a..8872282 100644 --- a/libion/ion_test.c +++ b/libion/ion_test.c @@ -1,3 +1,19 @@ +/* + * Copyright 2013 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -13,7 +29,6 @@ #include <ion/ion.h> #include <linux/ion.h> -#include <linux/omap_ion.h> size_t len = 1024*1024, align = 0; int prot = PROT_READ | PROT_WRITE; @@ -23,256 +38,250 @@ int heap_mask = 1; int test = -1; size_t stride; -int _ion_alloc_test(int *fd, struct ion_handle **handle) +int _ion_alloc_test(int *fd, ion_user_handle_t *handle) { - int ret; + int ret; - *fd = ion_open(); - if (*fd < 0) - return *fd; + *fd = ion_open(); + if (*fd < 0) + return *fd; - ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle); + ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle); - if (ret) - printf("%s failed: %s\n", __func__, strerror(ret)); - return ret; + if (ret) + printf("%s failed: %s\n", __func__, strerror(ret)); + return ret; } void ion_alloc_test() { - int fd, ret; - struct ion_handle *handle; + int fd, ret; + ion_user_handle_t handle; - if(_ion_alloc_test(&fd, &handle)) - return; + if(_ion_alloc_test(&fd, &handle)) + return; - ret = ion_free(fd, handle); - if (ret) { - printf("%s failed: %s %p\n", __func__, strerror(ret), handle); - return; - } - ion_close(fd); - printf("ion alloc test: passed\n"); + ret = ion_free(fd, handle); + if (ret) { + printf("%s failed: %s %d\n", __func__, strerror(ret), handle); + return; + } + ion_close(fd); + printf("ion alloc test: passed\n"); } void ion_map_test() { - int fd, map_fd, ret; - size_t i; - struct ion_handle *handle; - unsigned char *ptr; + int fd, map_fd, ret; + size_t i; + ion_user_handle_t handle; + unsigned char *ptr; - if(_ion_alloc_test(&fd, &handle)) - return; + if(_ion_alloc_test(&fd, &handle)) + return; - ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd); - if (ret) - return; + ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd); + if (ret) + return; - for (i = 0; i < len; i++) { - ptr[i] = (unsigned char)i; - } - for (i = 0; i < len; i++) - if (ptr[i] != (unsigned char)i) - printf("%s failed wrote %d read %d from mapped " - "memory\n", __func__, i, ptr[i]); - /* clean up properly */ - ret = ion_free(fd, handle); - ion_close(fd); - munmap(ptr, len); - close(map_fd); + for (i = 0; i < len; i++) { + ptr[i] = (unsigned char)i; + } + for (i = 0; i < len; i++) + if (ptr[i] != (unsigned char)i) + printf("%s failed wrote %zu read %d from mapped " + "memory\n", __func__, i, ptr[i]); + /* clean up properly */ + ret = ion_free(fd, handle); + ion_close(fd); + munmap(ptr, len); + close(map_fd); - _ion_alloc_test(&fd, &handle); - close(fd); + _ion_alloc_test(&fd, &handle); + close(fd); #if 0 - munmap(ptr, len); - close(map_fd); - ion_close(fd); + munmap(ptr, len); + close(map_fd); + ion_close(fd); - _ion_alloc_test(len, align, flags, &fd, &handle); - close(map_fd); - ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd); - /* don't clean up */ + _ion_alloc_test(len, align, flags, &fd, &handle); + close(map_fd); + ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd); + /* don't clean up */ #endif } void ion_share_test() { - struct ion_handle *handle; - int sd[2]; - int num_fd = 1; - struct iovec count_vec = { - .iov_base = &num_fd, - .iov_len = sizeof num_fd, - }; - char buf[CMSG_SPACE(sizeof(int))]; - socketpair(AF_UNIX, SOCK_STREAM, 0, sd); - if (fork()) { - struct msghdr msg = { - .msg_control = buf, - .msg_controllen = sizeof buf, - .msg_iov = &count_vec, - .msg_iovlen = 1, - }; + ion_user_handle_t handle; + int sd[2]; + int num_fd = 1; + struct iovec count_vec = { + .iov_base = &num_fd, + .iov_len = sizeof num_fd, + }; + char buf[CMSG_SPACE(sizeof(int))]; + socketpair(AF_UNIX, SOCK_STREAM, 0, sd); + if (fork()) { + struct msghdr msg = { + .msg_control = buf, + .msg_controllen = sizeof buf, + .msg_iov = &count_vec, + .msg_iovlen = 1, + }; - struct cmsghdr *cmsg; - int fd, share_fd, ret; - char *ptr; - /* parent */ - if(_ion_alloc_test(&fd, &handle)) - return; - ret = ion_share(fd, handle, &share_fd); - if (ret) - printf("share failed %s\n", strerror(errno)); - ptr = mmap(NULL, len, prot, map_flags, share_fd, 0); - if (ptr == MAP_FAILED) { - return; - } - strcpy(ptr, "master"); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - *(int *)CMSG_DATA(cmsg) = share_fd; - /* send the fd */ - printf("master? [%10s] should be [master]\n", ptr); - printf("master sending msg 1\n"); - sendmsg(sd[0], &msg, 0); - if (recvmsg(sd[0], &msg, 0) < 0) - perror("master recv msg 2"); - printf("master? [%10s] should be [child]\n", ptr); + struct cmsghdr *cmsg; + int fd, share_fd, ret; + char *ptr; + /* parent */ + if(_ion_alloc_test(&fd, &handle)) + return; + ret = ion_share(fd, handle, &share_fd); + if (ret) + printf("share failed %s\n", strerror(errno)); + ptr = mmap(NULL, len, prot, map_flags, share_fd, 0); + if (ptr == MAP_FAILED) { + return; + } + strcpy(ptr, "master"); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *(int *)CMSG_DATA(cmsg) = share_fd; + /* send the fd */ + printf("master? [%10s] should be [master]\n", ptr); + printf("master sending msg 1\n"); + sendmsg(sd[0], &msg, 0); + if (recvmsg(sd[0], &msg, 0) < 0) + perror("master recv msg 2"); + printf("master? [%10s] should be [child]\n", ptr); - /* send ping */ - sendmsg(sd[0], &msg, 0); - printf("master->master? [%10s]\n", ptr); - if (recvmsg(sd[0], &msg, 0) < 0) - perror("master recv 1"); - } else { - struct msghdr msg; - struct cmsghdr *cmsg; - char* ptr; - int fd, recv_fd; - char* child_buf[100]; - /* child */ - struct iovec count_vec = { - .iov_base = child_buf, - .iov_len = sizeof child_buf, - }; + /* send ping */ + sendmsg(sd[0], &msg, 0); + printf("master->master? [%10s]\n", ptr); + if (recvmsg(sd[0], &msg, 0) < 0) + perror("master recv 1"); + } else { + struct msghdr msg; + struct cmsghdr *cmsg; + char* ptr; + int fd, recv_fd; + char* child_buf[100]; + /* child */ + struct iovec count_vec = { + .iov_base = child_buf, + .iov_len = sizeof child_buf, + }; - struct msghdr child_msg = { - .msg_control = buf, - .msg_controllen = sizeof buf, - .msg_iov = &count_vec, - .msg_iovlen = 1, - }; + struct msghdr child_msg = { + .msg_control = buf, + .msg_controllen = sizeof buf, + .msg_iov = &count_vec, + .msg_iovlen = 1, + }; - if (recvmsg(sd[1], &child_msg, 0) < 0) - perror("child recv msg 1"); - cmsg = CMSG_FIRSTHDR(&child_msg); - if (cmsg == NULL) { - printf("no cmsg rcvd in child"); - return; - } - recv_fd = *(int*)CMSG_DATA(cmsg); - if (recv_fd < 0) { - printf("could not get recv_fd from socket"); - return; - } - printf("child %d\n", recv_fd); - fd = ion_open(); - ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0); - if (ptr == MAP_FAILED) { - return; - } - printf("child? [%10s] should be [master]\n", ptr); - strcpy(ptr, "child"); - printf("child sending msg 2\n"); - sendmsg(sd[1], &child_msg, 0); - } + if (recvmsg(sd[1], &child_msg, 0) < 0) + perror("child recv msg 1"); + cmsg = CMSG_FIRSTHDR(&child_msg); + if (cmsg == NULL) { + printf("no cmsg rcvd in child"); + return; + } + recv_fd = *(int*)CMSG_DATA(cmsg); + if (recv_fd < 0) { + printf("could not get recv_fd from socket"); + return; + } + printf("child %d\n", recv_fd); + fd = ion_open(); + ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0); + if (ptr == MAP_FAILED) { + return; + } + printf("child? [%10s] should be [master]\n", ptr); + strcpy(ptr, "child"); + printf("child sending msg 2\n"); + sendmsg(sd[1], &child_msg, 0); + } } int main(int argc, char* argv[]) { - int c; - enum tests { - ALLOC_TEST = 0, MAP_TEST, SHARE_TEST, - }; + int c; + enum tests { + ALLOC_TEST = 0, MAP_TEST, SHARE_TEST, + }; - while (1) { - static struct option opts[] = { - {"alloc", no_argument, 0, 'a'}, - {"alloc_flags", required_argument, 0, 'f'}, - {"heap_mask", required_argument, 0, 'h'}, - {"map", no_argument, 0, 'm'}, - {"share", no_argument, 0, 's'}, - {"len", required_argument, 0, 'l'}, - {"align", required_argument, 0, 'g'}, - {"map_flags", required_argument, 0, 'z'}, - {"prot", required_argument, 0, 'p'}, - }; - int i = 0; - c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i); - if (c == -1) - break; + while (1) { + static struct option opts[] = { + {"alloc", no_argument, 0, 'a'}, + {"alloc_flags", required_argument, 0, 'f'}, + {"heap_mask", required_argument, 0, 'h'}, + {"map", no_argument, 0, 'm'}, + {"share", no_argument, 0, 's'}, + {"len", required_argument, 0, 'l'}, + {"align", required_argument, 0, 'g'}, + {"map_flags", required_argument, 0, 'z'}, + {"prot", required_argument, 0, 'p'}, + }; + int i = 0; + c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i); + if (c == -1) + break; - switch (c) { - case 'l': - len = atol(optarg); - break; - case 'g': - align = atol(optarg); - break; - case 'z': - map_flags = 0; - map_flags |= strstr(optarg, "PROT_EXEC") ? - PROT_EXEC : 0; - map_flags |= strstr(optarg, "PROT_READ") ? - PROT_READ: 0; - map_flags |= strstr(optarg, "PROT_WRITE") ? - PROT_WRITE: 0; - map_flags |= strstr(optarg, "PROT_NONE") ? - PROT_NONE: 0; - break; - case 'p': - prot = 0; - prot |= strstr(optarg, "MAP_PRIVATE") ? - MAP_PRIVATE : 0; - prot |= strstr(optarg, "MAP_SHARED") ? - MAP_PRIVATE : 0; - break; - case 'f': - alloc_flags = atol(optarg); - break; - case 'h': - heap_mask = atol(optarg); - break; - case 'a': - test = ALLOC_TEST; - break; - case 'm': - test = MAP_TEST; - break; - case 's': - test = SHARE_TEST; - break; - } - } - printf("test %d, len %u, align %u, map_flags %d, prot %d, heap_mask %d," - " alloc_flags %d\n", test, len, align, map_flags, prot, - heap_mask, alloc_flags); - switch (test) { - case ALLOC_TEST: - ion_alloc_test(); - break; - case MAP_TEST: - ion_map_test(); - break; - case SHARE_TEST: - ion_share_test(); - break; - default: - printf("must specify a test (alloc, map, share)\n"); - } - return 0; + switch (c) { + case 'l': + len = atol(optarg); + break; + case 'g': + align = atol(optarg); + break; + case 'z': + map_flags = 0; + map_flags |= strstr(optarg, "PROT_EXEC") ? PROT_EXEC : 0; + map_flags |= strstr(optarg, "PROT_READ") ? PROT_READ: 0; + map_flags |= strstr(optarg, "PROT_WRITE") ? PROT_WRITE: 0; + map_flags |= strstr(optarg, "PROT_NONE") ? PROT_NONE: 0; + break; + case 'p': + prot = 0; + prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0; + prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0; + break; + case 'f': + alloc_flags = atol(optarg); + break; + case 'h': + heap_mask = atol(optarg); + break; + case 'a': + test = ALLOC_TEST; + break; + case 'm': + test = MAP_TEST; + break; + case 's': + test = SHARE_TEST; + break; + } + } + printf("test %d, len %zu, align %zu, map_flags %d, prot %d, heap_mask %d," + " alloc_flags %d\n", test, len, align, map_flags, prot, + heap_mask, alloc_flags); + switch (test) { + case ALLOC_TEST: + ion_alloc_test(); + break; + case MAP_TEST: + ion_map_test(); + break; + case SHARE_TEST: + ion_share_test(); + break; + default: + printf("must specify a test (alloc, map, share)\n"); + } + return 0; } diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h new file mode 100644 index 0000000..5af39d0 --- /dev/null +++ b/libion/kernel-headers/linux/ion.h @@ -0,0 +1,78 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _UAPI_LINUX_ION_H +#define _UAPI_LINUX_ION_H +#include <linux/ioctl.h> +#include <linux/types.h> +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +typedef int ion_user_handle_t; +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_DMA, + ION_HEAP_TYPE_CUSTOM, +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + ION_NUM_HEAPS = 16, +}; +#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) +#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) +#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 +#define ION_FLAG_CACHED 1 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_FLAG_CACHED_NEEDS_SYNC 2 +struct ion_allocation_data { + size_t len; + size_t align; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + unsigned int heap_id_mask; + unsigned int flags; + ion_user_handle_t handle; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct ion_handle_data { + ion_user_handle_t handle; +}; +struct ion_custom_data { +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + unsigned int cmd; + unsigned long arg; +}; +#define ION_IOC_MAGIC 'I' +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data) +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) +#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) +#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ diff --git a/libion/kernel-headers/linux/ion_test.h b/libion/kernel-headers/linux/ion_test.h new file mode 100644 index 0000000..6f3e2a7 --- /dev/null +++ b/libion/kernel-headers/linux/ion_test.h @@ -0,0 +1,38 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _UAPI_LINUX_ION_TEST_H +#define _UAPI_LINUX_ION_TEST_H +#include <linux/ioctl.h> +#include <linux/types.h> +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct ion_test_rw_data { + __u64 ptr; + __u64 offset; + __u64 size; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + int write; + int __padding; +}; +#define ION_IOC_MAGIC 'I' +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_TEST_SET_FD _IO(ION_IOC_MAGIC, 0xf0) +#define ION_IOC_TEST_DMA_MAPPING _IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data) +#define ION_IOC_TEST_KERNEL_MAPPING _IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data) +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ diff --git a/libion/original-kernel-headers/linux/ion.h b/libion/original-kernel-headers/linux/ion.h new file mode 100644 index 0000000..f09e7c1 --- /dev/null +++ b/libion/original-kernel-headers/linux/ion.h @@ -0,0 +1,196 @@ +/* + * drivers/staging/android/uapi/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_ION_H +#define _UAPI_LINUX_ION_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +typedef int ion_user_handle_t; + +/** + * enum ion_heap_types - list of all possible types of heaps + * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc + * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc + * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved + * carveout heap, allocations are physically + * contiguous + * @ION_HEAP_TYPE_DMA: memory allocated via DMA API + * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask + * is used to identify the heaps, so only 32 + * total heap types are supported + */ +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_DMA, + ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always + are at the end of this enum */ + ION_NUM_HEAPS = 16, +}; + +#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) +#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) +#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) + +#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 + +/** + * allocation flags - the lower 16 bits are used by core ion, the upper 16 + * bits are reserved for use by the heaps themselves. + */ +#define ION_FLAG_CACHED 1 /* mappings of this buffer should be + cached, ion will do cache + maintenance when the buffer is + mapped for dma */ +#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created + at mmap time, if this is set + caches must be managed manually */ + +/** + * DOC: Ion Userspace API + * + * create a client by opening /dev/ion + * most operations handled via following ioctls + * + */ + +/** + * struct ion_allocation_data - metadata passed from userspace for allocations + * @len: size of the allocation + * @align: required alignment of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct ion_allocation_data { + size_t len; + size_t align; + unsigned int heap_id_mask; + unsigned int flags; + ion_user_handle_t handle; +}; + +/** + * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair + * @handle: a handle + * @fd: a file descriptor representing that handle + * + * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the file + * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace + * provides the file descriptor and the kernel returns the handle. + */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; + +/** + * struct ion_handle_data - a handle passed to/from the kernel + * @handle: a handle + */ +struct ion_handle_data { + ion_user_handle_t handle; +}; + +/** + * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl + * @cmd: the custom ioctl function to call + * @arg: additional data to pass to the custom ioctl, typically a user + * pointer to a predefined structure + * + * This works just like the regular cmd and arg fields of an ioctl. + */ +struct ion_custom_data { + unsigned int cmd; + unsigned long arg; +}; + +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_ALLOC - allocate memory + * + * Takes an ion_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data) + +/** + * DOC: ION_IOC_FREE - free memory + * + * Takes an ion_handle_data struct and frees the handle. + */ +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) + +/** + * DOC: ION_IOC_MAP - get a file descriptor to mmap + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be used as an argument to mmap. + */ +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) + +/** + * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be passed to another process. The corresponding opaque handle can + * be retrieved via ION_IOC_IMPORT. + */ +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) + +/** + * DOC: ION_IOC_IMPORT - imports a shared file descriptor + * + * Takes an ion_fd_data struct with the fd field populated with a valid file + * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle + * filed set to the corresponding opaque handle. + */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) + +/** + * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory + * + * Deprecated in favor of using the dma_buf api's correctly (syncing + * will happend automatically when the buffer is mapped to a device). + * If necessary should be used after touching a cached buffer from the cpu, + * this will make the buffer in memory coherent. + */ +#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) + +/** + * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl + * + * Takes the argument of the architecture specific ioctl to call and + * passes appropriate userdata for that ioctl + */ +#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) + +#endif /* _UAPI_LINUX_ION_H */ diff --git a/libion/original-kernel-headers/linux/ion_test.h b/libion/original-kernel-headers/linux/ion_test.h new file mode 100644 index 0000000..ffef06f --- /dev/null +++ b/libion/original-kernel-headers/linux/ion_test.h @@ -0,0 +1,70 @@ +/* + * drivers/staging/android/uapi/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_ION_TEST_H +#define _UAPI_LINUX_ION_TEST_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +/** + * struct ion_test_rw_data - metadata passed to the kernel to read handle + * @ptr: a pointer to an area at least as large as size + * @offset: offset into the ion buffer to start reading + * @size: size to read or write + * @write: 1 to write, 0 to read + */ +struct ion_test_rw_data { + __u64 ptr; + __u64 offset; + __u64 size; + int write; + int __padding; +}; + +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_TEST_SET_DMA_BUF - attach a dma buf to the test driver + * + * Attaches a dma buf fd to the test driver. Passing a second fd or -1 will + * release the first fd. + */ +#define ION_IOC_TEST_SET_FD \ + _IO(ION_IOC_MAGIC, 0xf0) + +/** + * DOC: ION_IOC_TEST_DMA_MAPPING - read or write memory from a handle as DMA + * + * Reads or writes the memory from a handle using an uncached mapping. Can be + * used by unit tests to emulate a DMA engine as close as possible. Only + * expected to be used for debugging and testing, may not always be available. + */ +#define ION_IOC_TEST_DMA_MAPPING \ + _IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data) + +/** + * DOC: ION_IOC_TEST_KERNEL_MAPPING - read or write memory from a handle + * + * Reads or writes the memory from a handle using a kernel mapping. Can be + * used by unit tests to test heap map_kernel functions. Only expected to be + * used for debugging and testing, may not always be available. + */ +#define ION_IOC_TEST_KERNEL_MAPPING \ + _IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data) + + +#endif /* _UAPI_LINUX_ION_H */ diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk new file mode 100644 index 0000000..8dc7f9d --- /dev/null +++ b/libion/tests/Android.mk @@ -0,0 +1,34 @@ +# +# Copyright (C) 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := ion-unit-tests +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers +LOCAL_SHARED_LIBRARIES += libion +LOCAL_STATIC_LIBRARIES += libgtest_main +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers +LOCAL_SRC_FILES := \ + ion_test_fixture.cpp \ + allocate_test.cpp \ + formerly_valid_handle_test.cpp \ + invalid_values_test.cpp \ + map_test.cpp \ + device_test.cpp \ + exit_test.cpp +include $(BUILD_NATIVE_TEST) diff --git a/libion/tests/allocate_test.cpp b/libion/tests/allocate_test.cpp new file mode 100644 index 0000000..e26b302 --- /dev/null +++ b/libion/tests/allocate_test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/mman.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> +#include "ion_test_fixture.h" + +class Allocate : public IonAllHeapsTest { +}; + +TEST_F(Allocate, Allocate) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ion_user_handle_t handle = 0; + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle)); + ASSERT_TRUE(handle != 0); + ASSERT_EQ(0, ion_free(m_ionFd, handle)); + } + } +} + +TEST_F(Allocate, AllocateCached) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ion_user_handle_t handle = 0; + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &handle)); + ASSERT_TRUE(handle != 0); + ASSERT_EQ(0, ion_free(m_ionFd, handle)); + } + } +} + +TEST_F(Allocate, AllocateCachedNeedsSync) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ion_user_handle_t handle = 0; + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED_NEEDS_SYNC, &handle)); + ASSERT_TRUE(handle != 0); + ASSERT_EQ(0, ion_free(m_ionFd, handle)); + } + } +} + +TEST_F(Allocate, RepeatedAllocate) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ion_user_handle_t handle = 0; + + for (unsigned int i = 0; i < 1024; i++) { + SCOPED_TRACE(::testing::Message() << "iteration " << i); + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle)); + ASSERT_TRUE(handle != 0); + ASSERT_EQ(0, ion_free(m_ionFd, handle)); + } + } + } +} + +TEST_F(Allocate, Zeroed) +{ + void *zeroes = calloc(4096, 1); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int fds[16]; + for (unsigned int i = 0; i < 16; i++) { + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr = NULL; + ptr = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + memset(ptr, 0xaa, 4096); + + ASSERT_EQ(0, munmap(ptr, 4096)); + fds[i] = map_fd; + } + + for (unsigned int i = 0; i < 16; i++) { + ASSERT_EQ(0, close(fds[i])); + } + + int newIonFd = ion_open(); + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(newIonFd, 4096, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr = NULL; + ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, memcmp(ptr, zeroes, 4096)); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(zeroes); + +} + +TEST_F(Allocate, Large) +{ + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + ion_user_handle_t handle = 0; + ASSERT_EQ(-ENOMEM, ion_alloc(m_ionFd, 3UL*1024*1024*1024, 0, heapMask, 0, &handle)); + } +} diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp new file mode 100644 index 0000000..6f6e1bd --- /dev/null +++ b/libion/tests/device_test.cpp @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <linux/ion_test.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +#define ALIGN(x,y) (((x) + ((y) - 1)) & ~((y) - 1)) + +class Device : public IonAllHeapsTest { + public: + virtual void SetUp(); + virtual void TearDown(); + int m_deviceFd; + void readDMA(int fd, void *buf, size_t size); + void writeDMA(int fd, void *buf, size_t size); + void readKernel(int fd, void *buf, size_t size); + void writeKernel(int fd, void *buf, size_t size); + void blowCache(); + void dirtyCache(void *ptr, size_t size); +}; + +void Device::SetUp() +{ + IonAllHeapsTest::SetUp(); + m_deviceFd = open("/dev/ion-test", O_RDWR); + ASSERT_GE(m_deviceFd, 0); +} + +void Device::TearDown() +{ + ASSERT_EQ(0, close(m_deviceFd)); + IonAllHeapsTest::TearDown(); +} + +void Device::readDMA(int fd, void *buf, size_t size) +{ + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd)); + struct ion_test_rw_data ion_test_rw_data = { + .ptr = (uint64_t)buf, + .offset = 0, + .size = size, + .write = 0, + }; + + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data)); + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1)); +} + +void Device::writeDMA(int fd, void *buf, size_t size) +{ + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd)); + struct ion_test_rw_data ion_test_rw_data = { + .ptr = (uint64_t)buf, + .offset = 0, + .size = size, + .write = 1, + }; + + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data)); + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1)); +} + +void Device::readKernel(int fd, void *buf, size_t size) +{ + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd)); + struct ion_test_rw_data ion_test_rw_data = { + .ptr = (uint64_t)buf, + .offset = 0, + .size = size, + .write = 0, + }; + + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data)); + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1)); +} + +void Device::writeKernel(int fd, void *buf, size_t size) +{ + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd)); + struct ion_test_rw_data ion_test_rw_data = { + .ptr = (uint64_t)buf, + .offset = 0, + .size = size, + .write = 1, + }; + + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data)); + ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1)); +} + +void Device::blowCache() +{ + const size_t bigger_than_cache = 8*1024*1024; + void *buf1 = malloc(bigger_than_cache); + void *buf2 = malloc(bigger_than_cache); + memset(buf1, 0xaa, bigger_than_cache); + memcpy(buf2, buf1, bigger_than_cache); + free(buf1); + free(buf2); +} + +void Device::dirtyCache(void *ptr, size_t size) +{ + /* try to dirty cache lines */ + for (size_t i = size-1; i > 0; i--) { + ((volatile char *)ptr)[i]; + ((char *)ptr)[i] = i; + } +} + +TEST_F(Device, KernelReadCached) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + ((char*)buf)[4096] = 0x12; + readKernel(map_fd, buf, 4096); + ASSERT_EQ(((char*)buf)[4096], 0x12); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, KernelWriteCached) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeKernel(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMAReadCached) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + readDMA(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMAWriteCached) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeDMA(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, KernelReadCachedNeedsSync) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + ((char*)buf)[4096] = 0x12; + readKernel(map_fd, buf, 4096); + ASSERT_EQ(((char*)buf)[4096], 0x12); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, KernelWriteCachedNeedsSync) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeKernel(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMAReadCachedNeedsSync) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + ion_sync_fd(m_ionFd, map_fd); + + readDMA(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMAWriteCachedNeedsSync) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeDMA(map_fd, buf, 4096); + + ion_sync_fd(m_ionFd, map_fd); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} +TEST_F(Device, KernelRead) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = 0; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + ((char*)buf)[4096] = 0x12; + readKernel(map_fd, buf, 4096); + ASSERT_EQ(((char*)buf)[4096], 0x12); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, KernelWrite) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = 0; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeKernel(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMARead) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = 0; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + for (int i = 0; i < 4096; i++) + ((char *)ptr)[i] = i; + + readDMA(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)buf)[i]); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, DMAWrite) +{ + void *alloc = malloc(8192 + 1024); + void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024); + + for (int i = 0; i < 4096; i++) + ((char *)buf)[i] = i; + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = 0; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + writeDMA(map_fd, buf, 4096); + + for (int i = 0; i < 4096; i++) + ASSERT_EQ((char)i, ((char *)ptr)[i]) << i; + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } + + free(alloc); +} + +TEST_F(Device, IsCached) +{ + void *buf = malloc(4096); + + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + dirtyCache(ptr, 4096); + + readDMA(map_fd, buf, 4096); + + bool same = true; + for (int i = 4096-16; i >= 0; i -= 16) + if (((char *)buf)[i] != i) + same = false; + ASSERT_FALSE(same); + + ASSERT_EQ(0, munmap(ptr, 4096)); + ASSERT_EQ(0, close(map_fd)); + } +} diff --git a/libion/tests/exit_test.cpp b/libion/tests/exit_test.cpp new file mode 100644 index 0000000..cdd3e27 --- /dev/null +++ b/libion/tests/exit_test.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/mman.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +class Exit : public IonAllHeapsTest { +}; + +TEST_F(Exit, WithAlloc) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + ion_user_handle_t handle = 0; + + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle)); + ASSERT_TRUE(handle != 0); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } +} + +TEST_F(Exit, WithAllocFd) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int handle_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd)); + ASSERT_NE(-1, handle_fd); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } +} + +TEST_F(Exit, WithRepeatedAllocFd) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + for (unsigned int i = 0; i < 1024; i++) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ASSERT_EXIT({ + int handle_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd)); + ASSERT_NE(-1, handle_fd); + exit(0); + }, ::testing::ExitedWithCode(0), "") + << "failed on heap " << heapMask + << " and size " << size + << " on iteration " << i; + } + } + } +} + + +TEST_F(Exit, WithMapping) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } + +} + +TEST_F(Exit, WithPartialMapping) +{ + static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, munmap(ptr, size / 2)); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } +} + +TEST_F(Exit, WithMappingCached) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } + +} + +TEST_F(Exit, WithPartialMappingCached) +{ + static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, munmap(ptr, size / 2)); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } +} + +TEST_F(Exit, WithMappingNeedsSync) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } + +} + +TEST_F(Exit, WithPartialMappingNeedsSync) +{ + static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + EXPECT_EXIT({ + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, munmap(ptr, size / 2)); + exit(0); + }, ::testing::ExitedWithCode(0), ""); + } + } +} diff --git a/libion/tests/formerly_valid_handle_test.cpp b/libion/tests/formerly_valid_handle_test.cpp new file mode 100644 index 0000000..01ab8f3 --- /dev/null +++ b/libion/tests/formerly_valid_handle_test.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/mman.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +class FormerlyValidHandle : public IonTest { + public: + virtual void SetUp(); + virtual void TearDown(); + ion_user_handle_t m_handle; +}; + +void FormerlyValidHandle::SetUp() +{ + IonTest::SetUp(); + ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, 1/* ion_env->m_firstHeap */, 0, &m_handle)); + ASSERT_TRUE(m_handle != 0); + ASSERT_EQ(0, ion_free(m_ionFd, m_handle)); +} + +void FormerlyValidHandle::TearDown() +{ + m_handle = 0; +} + +TEST_F(FormerlyValidHandle, free) +{ + ASSERT_EQ(-EINVAL, ion_free(m_ionFd, m_handle)); +} + +TEST_F(FormerlyValidHandle, map) +{ + int map_fd; + unsigned char *ptr; + + ASSERT_EQ(-EINVAL, ion_map(m_ionFd, m_handle, 4096, PROT_READ, 0, 0, &ptr, &map_fd)); +} + +TEST_F(FormerlyValidHandle, share) +{ + int share_fd; + + ASSERT_EQ(-EINVAL, ion_share(m_ionFd, m_handle, &share_fd)); +} diff --git a/libion/tests/invalid_values_test.cpp b/libion/tests/invalid_values_test.cpp new file mode 100644 index 0000000..77fea17 --- /dev/null +++ b/libion/tests/invalid_values_test.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/mman.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +class InvalidValues : public IonAllHeapsTest { + public: + virtual void SetUp(); + virtual void TearDown(); + ion_user_handle_t m_validHandle; + int m_validShareFd; + ion_user_handle_t const m_badHandle = -1; +}; + +void InvalidValues::SetUp() +{ + IonAllHeapsTest::SetUp(); + ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, m_firstHeap, 0, &m_validHandle)) + << m_ionFd << " " << m_firstHeap; + ASSERT_TRUE(m_validHandle != 0); + ASSERT_EQ(0, ion_share(m_ionFd, m_validHandle, &m_validShareFd)); +} + +void InvalidValues::TearDown() +{ + ASSERT_EQ(0, ion_free(m_ionFd, m_validHandle)); + ASSERT_EQ(0, close(m_validShareFd)); + m_validHandle = 0; + IonAllHeapsTest::TearDown(); +} + +TEST_F(InvalidValues, ion_close) +{ + EXPECT_EQ(-EBADF, ion_close(-1)); +} + +TEST_F(InvalidValues, ion_alloc) +{ + ion_user_handle_t handle; + /* invalid ion_fd */ + int ret = ion_alloc(0, 4096, 0, m_firstHeap, 0, &handle); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion_fd */ + EXPECT_EQ(-EBADF, ion_alloc(-1, 4096, 0, m_firstHeap, 0, &handle)); + /* no heaps */ + EXPECT_EQ(-ENODEV, ion_alloc(m_ionFd, 4096, 0, 0, 0, &handle)); + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + /* zero size */ + EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 0, 0, heapMask, 0, &handle)); + /* too large size */ + EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, -1, 0, heapMask, 0, &handle)); + /* bad alignment */ + EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, -1, heapMask, 0, &handle)); + /* NULL handle */ + EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, 0, heapMask, 0, NULL)); + } +} + +TEST_F(InvalidValues, ion_alloc_fd) +{ + int fd; + /* invalid ion_fd */ + int ret = ion_alloc_fd(0, 4096, 0, m_firstHeap, 0, &fd); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion_fd */ + EXPECT_EQ(-EBADF, ion_alloc_fd(-1, 4096, 0, m_firstHeap, 0, &fd)); + /* no heaps */ + EXPECT_EQ(-ENODEV, ion_alloc_fd(m_ionFd, 4096, 0, 0, 0, &fd)); + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + /* zero size */ + EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 0, 0, heapMask, 0, &fd)); + /* too large size */ + EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, -1, 0, heapMask, 0, &fd)); + /* bad alignment */ + EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, -1, heapMask, 0, &fd)); + /* NULL handle */ + EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, NULL)); + } +} + +TEST_F(InvalidValues, ion_free) +{ + /* invalid ion fd */ + int ret = ion_free(0, m_validHandle); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion fd */ + EXPECT_EQ(-EBADF, ion_free(-1, m_validHandle)); + /* zero handle */ + EXPECT_EQ(-EINVAL, ion_free(m_ionFd, 0)); + /* bad handle */ + EXPECT_EQ(-EINVAL, ion_free(m_ionFd, m_badHandle)); +} + +TEST_F(InvalidValues, ion_map) +{ + int map_fd; + unsigned char *ptr; + + /* invalid ion fd */ + int ret = ion_map(0, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion fd */ + EXPECT_EQ(-EBADF, ion_map(-1, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd)); + /* zero handle */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, 0, 4096, PROT_READ, 0, 0, &ptr, &map_fd)); + /* bad handle */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_badHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd)); + /* zero length */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 0, PROT_READ, 0, 0, &ptr, &map_fd)); + /* bad prot */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, -1, 0, 0, &ptr, &map_fd)); + /* bad offset */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, -1, &ptr, &map_fd)); + /* NULL ptr */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, NULL, &map_fd)); + /* NULL map_fd */ + EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, NULL)); +} + +TEST_F(InvalidValues, ion_share) +{ + int share_fd; + + /* invalid ion fd */ + int ret = ion_share(0, m_validHandle, &share_fd); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion fd */ + EXPECT_EQ(-EBADF, ion_share(-1, m_validHandle, &share_fd)); + /* zero handle */ + EXPECT_EQ(-EINVAL, ion_share(m_ionFd, 0, &share_fd)); + /* bad handle */ + EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_badHandle, &share_fd)); + /* NULL share_fd */ + EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_validHandle, NULL)); +} + +TEST_F(InvalidValues, ion_import) +{ + ion_user_handle_t handle; + + /* invalid ion fd */ + int ret = ion_import(0, m_validShareFd, &handle); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion fd */ + EXPECT_EQ(-EBADF, ion_import(-1, m_validShareFd, &handle)); + /* bad share_fd */ + EXPECT_EQ(-EINVAL, ion_import(m_ionFd, 0, &handle)); + /* invalid share_fd */ + EXPECT_EQ(-EBADF, ion_import(m_ionFd, -1, &handle)); + /* NULL handle */ + EXPECT_EQ(-EINVAL, ion_import(m_ionFd, m_validShareFd, NULL)); +} + +TEST_F(InvalidValues, ion_sync_fd) +{ + /* invalid ion fd */ + int ret = ion_sync_fd(0, m_validShareFd); + EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY); + /* invalid ion fd */ + EXPECT_EQ(-EBADF, ion_sync_fd(-1, m_validShareFd)); + /* bad share_fd */ + EXPECT_EQ(-EINVAL, ion_sync_fd(m_ionFd, 0)); + /* invalid share_fd */ + EXPECT_EQ(-EBADF, ion_sync_fd(m_ionFd, -1)); +} diff --git a/libion/tests/ion_test_fixture.cpp b/libion/tests/ion_test_fixture.cpp new file mode 100644 index 0000000..e20c730 --- /dev/null +++ b/libion/tests/ion_test_fixture.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +IonTest::IonTest() : m_ionFd(-1) +{ +} + +void IonTest::SetUp() { + m_ionFd = ion_open(); + ASSERT_GE(m_ionFd, 0); +} + +void IonTest::TearDown() { + ion_close(m_ionFd); +} + +IonAllHeapsTest::IonAllHeapsTest() : + m_firstHeap(0), + m_lastHeap(0), + m_allHeaps() +{ +} + +void IonAllHeapsTest::SetUp() { + int fd = ion_open(); + ASSERT_GE(fd, 0); + + for (int i = 1; i != 0; i <<= 1) { + ion_user_handle_t handle = 0; + int ret; + ret = ion_alloc(fd, 4096, 0, i, 0, &handle); + if (ret == 0 && handle != 0) { + ion_free(fd, handle); + if (!m_firstHeap) { + m_firstHeap = i; + } + m_lastHeap = i; + m_allHeaps.push_back(i); + } else { + ASSERT_EQ(-ENODEV, ret); + } + } + ion_close(fd); + + EXPECT_NE(0U, m_firstHeap); + EXPECT_NE(0U, m_lastHeap); + + RecordProperty("Heaps", m_allHeaps.size()); + IonTest::SetUp(); +} + +void IonAllHeapsTest::TearDown() { + IonTest::TearDown(); +} diff --git a/libion/tests/ion_test_fixture.h b/libion/tests/ion_test_fixture.h new file mode 100644 index 0000000..4098214 --- /dev/null +++ b/libion/tests/ion_test_fixture.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ION_TEST_FIXTURE_H_ +#define ION_TEST_FIXTURE_H_ + +#include <gtest/gtest.h> + +using ::testing::Test; + +class IonTest : public virtual Test { + public: + IonTest(); + virtual ~IonTest() {}; + virtual void SetUp(); + virtual void TearDown(); + int m_ionFd; +}; + +class IonAllHeapsTest : public IonTest { + public: + IonAllHeapsTest(); + virtual ~IonAllHeapsTest() {}; + virtual void SetUp(); + virtual void TearDown(); + + unsigned int m_firstHeap; + unsigned int m_lastHeap; + + std::vector<unsigned int> m_allHeaps; +}; + +#endif /* ION_TEST_FIXTURE_H_ */ diff --git a/libion/tests/map_test.cpp b/libion/tests/map_test.cpp new file mode 100644 index 0000000..c006dc8 --- /dev/null +++ b/libion/tests/map_test.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/mman.h> + +#include <gtest/gtest.h> + +#include <ion/ion.h> + +#include "ion_test_fixture.h" + +class Map : public IonAllHeapsTest { +}; + +TEST_F(Map, MapHandle) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + ion_user_handle_t handle = 0; + + ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle)); + ASSERT_TRUE(handle != 0); + + int map_fd = -1; + unsigned char *ptr = NULL; + ASSERT_EQ(0, ion_map(m_ionFd, handle, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0, &ptr, &map_fd)); + ASSERT_TRUE(ptr != NULL); + ASSERT_GE(map_fd, 0); + + ASSERT_EQ(0, close(map_fd)); + + ASSERT_EQ(0, ion_free(m_ionFd, handle)); + + memset(ptr, 0xaa, size); + + ASSERT_EQ(0, munmap(ptr, size)); + } + } +} + +TEST_F(Map, MapFd) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, close(map_fd)); + + memset(ptr, 0xaa, size); + + ASSERT_EQ(0, munmap(ptr, size)); + } + } +} + +TEST_F(Map, MapOffset) +{ + for (unsigned int heapMask : m_allHeaps) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + int map_fd = -1; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, PAGE_SIZE * 2, 0, heapMask, 0, &map_fd)); + ASSERT_GE(map_fd, 0); + + unsigned char *ptr; + ptr = (unsigned char *)mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + memset(ptr, 0, PAGE_SIZE); + memset(ptr + PAGE_SIZE, 0xaa, PAGE_SIZE); + + ASSERT_EQ(0, munmap(ptr, PAGE_SIZE * 2)); + + ptr = (unsigned char *)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, PAGE_SIZE); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(ptr[0], 0xaa); + ASSERT_EQ(ptr[PAGE_SIZE - 1], 0xaa); + + ASSERT_EQ(0, munmap(ptr, PAGE_SIZE)); + + ASSERT_EQ(0, close(map_fd)); + } +} + +TEST_F(Map, MapCached) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, close(map_fd)); + + memset(ptr, 0xaa, size); + + ASSERT_EQ(0, munmap(ptr, size)); + } + } +} + +TEST_F(Map, MapCachedNeedsSync) +{ + static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024}; + for (unsigned int heapMask : m_allHeaps) { + for (size_t size : allocationSizes) { + SCOPED_TRACE(::testing::Message() << "heap " << heapMask); + SCOPED_TRACE(::testing::Message() << "size " << size); + int map_fd = -1; + unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC; + + ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd)); + ASSERT_GE(map_fd, 0); + + void *ptr; + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); + ASSERT_TRUE(ptr != NULL); + + ASSERT_EQ(0, close(map_fd)); + + memset(ptr, 0xaa, size); + + ASSERT_EQ(0, munmap(ptr, size)); + } + } +} |