1 /*
2 * Copyright (C) 2018 Samsung Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <iostream>
17 #include <fstream>
18 #include <string>
19 #include <cerrno>
20
21 #include <unistd.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/ioctl.h>
26 #include <sys/mman.h>
27 #include <fcntl.h>
28
29 #include "ion_test_fixture.h"
30 #include "ion_test_define.h"
31
32 using namespace std;
33
IonTest()34 IonTest::IonTest() : m_ionFd(-1), m_heapCount(0), m_allHeapMask(0)
35 {
36 m_idTable[0].legacy_id = ION_EXYNOS_HEAP_ID_SYSTEM;
37 m_idTable[1].legacy_id = ION_EXYNOS_HEAP_ID_CRYPTO;
38 m_idTable[2].legacy_id = ION_EXYNOS_HEAP_ID_VIDEO_STREAM;
39 m_idTable[3].legacy_id = ION_EXYNOS_HEAP_ID_VIDEO_FRAME;
40 m_idTable[4].legacy_id = ION_EXYNOS_HEAP_ID_VIDEO_SCALER;
41 m_idTable[5].legacy_id = ION_EXYNOS_HEAP_ID_CAMERA;
42 m_idTable[6].legacy_id = ION_EXYNOS_HEAP_ID_SECURE_CAMERA;
43
44 for (unsigned int i = 0; i < MAX_LEGACY_HEAP_IDS; i++)
45 m_idTable[i].heap_id = ION_NUM_HEAP_IDS;
46 }
47
SetUp()48 void IonTest::SetUp()
49 {
50 m_ionFd = open("/dev/ion", O_RDWR);
51
52 m_ionHeapData = new ion_heap_data[ION_NUM_HEAP_IDS];
53 if (m_ionHeapData != NULL) {
54 ion_heap_query query;
55 int ret;
56
57 memset(&query, 0, sizeof(query));
58 memset(m_ionHeapData, 0, sizeof(ion_heap_data) * ION_NUM_HEAP_IDS);
59
60 query.cnt = ION_NUM_HEAP_IDS;
61 query.heaps = reinterpret_cast<__u64>(m_ionHeapData);
62
63 ret = ioctl(m_ionFd, ION_IOC_HEAP_QUERY, &query);
64 if (ret < 0) {
65 FAIL() << "ION_IOC_HEAP_QUERY failed: " << strerror(errno);
66 } else {
67 m_heapCount = query.cnt;
68 }
69 }
70
71 for (unsigned int i = 0; i < MAX_LEGACY_HEAP_IDS; i++) {
72 const char *name = exynos_ion_get_heap_name(m_idTable[i].legacy_id);
73 for (unsigned int k = 0; k < m_heapCount; k++) {
74 if (!strcmp(name, m_ionHeapData[k].name) &&
75 (strlen(name) == strlen(m_ionHeapData[k].name))) {
76 m_allHeapMask |= 1 << m_idTable[i].legacy_id;
77 m_idTable[i].heap_id = m_ionHeapData[k].heap_id;
78 }
79 }
80 }
81
82 RecordProperty("Heaps", m_heapCount);
83
84 SUCCEED() << "Found " << m_heapCount << " heaps found";
85 }
86
TearDown()87 void IonTest::TearDown()
88 {
89 delete [] m_ionHeapData;
90 close(m_ionFd);
91 }
92
getCmaUsed(std::string heapname)93 size_t IonTest::getCmaUsed(std::string heapname)
94 {
95 std::string pathname = "/sys/kernel/debug/cma/cma-";
96 pathname = pathname + heapname;
97 pathname = pathname + "/used";
98
99 ifstream ifs;
100 ifs.open(pathname);
101 // CONFIG_CMA_DEBUGFS is not enabled or @heapname is not defined
102 if (!ifs)
103 return 0;
104
105 size_t len;
106 ifs >> len;
107
108 return len * sysconf(_SC_PAGESIZE);
109 }
110
IonAllocTest()111 IonAllocTest::IonAllocTest() : m_memTotal(0)
112 {
113 }
114
SetUp()115 void IonAllocTest::SetUp()
116 {
117 IonTest::SetUp();
118
119 ifstream ifs;
120 ifs.open("/proc/meminfo");
121
122 string title, kb;
123 size_t size;
124
125 ifs >> title >> size >> kb;
126
127 m_memTotal = size;
128
129 RecordProperty("MemTotalInKb", m_memTotal);
130
131 SUCCEED() << "MemTotal: " << m_memTotal << " kb";
132 }
133
TearDown()134 void IonAllocTest::TearDown()
135 {
136 IonTest::TearDown();
137 }
138
IonSpecialTest()139 IonSpecialTest::IonSpecialTest() : m_ionTestDevFd(-1)
140 {
141 }
142
SetUp()143 void IonSpecialTest::SetUp()
144 {
145 IonTest::SetUp();
146
147 m_ionTestDevFd = open("/dev/ion-test", O_RDWR);
148 if (m_ionTestDevFd < 0) {
149 FAIL() << "Failed to open /dev/ion-test: " << strerror(errno);
150 }
151 }
152
TearDown()153 void IonSpecialTest::TearDown()
154 {
155 IonTest::TearDown();
156
157 close(m_ionTestDevFd);
158 }
159
ionAlloc(size_t size,unsigned int heapmask,unsigned int flags)160 int IonSpecialTest::ionAlloc(size_t size, unsigned int heapmask,
161 unsigned int flags)
162 {
163 int fd = -1;
164
165 ion_allocation_data_modern data;
166
167 data.len = size;
168 data.heap_id_mask = heapmask;
169 data.flags = flags;
170 data.fd = 0;
171
172 if (ioctl(getIonFd(), ION_IOC_ALLOC_MODERN, &data) == 0)
173 fd = static_cast<int>(data.fd);
174
175 return fd;
176 }
177
ionMmap(int fd,size_t size)178 char *IonClientDeviceTest::ionMmap(int fd, size_t size)
179 {
180 void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
181 if (p == MAP_FAILED)
182 return NULL;
183 return reinterpret_cast<char *>(p);
184 }
185
ionMunmap(void * ptr,size_t size)186 void IonClientDeviceTest::ionMunmap(void *ptr, size_t size)
187 {
188 munmap(ptr, size);
189 }
190
ionTestMapping(int fd,bool write,unsigned long cmd,void * ptr,size_t size,off_t offset)191 void IonClientDeviceTest::ionTestMapping(int fd, bool write, unsigned long cmd,
192 void *ptr, size_t size, off_t offset)
193 {
194 EXPECT_EQ(0, ioctl(getTestDevFd(), ION_IOC_TEST_SET_FD, fd));
195
196 ion_test_rw_data data;
197
198 data.ptr = reinterpret_cast<__u64>(ptr);
199 data.offset = offset;
200 data.size = size;
201 data.write = write ? 1 : 0;
202
203 EXPECT_EQ(0, ioctl(getTestDevFd(), cmd, &data)) << strerror(errno);
204
205 EXPECT_EQ(0, ioctl(getTestDevFd(), ION_IOC_TEST_SET_FD, -1));
206 }
207
blowCache()208 void IonClientDeviceTest::blowCache()
209 {
210 const size_t bigger_than_cache = mb(8);
211 const size_t nelem = bigger_than_cache / sizeof(unsigned int);
212 unsigned int *buf1 = new unsigned int[nelem];
213 unsigned int *buf2 = new unsigned int[nelem];
214
215 // write order is swizzled to prevent
216 // detection of streaming write by a high-performance CPU.
217 // Such CPUs skip storing streaming writes to caches.
218 for (size_t i = 0; i < (nelem / 2); i++) {
219 buf1[i] = i;
220 buf1[nelem - i - 1] = i;
221 }
222
223 memcpy(buf2, buf1, bigger_than_cache);
224
225 delete [] buf2;
226 delete [] buf1;
227 }
228
dirtyCache(void * ptr,size_t size)229 void IonClientDeviceTest::dirtyCache(void *ptr, size_t size)
230 {
231 unsigned int *uip = reinterpret_cast<unsigned int *>(ptr);
232 const size_t nelem = size / sizeof(unsigned int);
233
234 for (size_t i = 0; i < (nelem / 2); i++) {
235 uip[i] = 0x5a6b5a6b;
236 uip[nelem - i - 1] = 0x6b5a6b5a;
237 }
238 }
239
fill(void * ptr,size_t size,off_t offset)240 void IonClientDeviceTest::fill(void *ptr, size_t size, off_t offset)
241 {
242 unsigned int *uip = reinterpret_cast<unsigned int *>(ptr);
243
244 size /= sizeof(unsigned int);
245 offset /= sizeof(unsigned int);
246
247 uip += offset;
248
249 for (size_t i = 0; i < (size / 2); i++) {
250 uip[i] = i;
251 uip[size - i - 1] = size - i - 1;
252 }
253 }
254
check(void * ptr,size_t size,off_t offset)255 bool IonClientDeviceTest::check(void *ptr, size_t size, off_t offset)
256 {
257 unsigned int *uip = reinterpret_cast<unsigned int *>(ptr);
258
259 size /= sizeof(unsigned int);
260 offset /= sizeof(unsigned int);
261
262 uip += offset;
263
264 for (size_t i = 0; i < size; i++) {
265 if (uip[i] != i) {
266 cerr << "Expected " << i << " at offset " << i * sizeof(i) << " byte but found " << uip[i] << endl;
267 return false;
268 }
269 }
270
271 return true;
272 }
273