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