1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fbl/unique_ptr.h>
6 #include <lib/fzl/owned-vmo-mapper.h>
7 #include <unittest/unittest.h>
8 
9 #include <utility>
10 
11 // Note: these tests focus on the added functionality of the owned VMO
12 // mapper.  The core functionality is assumed to have already been tested by the
13 // vmo/vmar tests.
14 namespace {
15 
16 constexpr char vmo_name[ZX_MAX_NAME_LEN] = "my-vmo";
17 constexpr size_t kNonRootVmarSize = (512 << 20);
18 constexpr zx_vm_option_t kNonRootVmarOpts = ZX_VM_CAN_MAP_SPECIFIC |
19                                             ZX_VM_CAN_MAP_READ |
20                                             ZX_VM_CAN_MAP_WRITE;
21 
ValidateCreateHelper(const fzl::OwnedVmoMapper & mapper,uint64_t size)22 bool ValidateCreateHelper(const fzl::OwnedVmoMapper& mapper, uint64_t size) {
23     BEGIN_HELPER;
24 
25     ASSERT_TRUE(mapper.vmo().is_valid());
26     ASSERT_EQ(mapper.size(), size);
27     ASSERT_NONNULL(mapper.start());
28 
29     auto data = static_cast<const uint8_t*>(mapper.start());
30     for (size_t i = 0; i < size; ++i) {
31         ASSERT_EQ(data[i], 0);
32     }
33 
34     char name[ZX_MAX_NAME_LEN] = {};
35     zx_status_t status = mapper.vmo().get_property(ZX_PROP_NAME, name, countof(name));
36     ASSERT_EQ(status, ZX_OK);
37     for (size_t i = 0; i < countof(name); ++i) {
38         ASSERT_EQ(name[i], vmo_name[i]);
39     }
40 
41     END_HELPER;
42 }
43 
44 template <bool NON_ROOT_VMAR>
UncheckedCreateHelper(fbl::unique_ptr<fzl::OwnedVmoMapper> * out_mapper,uint64_t size,const char * name,zx_vm_option_t map_options=ZX_VM_PERM_READ|ZX_VM_PERM_WRITE,uint32_t cache_policy=0)45 bool UncheckedCreateHelper(fbl::unique_ptr<fzl::OwnedVmoMapper>* out_mapper,
46                            uint64_t size,
47                            const char* name,
48                            zx_vm_option_t map_options = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
49                            uint32_t cache_policy = 0) {
50     BEGIN_HELPER;
51 
52     fbl::RefPtr<fzl::VmarManager> manager;
53     if (NON_ROOT_VMAR) {
54         manager = fzl::VmarManager::Create(kNonRootVmarSize, nullptr, kNonRootVmarOpts);
55         ASSERT_NONNULL(manager);
56     }
57 
58     ASSERT_NONNULL(out_mapper);
59     auto mapper = fbl::make_unique<fzl::OwnedVmoMapper>();
60     if (mapper->CreateAndMap(size, name, map_options, std::move(manager), cache_policy) == ZX_OK) {
61         *out_mapper = std::move(mapper);
62     }
63     END_HELPER;
64 }
65 
66 template <bool NON_ROOT_VMAR>
CreateHelper(fbl::unique_ptr<fzl::OwnedVmoMapper> * out_mapper,uint64_t size,const char * name,zx_vm_option_t map_options=ZX_VM_PERM_READ|ZX_VM_PERM_WRITE,uint32_t cache_policy=0)67 bool CreateHelper(fbl::unique_ptr<fzl::OwnedVmoMapper>* out_mapper,
68                   uint64_t size,
69                   const char* name,
70                   zx_vm_option_t map_options = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
71                   uint32_t cache_policy = 0) {
72     BEGIN_HELPER;
73 
74     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(out_mapper,
75                                                      size,
76                                                      name,
77                                                      map_options,
78                                                      cache_policy));
79     ASSERT_NONNULL(*out_mapper);
80     ASSERT_TRUE(ValidateCreateHelper(**out_mapper, size));
81 
82     END_HELPER;
83 }
84 
85 template <bool NON_ROOT_VMAR>
CreateAndMapHelper(fzl::OwnedVmoMapper * inout_mapper,uint64_t size,const char * name,zx_vm_option_t map_options=ZX_VM_PERM_READ|ZX_VM_PERM_WRITE,uint32_t cache_policy=0)86 bool CreateAndMapHelper(fzl::OwnedVmoMapper* inout_mapper,
87                         uint64_t size,
88                         const char* name,
89                         zx_vm_option_t map_options = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
90                         uint32_t cache_policy = 0) {
91     BEGIN_HELPER;
92 
93     fbl::RefPtr<fzl::VmarManager> manager;
94     if (NON_ROOT_VMAR) {
95         manager = fzl::VmarManager::Create(kNonRootVmarSize, nullptr, kNonRootVmarOpts);
96         ASSERT_NONNULL(manager);
97     }
98 
99     ASSERT_NONNULL(inout_mapper);
100     zx_status_t status;
101     status = inout_mapper->CreateAndMap(size,
102                                         name,
103                                         map_options,
104                                         std::move(manager),
105                                         cache_policy);
106     ASSERT_EQ(status, ZX_OK);
107     ASSERT_TRUE(ValidateCreateHelper(*inout_mapper, size));
108 
109     END_HELPER;
110 }
111 
112 template <bool NON_ROOT_VMAR>
MapHelper(fzl::OwnedVmoMapper * inout_mapper,zx::vmo vmo,uint64_t size,zx_vm_option_t map_options=ZX_VM_PERM_READ|ZX_VM_PERM_WRITE)113 bool MapHelper(fzl::OwnedVmoMapper* inout_mapper,
114                zx::vmo vmo,
115                uint64_t size,
116                zx_vm_option_t map_options = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE) {
117     BEGIN_HELPER;
118 
119     fbl::RefPtr<fzl::VmarManager> manager;
120     if (NON_ROOT_VMAR) {
121         manager = fzl::VmarManager::Create(kNonRootVmarSize, nullptr, kNonRootVmarOpts);
122         ASSERT_NONNULL(manager);
123     }
124 
125     ASSERT_NONNULL(inout_mapper);
126     zx_status_t status;
127     status = inout_mapper->Map(std::move(vmo), size, map_options, std::move(manager));
128     ASSERT_EQ(status, ZX_OK);
129     ASSERT_TRUE(ValidateCreateHelper(*inout_mapper, size));
130 
131     END_HELPER;
132 }
133 
134 template <bool NON_ROOT_VMAR>
CreateTest()135 bool CreateTest() {
136     BEGIN_TEST;
137 
138     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
139     ASSERT_TRUE(CreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, vmo_name));
140 
141     END_TEST;
142 }
143 
144 template <bool NON_ROOT_VMAR>
CreateAndMapTest()145 bool CreateAndMapTest() {
146     BEGIN_TEST;
147 
148     fzl::OwnedVmoMapper mapper;
149     ASSERT_TRUE(CreateAndMapHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, vmo_name));
150 
151     END_TEST;
152 }
153 
154 template <bool NON_ROOT_VMAR>
MapTest()155 bool MapTest() {
156     BEGIN_TEST;
157 
158     zx::vmo vmo;
159     zx_status_t status;
160 
161     status = zx::vmo::create(ZX_PAGE_SIZE, 0, &vmo);
162     ASSERT_EQ(status, ZX_OK);
163 
164     status = vmo.set_property(ZX_PROP_NAME, vmo_name, strlen(vmo_name));
165     ASSERT_EQ(status, ZX_OK);
166 
167     fzl::OwnedVmoMapper mapper;
168     ASSERT_TRUE(MapHelper<NON_ROOT_VMAR>(&mapper, std::move(vmo), ZX_PAGE_SIZE));
169 
170     END_TEST;
171 }
172 
173 template <bool NON_ROOT_VMAR>
MoveTest()174 bool MoveTest() {
175     BEGIN_TEST;
176 
177     fzl::OwnedVmoMapper mapper1;
178     ASSERT_TRUE(CreateAndMapHelper<NON_ROOT_VMAR>(&mapper1, ZX_PAGE_SIZE, vmo_name));
179 
180     // Move by construction
181     zx_handle_t orig_handle = mapper1.vmo().get();
182     void* orig_start = mapper1.start();
183     size_t orig_size = mapper1.size();
184     const fzl::VmarManager* orig_manager = mapper1.manager().get();
185 
186     ASSERT_NE(orig_handle, ZX_HANDLE_INVALID);
187     ASSERT_NONNULL(orig_start);
188     ASSERT_EQ(orig_size, ZX_PAGE_SIZE);
189     if (NON_ROOT_VMAR) {
190         ASSERT_NONNULL(orig_manager);
191     } else {
192         ASSERT_NULL(orig_manager);
193     }
194 
195     fzl::OwnedVmoMapper mapper2(std::move(mapper1));;
196     ASSERT_EQ(mapper1.vmo().get(), ZX_HANDLE_INVALID);
197     ASSERT_NULL(mapper1.start());
198     ASSERT_EQ(mapper1.size(), 0);
199     ASSERT_NULL(mapper1.manager());
200 
201     ASSERT_EQ(mapper2.vmo().get(), orig_handle);
202     ASSERT_EQ(mapper2.start(), orig_start);
203     ASSERT_EQ(mapper2.size(), orig_size);
204     ASSERT_EQ(mapper2.manager().get(), orig_manager);
205     ASSERT_TRUE(ValidateCreateHelper(mapper2, orig_size));
206 
207     // Move by assignment
208     mapper1 = std::move(mapper2);
209 
210     ASSERT_EQ(mapper2.vmo().get(), ZX_HANDLE_INVALID);
211     ASSERT_NULL(mapper2.start());
212     ASSERT_EQ(mapper2.size(), 0);
213     ASSERT_NULL(mapper2.manager());
214 
215     ASSERT_EQ(mapper1.vmo().get(), orig_handle);
216     ASSERT_EQ(mapper1.start(), orig_start);
217     ASSERT_EQ(mapper1.size(), orig_size);
218     ASSERT_EQ(mapper1.manager().get(), orig_manager);
219     ASSERT_TRUE(ValidateCreateHelper(mapper1, orig_size));
220 
221     END_TEST;
222 }
223 
224 template <bool NON_ROOT_VMAR>
ReadTest()225 bool ReadTest() {
226     BEGIN_TEST;
227 
228     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
229     ASSERT_TRUE(CreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, vmo_name));
230 
231     uint8_t bytes[ZX_PAGE_SIZE];
232     memset(bytes, 0xff, ZX_PAGE_SIZE);
233 
234     zx_status_t status = mapper->vmo().read(bytes, 0, ZX_PAGE_SIZE);
235     ASSERT_EQ(status, ZX_OK);
236     for (size_t i = 0; i < ZX_PAGE_SIZE; ++i) {
237         ASSERT_EQ(bytes[i], 0);
238     }
239 
240     END_TEST;
241 }
242 
243 // Test that touching memory, then zx_vmo_reading, works as expected.
244 template <bool NON_ROOT_VMAR>
WriteMappingTest()245 bool WriteMappingTest() {
246     BEGIN_TEST;
247 
248     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
249     ASSERT_TRUE(CreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, vmo_name));
250 
251     auto data = static_cast<uint8_t*>(mapper->start());
252     memset(data, 0xff, ZX_PAGE_SIZE);
253 
254     uint8_t bytes[ZX_PAGE_SIZE] = {};
255     zx_status_t status = mapper->vmo().read(bytes, 0, ZX_PAGE_SIZE);
256     ASSERT_EQ(status, ZX_OK);
257     for (size_t i = 0; i < ZX_PAGE_SIZE; ++i) {
258         ASSERT_EQ(bytes[i], 0xff);
259     }
260 
261     END_TEST;
262 }
263 
264 // Test that zx_vmo_writing, then reading memory, works as expected.
265 template <bool NON_ROOT_VMAR>
ReadMappingTest()266 bool ReadMappingTest() {
267     BEGIN_TEST;
268 
269     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
270     ASSERT_TRUE(CreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, vmo_name));
271 
272     uint8_t bytes[ZX_PAGE_SIZE];
273     memset(bytes, 0xff, ZX_PAGE_SIZE);
274     zx_status_t status = mapper->vmo().write(bytes, 0, ZX_PAGE_SIZE);
275     ASSERT_EQ(status, ZX_OK);
276 
277     auto data = static_cast<uint8_t*>(mapper->start());
278     for (size_t i = 0; i < ZX_PAGE_SIZE; ++i) {
279         ASSERT_EQ(data[i], 0xff);
280     }
281 
282     END_TEST;
283 }
284 
285 template <bool NON_ROOT_VMAR>
EmptyNameTest()286 bool EmptyNameTest() {
287     BEGIN_TEST;
288 
289     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
290     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, ""));
291     ASSERT_NONNULL(mapper);
292 
293     char name[ZX_MAX_NAME_LEN] = {};
294     zx_status_t status = mapper->vmo().get_property(ZX_PROP_NAME, name, ZX_MAX_NAME_LEN);
295     ASSERT_EQ(status, ZX_OK);
296     for (size_t i = 0; i < ZX_MAX_NAME_LEN; ++i) {
297         ASSERT_EQ(name[i], 0);
298     }
299 
300     END_TEST;
301 }
302 
303 template <bool NON_ROOT_VMAR>
NullptrNameTest()304 bool NullptrNameTest() {
305     BEGIN_TEST;
306 
307     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
308     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, nullptr));
309     ASSERT_NONNULL(mapper);
310 
311     char name[ZX_MAX_NAME_LEN] = {};
312     zx_status_t status = mapper->vmo().get_property(ZX_PROP_NAME, name, ZX_MAX_NAME_LEN);
313     ASSERT_EQ(status, ZX_OK);
314     for (size_t i = 0; i < ZX_MAX_NAME_LEN; ++i) {
315         ASSERT_EQ(name[i], 0);
316     }
317 
318     END_TEST;
319 }
320 
321 template <bool NON_ROOT_VMAR>
LongNameTest()322 bool LongNameTest() {
323     BEGIN_TEST;
324 
325     char long_name[ZX_PAGE_SIZE];
326     memset(long_name, 'x', ZX_PAGE_SIZE);
327     long_name[ZX_PAGE_SIZE - 1] = 0;
328 
329     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
330     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(&mapper, ZX_PAGE_SIZE, long_name));
331     ASSERT_NONNULL(mapper);
332 
333     char name[ZX_MAX_NAME_LEN] = {};
334     zx_status_t status = mapper->vmo().get_property(ZX_PROP_NAME, name, ZX_MAX_NAME_LEN);
335     ASSERT_EQ(status, ZX_OK);
336     for (size_t i = 0; i < ZX_MAX_NAME_LEN - 1; ++i) {
337         ASSERT_EQ(name[i], 'x');
338     }
339     ASSERT_EQ(name[ZX_MAX_NAME_LEN - 1], 0);
340 
341     END_TEST;
342 }
343 
344 template <bool NON_ROOT_VMAR>
GoodSizesTest()345 bool GoodSizesTest() {
346     BEGIN_TEST;
347 
348     static const size_t sizes[] = {
349         ZX_PAGE_SIZE,
350         16 * ZX_PAGE_SIZE,
351         ZX_PAGE_SIZE * ZX_PAGE_SIZE,
352         ZX_PAGE_SIZE + 1,
353     };
354 
355     for (size_t size : sizes) {
356         fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
357         ASSERT_TRUE(CreateHelper<NON_ROOT_VMAR>(&mapper, size, vmo_name));
358     }
359 
360     END_TEST;
361 }
362 
363 template <bool NON_ROOT_VMAR>
BadSizesTest()364 bool BadSizesTest() {
365     BEGIN_TEST;
366 
367     // Size 0 should fail.
368     fbl::unique_ptr<fzl::OwnedVmoMapper> mapper;
369     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(&mapper, 0, vmo_name));
370     ASSERT_NULL(mapper);
371 
372     // So should an aburdly big request.
373     ASSERT_TRUE(UncheckedCreateHelper<NON_ROOT_VMAR>(&mapper, SIZE_MAX, vmo_name));
374     ASSERT_NULL(mapper);
375 
376     END_TEST;
377 }
378 
379 }  // namespace
380 
381 #define MAKE_TEST(_name) \
382     RUN_NAMED_TEST(#_name "_RootVmar",    _name<false>) \
383     RUN_NAMED_TEST(#_name "_NON_ROOT_VMAR", _name<true>)
384 
385 BEGIN_TEST_CASE(owned_vmo_mapper_tests)
386 MAKE_TEST(CreateTest)
387 MAKE_TEST(CreateAndMapTest)
388 MAKE_TEST(MapTest)
389 MAKE_TEST(MoveTest)
390 MAKE_TEST(ReadTest)
391 MAKE_TEST(WriteMappingTest)
392 MAKE_TEST(ReadMappingTest)
393 MAKE_TEST(EmptyNameTest)
394 MAKE_TEST(NullptrNameTest)
395 MAKE_TEST(LongNameTest)
396 MAKE_TEST(GoodSizesTest)
397 MAKE_TEST(BadSizesTest)
398 END_TEST_CASE(owned_vmo_mapper_tests)
399 
400 #undef MAKE_TEST
401