summaryrefslogtreecommitdiffstats
path: root/libion
diff options
context:
space:
mode:
Diffstat (limited to 'libion')
-rw-r--r--libion/Android.mk5
-rw-r--r--libion/include/ion/ion.h46
-rw-r--r--libion/ion.c182
-rw-r--r--libion/ion_test.c443
-rw-r--r--libion/kernel-headers/linux/ion.h78
-rw-r--r--libion/kernel-headers/linux/ion_test.h38
-rw-r--r--libion/original-kernel-headers/linux/ion.h196
-rw-r--r--libion/original-kernel-headers/linux/ion_test.h70
-rw-r--r--libion/tests/Android.mk34
-rw-r--r--libion/tests/allocate_test.cpp145
-rw-r--r--libion/tests/device_test.cpp568
-rw-r--r--libion/tests/exit_test.cpp227
-rw-r--r--libion/tests/formerly_valid_handle_test.cpp63
-rw-r--r--libion/tests/invalid_values_test.cpp186
-rw-r--r--libion/tests/ion_test_fixture.cpp73
-rw-r--r--libion/tests/ion_test_fixture.h46
-rw-r--r--libion/tests/map_test.cpp162
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));
+ }
+ }
+}