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