test_map_ptr_x64.cpp
Go to the documentation of this file.
1 //
2 // Bareflank Hypervisor
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #include <test.h>
25 
26 #include <map>
27 #include <exception>
28 
29 #include <intrinsics/x64.h>
30 
31 constexpr const auto valid_virt = 0x0000111100000000UL;
32 constexpr const auto valid_phys = 0x0000222200000000UL;
33 constexpr const auto invalid_virt = 0x0U;
34 constexpr const auto invalid_phys = 0x0U;
35 constexpr const auto phys_offset = 0x10U;
36 constexpr const auto valid_map = valid_virt + phys_offset;
37 
38 std::map<const void *, bool> g_freed;
39 std::map<const void *, bool> g_flushed;
40 std::map<const void *, bool> g_cache_flushed;
41 std::map<memory_manager_x64::integer_pointer, memory_manager_x64::integer_pointer> g_mapped;
42 std::map<memory_manager_x64::integer_pointer, bool> g_unmapped;
43 
45 
46 extern "C" void
47 __invlpg(const void *virt) noexcept
48 { g_flushed[virt] = true; }
49 
50 extern "C" void
52 { g_cache_flushed[addr] = true; }
53 
54 auto g_pte_valid_present = true;
56 auto g_pte_large_page = false;
59 
60 static auto dummy_pt = std::make_unique<memory_manager_x64::integer_pointer[]>(x64::page_table::num_entries);
61 static auto dummy_pt_span = gsl::make_span(dummy_pt, x64::page_table::num_entries);
62 
65 {
66  (void) size;
67 
69 
70  for (auto &element : dummy_pt_span)
71  {
72  element = 0;
73 
74  auto pte = page_table_entry_x64{&element};
75  if (g_pte_valid_present) pte.set_present(true);
76  if (g_pte_valid_phys_addr) pte.set_phys_addr(valid_phys);
77  if (g_pte_large_page)
78  {
79  if (g_pte_large_page_count == 0)
80  pte.set_ps(true);
81  }
82  }
83 
84  if (g_pte_large_page_count == 0)
86 
87  return reinterpret_cast<memory_manager_x64::pointer>(dummy_pt.get());
88 }
89 
90 static void
92 { g_freed[ptr] = true; }
93 
94 static void
98 {
99  (void) attr;
100  g_mapped[virt] = phys;
101 }
102 
103 static void
105 {
106  (void) virt;
107  g_unmapped[virt] = true;
108 }
109 
110 static auto
111 setup_mm(MockRepository &mocks)
112 {
113  auto mm = mocks.Mock<memory_manager_x64>();
114  mocks.OnCallFunc(memory_manager_x64::instance).Return(mm);
115 
116  mocks.OnCall(mm, memory_manager_x64::alloc_map).Do(mm_alloc_map);
117  mocks.OnCall(mm, memory_manager_x64::free_map).Do(mm_free_map);
118 
119  g_freed.clear();
120 
121  return mm;
122 }
123 
124 static auto
125 setup_pt(MockRepository &mocks)
126 {
127  auto pt = mocks.Mock<root_page_table_x64>();
128  mocks.OnCallFunc(root_pt).Return(pt);
129 
130  mocks.OnCall(pt, root_page_table_x64::map_4k).Do(pt_map);
131  mocks.OnCall(pt, root_page_table_x64::unmap).Do(pt_unmap);
132 
133  g_flushed.clear();
134  g_mapped.clear();
135  g_unmapped.clear();
136 
137  return pt;
138 }
139 
140 void
141 memory_manager_ut::test_unique_map_ptr_x64_default_constructor()
142 {
144  this->expect_no_exception([&] { bfn::unique_map_ptr_x64<int>(nullptr); });
145 }
146 
147 void
148 memory_manager_ut::test_unique_map_ptr_x64_phys_constructor_invalid_args()
149 {
154 }
155 
156 void
157 memory_manager_ut::test_unique_map_ptr_x64_phys_constructor_mm_map_fails()
158 {
159  MockRepository mocks;
160  setup_mm(mocks);
161  auto &&pt = setup_pt(mocks);
162 
163  mocks.OnCall(pt, root_page_table_x64::map_4k).Throw(std::runtime_error("error"));
164 
165  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
166  {
168  });
169 }
170 
171 void
172 memory_manager_ut::test_unique_map_ptr_x64_phys_constructor_success()
173 {
174  MockRepository mocks;
175  setup_mm(mocks);
176  setup_pt(mocks);
177 
178  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
179  {
181 
182  this->expect_true(map);
183  this->expect_true(map.get() == make_ptr(valid_virt));
184  this->expect_true(map.size() == x64::page_size);
185  this->expect_true(g_flushed[make_ptr(valid_virt)]);
186  this->expect_true(g_mapped[valid_virt] == valid_phys);
187 
188  map.reset();
189 
190  this->expect_true(g_unmapped[valid_virt]);
191  this->expect_true(g_freed[make_ptr(valid_virt)]);
192  });
193 }
194 
195 void
196 memory_manager_ut::test_unique_map_ptr_x64_phys_range_constructor_invalid_args()
197 {
198  auto &&phys_range_1 = std::make_pair(0x1111000000000010UL, x64::page_size * 2UL);
199  auto &&phys_range_2 = std::make_pair(0x1111000000004000UL, x64::page_size * 2UL);
200  auto &&phys_range_3 = std::make_pair(0x1111000000008000UL, x64::page_size * 2UL);
201  auto &&list = {phys_range_1, phys_range_2, phys_range_3};
202 
203  auto &&invalid_phys_range_1 = std::make_pair(0UL, x64::page_size * 2UL);
204  auto &&invalid_phys_range_2 = std::make_pair(0x1111000000000010UL, 0UL);
205  auto &&invalid_phys_range_3 = std::make_pair(0x1111000000000010UL, 2UL);
206  auto &&invalid_list1 = {phys_range_1, invalid_phys_range_1, phys_range_3};
207  auto &&invalid_list2 = {phys_range_1, invalid_phys_range_2, phys_range_3};
208  auto &&invalid_list3 = {phys_range_1, invalid_phys_range_3, phys_range_3};
209 
211  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt + 0x10U, list, read_write); }, ""_ut_ffe);
212  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, {}, read_write); }, ""_ut_ffe);
213  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, invalid_list1, read_write); }, ""_ut_ffe);
214  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, invalid_list2, read_write); }, ""_ut_ffe);
215  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, invalid_list3, read_write); }, ""_ut_ffe);
216 }
217 
218 void
219 memory_manager_ut::test_unique_map_ptr_x64_phys_range_constructor_mm_map_fails()
220 {
221  MockRepository mocks;
222  setup_mm(mocks);
223  auto &&pt = setup_pt(mocks);
224 
225  mocks.OnCall(pt, root_page_table_x64::map_4k).Throw(std::runtime_error("error"));
226 
227  auto &&phys_range_1 = std::make_pair(0x1111000000000010UL, x64::page_size * 2UL);
228  auto &&phys_range_2 = std::make_pair(0x1111000000004000UL, x64::page_size * 2UL);
229  auto &&phys_range_3 = std::make_pair(0x1111000000008000UL, x64::page_size * 2UL);
230  auto &&list = {phys_range_1, phys_range_2, phys_range_3};
231 
232  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
233  {
234  this->expect_exception([&]{ bfn::unique_map_ptr_x64<int>(valid_virt, list, read_write); }, "error"_ut_ree);
235  });
236 }
237 
238 void
239 memory_manager_ut::test_unique_map_ptr_x64_phys_range_constructor_success()
240 {
241  MockRepository mocks;
242  setup_mm(mocks);
243  setup_pt(mocks);
244 
245  auto &&phys_range_1 = std::make_pair(0x1111000000000010UL, x64::page_size * 2UL);
246  auto &&phys_range_2 = std::make_pair(0x1111000000004000UL, x64::page_size * 2UL);
247  auto &&phys_range_3 = std::make_pair(0x1111000000008000UL, x64::page_size * 2UL);
248  auto &&list = {phys_range_1, phys_range_2, phys_range_3};
249 
250  auto &&virt1 = valid_virt + (0 * x64::page_size);
251  auto &&virt2 = valid_virt + (1 * x64::page_size);
252  auto &&virt3 = valid_virt + (2 * x64::page_size);
253  auto &&virt4 = valid_virt + (3 * x64::page_size);
254  auto &&virt5 = valid_virt + (4 * x64::page_size);
255  auto &&virt6 = valid_virt + (5 * x64::page_size);
256 
257  auto &&phys1 = 0x1111000000000000UL;
258  auto &&phys2 = 0x1111000000001000UL;
259  auto &&phys3 = 0x1111000000004000UL;
260  auto &&phys4 = 0x1111000000005000UL;
261  auto &&phys5 = 0x1111000000008000UL;
262  auto &&phys6 = 0x1111000000009000UL;
263 
264  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
265  {
267 
268  this->expect_true(map);
269  this->expect_true(map.get() == make_ptr(valid_map));
270  this->expect_true(map.size() == x64::page_size * 6UL);
271 
272  this->expect_true(g_flushed[make_ptr(virt1)]);
273  this->expect_true(g_flushed[make_ptr(virt2)]);
274  this->expect_true(g_flushed[make_ptr(virt3)]);
275  this->expect_true(g_flushed[make_ptr(virt4)]);
276  this->expect_true(g_flushed[make_ptr(virt5)]);
277  this->expect_true(g_flushed[make_ptr(virt6)]);
278 
279  this->expect_true(g_mapped[virt1] == phys1);
280  this->expect_true(g_mapped[virt2] == phys2);
281  this->expect_true(g_mapped[virt3] == phys3);
282  this->expect_true(g_mapped[virt4] == phys4);
283  this->expect_true(g_mapped[virt5] == phys5);
284  this->expect_true(g_mapped[virt6] == phys6);
285 
286  map.reset();
287 
288  this->expect_true(g_unmapped[virt1]);
289  this->expect_true(g_unmapped[virt2]);
290  this->expect_true(g_unmapped[virt3]);
291  this->expect_true(g_unmapped[virt4]);
292  this->expect_true(g_unmapped[virt5]);
293  this->expect_true(g_unmapped[virt6]);
294 
295  this->expect_true(g_freed[make_ptr(valid_virt)]);
296  });
297 }
298 
299 void
300 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_invalid_args()
301 {
303  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt + 0x10U, valid_virt, valid_phys, x64::page_size, 0x0); }, ""_ut_ffe);
306  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt, valid_phys + 0x10U, x64::page_size, 0x0); }, ""_ut_ffe);
307  this->expect_exception([&] { bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt, valid_phys, 0, 0x0); }, ""_ut_ffe);
308 }
309 
310 void
311 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_mm_map_fails()
312 {
313  MockRepository mocks;
314  setup_mm(mocks);
315  auto &&pt = setup_pt(mocks);
316 
317  mocks.OnCall(pt, root_page_table_x64::map_4k).Throw(std::runtime_error("error"));
318 
319  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
320  {
322  });
323 }
324 
325 void
326 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_success_1g()
327 {
328  MockRepository mocks;
329  setup_mm(mocks);
330  setup_pt(mocks);
331 
332  auto &&virt1 = valid_virt + (0 * x64::page_size);
333  auto &&virt2 = valid_virt + (1 * x64::page_size);
334 
335  auto &&phys1 = 0x0000222200000000UL;
336  auto &&phys2 = 0x0000222200001000UL;
337 
338  g_pte_large_page = true;
341  auto ___ = gsl::finally([&] { g_pte_large_page = false; });
342 
343  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
344  {
345  auto &&map = bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt + phys_offset, valid_phys, x64::page_size * 2UL, 0x0);
346 
347  this->expect_true(map);
348  this->expect_true(map.get() == make_ptr(valid_map));
349  this->expect_true(map.size() == x64::page_size * 2UL);
350 
351  this->expect_true(g_flushed[make_ptr(virt1)]);
352  this->expect_true(g_flushed[make_ptr(virt2)]);
353 
354  this->expect_true(g_mapped[virt1] == phys1);
355  this->expect_true(g_mapped[virt2] == phys2);
356 
357  map.reset();
358 
359  this->expect_true(g_unmapped[virt1]);
360  this->expect_true(g_unmapped[virt2]);
361 
362  this->expect_true(g_freed[make_ptr(virt1)]);
363  });
364 }
365 
366 void
367 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_success_2m()
368 {
369  MockRepository mocks;
370  setup_mm(mocks);
371  setup_pt(mocks);
372 
373  auto &&virt1 = valid_virt + (0 * x64::page_size);
374  auto &&virt2 = valid_virt + (1 * x64::page_size);
375 
376  auto &&phys1 = 0x0000222200000000UL;
377  auto &&phys2 = 0x0000222200001000UL;
378 
379  g_pte_large_page = true;
382  auto ___ = gsl::finally([&] { g_pte_large_page = false; });
383 
384  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
385  {
386  auto &&map = bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt + phys_offset, valid_phys, x64::page_size * 2UL, 0x0);
387 
388  this->expect_true(map);
389  this->expect_true(map.get() == make_ptr(valid_map));
390  this->expect_true(map.size() == x64::page_size * 2UL);
391 
392  this->expect_true(g_flushed[make_ptr(virt1)]);
393  this->expect_true(g_flushed[make_ptr(virt2)]);
394 
395  this->expect_true(g_mapped[virt1] == phys1);
396  this->expect_true(g_mapped[virt2] == phys2);
397 
398  map.reset();
399 
400  this->expect_true(g_unmapped[virt1]);
401  this->expect_true(g_unmapped[virt2]);
402 
403  this->expect_true(g_freed[make_ptr(virt1)]);
404  });
405 }
406 
407 void
408 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_success_4k()
409 {
410  MockRepository mocks;
411  setup_mm(mocks);
412  setup_pt(mocks);
413 
414  auto &&virt1 = valid_virt + (0 * x64::page_size);
415  auto &&virt2 = valid_virt + (1 * x64::page_size);
416  auto &&virt3 = valid_virt + (2 * x64::page_size);
417 
418  auto &&phys1 = 0x0000222200000000UL;
419  auto &&phys2 = 0x0000222200000000UL;
420  auto &&phys3 = 0x0000222200000000UL;
421 
422  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
423  {
424  auto &&map = bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt + phys_offset, valid_phys, x64::page_size * 2UL, 0x0);
425 
426  this->expect_true(map);
427  this->expect_true(map.get() == make_ptr(valid_map));
428  this->expect_true(map.size() == x64::page_size * 2UL);
429 
430  this->expect_true(g_flushed[make_ptr(virt1)]);
431  this->expect_true(g_flushed[make_ptr(virt2)]);
432  this->expect_true(g_flushed[make_ptr(virt3)]);
433 
434  this->expect_true(g_mapped[virt1] == phys1);
435  this->expect_true(g_mapped[virt2] == phys2);
436  this->expect_true(g_mapped[virt3] == phys3);
437 
438  map.reset();
439 
440  this->expect_true(g_unmapped[virt1]);
441  this->expect_true(g_unmapped[virt2]);
442  this->expect_true(g_unmapped[virt3]);
443 
444  this->expect_true(g_freed[make_ptr(virt1)]);
445  });
446 }
447 
448 void
449 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_success_4k_aligned_addr()
450 {
451  MockRepository mocks;
452  setup_mm(mocks);
453  setup_pt(mocks);
454 
455  auto &&virt1 = valid_virt + (0 * x64::page_size);
456  auto &&virt2 = valid_virt + (1 * x64::page_size);
457  auto &&virt3 = valid_virt + (2 * x64::page_size);
458 
459  auto &&phys1 = 0x0000222200000000UL;
460  auto &&phys2 = 0x0000222200000000UL;
461 
462  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
463  {
465 
466  this->expect_true(map);
467  this->expect_true(map.get() == make_ptr(valid_virt));
468  this->expect_true(map.size() == x64::page_size * 2UL);
469 
470  this->expect_true(g_flushed[make_ptr(virt1)]);
471  this->expect_true(g_flushed[make_ptr(virt2)]);
472  this->expect_false(g_flushed[make_ptr(virt3)]);
473 
474  this->expect_true(g_mapped[virt1] == phys1);
475  this->expect_true(g_mapped[virt2] == phys2);
476  this->expect_true(g_mapped[virt3] == 0);
477 
478  map.reset();
479 
480  this->expect_true(g_unmapped[virt1]);
481  this->expect_true(g_unmapped[virt2]);
482  this->expect_false(g_unmapped[virt3]);
483 
484  this->expect_true(g_freed[make_ptr(virt1)]);
485  });
486 }
487 
488 void
489 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_success_4k_aligned_size()
490 {
491  MockRepository mocks;
492  setup_mm(mocks);
493  setup_pt(mocks);
494 
495  auto &&virt1 = valid_virt + (0 * x64::page_size);
496  auto &&virt2 = valid_virt + (1 * x64::page_size);
497  auto &&virt3 = valid_virt + (2 * x64::page_size);
498 
499  auto &&phys1 = 0x0000222200000000UL;
500  auto &&phys2 = 0x0000222200000000UL;
501 
502  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
503  {
504  auto &&map = bfn::unique_map_ptr_x64<int>(valid_virt, valid_virt + phys_offset, valid_phys, x64::page_size * 2UL - phys_offset, 0x0);
505 
506  this->expect_true(map);
507  this->expect_true(map.get() == make_ptr(valid_map));
508  this->expect_true(map.size() == x64::page_size * 2UL - phys_offset);
509 
510  this->expect_true(g_flushed[make_ptr(virt1)]);
511  this->expect_true(g_flushed[make_ptr(virt2)]);
512  this->expect_false(g_flushed[make_ptr(virt3)]);
513 
514  this->expect_true(g_mapped[virt1] == phys1);
515  this->expect_true(g_mapped[virt2] == phys2);
516  this->expect_true(g_mapped[virt3] == 0);
517 
518  map.reset();
519 
520  this->expect_true(g_unmapped[virt1]);
521  this->expect_true(g_unmapped[virt2]);
522  this->expect_false(g_unmapped[virt3]);
523 
524  this->expect_true(g_freed[make_ptr(virt1)]);
525  });
526 }
527 
528 void
529 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_not_present()
530 {
531  MockRepository mocks;
532  setup_mm(mocks);
533  setup_pt(mocks);
534 
535  g_pte_valid_present = false;
536  auto ___ = gsl::finally([&] { g_pte_valid_present = true; });
537 
538  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
539  {
541  });
542 }
543 
544 void
545 memory_manager_ut::test_unique_map_ptr_x64_virt_cr3_constructor_invalid_phys_addr()
546 {
547  MockRepository mocks;
548  setup_mm(mocks);
549  setup_pt(mocks);
550 
551  g_pte_valid_phys_addr = false;
552  auto ___ = gsl::finally([&] { g_pte_valid_phys_addr = true; });
553 
554  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
555  {
557  });
558 }
559 
560 void
561 memory_manager_ut::test_unique_map_ptr_x64_copy_constructor()
562 {
563  MockRepository mocks;
564  setup_mm(mocks);
565  setup_pt(mocks);
566 
567  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
568  {
570  auto &&map2 = bfn::unique_map_ptr_x64<int>(std::move(map1));
571 
572  this->expect_false(map1);
573  this->expect_true(map2);
574  this->expect_true(map1.get() == nullptr);
575  this->expect_true(map2.get() == make_ptr(valid_virt));
576  this->expect_true(map1.size() == 0);
577  this->expect_true(map2.size() == x64::page_size);
578  });
579 }
580 
581 void
582 memory_manager_ut::test_unique_map_ptr_x64_move_operator_valid()
583 {
584  MockRepository mocks;
585  setup_mm(mocks);
586  setup_pt(mocks);
587 
588  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
589  {
591  auto map2 = std::move(map1);
592 
593  this->expect_false(map1);
594  this->expect_true(map2);
595  this->expect_true(map1.get() == nullptr);
596  this->expect_true(map2.get() == make_ptr(valid_virt));
597  this->expect_true(map1.size() == 0);
598  this->expect_true(map2.size() == x64::page_size);
599  });
600 }
601 
602 void
603 memory_manager_ut::test_unique_map_ptr_x64_move_operator_invalid()
604 {
605  MockRepository mocks;
606  setup_mm(mocks);
607  setup_pt(mocks);
608 
609  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
610  {
612  map = nullptr;
613 
614  this->expect_false(map);
615  this->expect_true(map.get() == nullptr);
616  this->expect_true(map.size() == 0);
617  });
618 }
619 
620 struct foo_t
621 { int test; };
622 
623 void
624 memory_manager_ut::test_unique_map_ptr_x64_reference_operators()
625 {
626  // MockRepository mocks;
627  // setup_mm(mocks);
628  // setup_pt(mocks);
629 
630  // foo_t foo{10};
631 
632  // auto &&lower = make_uintptr(&foo) & (x64::page_size - 1);
633  // auto &&upper = make_uintptr(&foo) & ~(x64::page_size - 1);
634 
635  // RUN_UNITTEST_WITH_MOCKS(mocks, [&]
636  // {
637  // auto &&map = bfn::unique_map_ptr_x64<foo_t>(upper, valid_phys + lower, read_write);
638  // auto &&foo2 = *map;
639 
640  // this->expect_true(map);
641  // this->expect_true(map.get() == &foo);
642  // this->expect_true((*map).test == 10);
643  // this->expect_true(map->test == 10);
644  // this->expect_true(foo2.test == 10);
645  // });
646 }
647 
648 void
649 memory_manager_ut::test_unique_map_ptr_x64_release()
650 {
651  MockRepository mocks;
652  setup_mm(mocks);
653  setup_pt(mocks);
654 
655  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
656  {
658  auto &&ret = map.release();
659 
660  this->expect_false(map);
661  this->expect_true(map.get() == nullptr);
662  this->expect_true(map.size() == 0);
663  this->expect_true(std::get<0>(ret) == make_ptr(valid_virt));
664  this->expect_true(std::get<1>(ret) == x64::page_size);
665  this->expect_true(std::get<2>(ret) == x64::page_size);
666  });
667 }
668 
669 void
670 memory_manager_ut::test_unique_map_ptr_x64_reset()
671 {
672  MockRepository mocks;
673  setup_mm(mocks);
674  setup_pt(mocks);
675 
676  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
677  {
679  map.reset(make_ptr<int>(valid_virt), x64::page_size, x64::page_size);
680 
681  this->expect_true(g_unmapped[valid_virt]);
682  this->expect_true(g_freed[make_ptr(valid_virt)]);
683 
684  this->expect_true(map);
685  this->expect_true(map.get() == make_ptr(valid_virt));
686  this->expect_true(map.size() == x64::page_size);
687  });
688 }
689 
690 void
691 memory_manager_ut::test_unique_map_ptr_x64_swap()
692 {
693  MockRepository mocks;
694  setup_mm(mocks);
695  setup_pt(mocks);
696 
697  auto &&virt1 = valid_virt + (0 * x64::page_size);
698  auto &&virt2 = valid_virt + (1 * x64::page_size);
699 
700  auto &&phys1 = 0x1111000000000000UL;
701  auto &&phys2 = 0x1111000000001000UL;
702 
703  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
704  {
705  auto &&map1 = bfn::unique_map_ptr_x64<int>(virt1, phys1, read_write);
706  auto &&map2 = bfn::unique_map_ptr_x64<int>(virt2, phys2, read_write);
707 
708  map1.swap(map2);
709  this->expect_true(map1.get() == make_ptr(virt2));
710  this->expect_true(map2.get() == make_ptr(virt1));
711 
712  bfn::swap(map1, map2);
713  this->expect_true(map1.get() == make_ptr(virt1));
714  this->expect_true(map2.get() == make_ptr(virt2));
715  });
716 }
717 
718 void
719 memory_manager_ut::test_unique_map_ptr_x64_flush()
720 {
721  MockRepository mocks;
722  setup_mm(mocks);
723  setup_pt(mocks);
724 
725  auto &&phys_range_1 = std::make_pair(0x1111000000000010UL, x64::page_size * 2UL);
726  auto &&phys_range_2 = std::make_pair(0x1111000000004000UL, x64::page_size * 2UL);
727  auto &&phys_range_3 = std::make_pair(0x1111000000008000UL, x64::page_size * 2UL);
728  auto &&list = {phys_range_1, phys_range_2, phys_range_3};
729 
730  auto &&virt1 = valid_virt + (0 * x64::page_size);
731  auto &&virt2 = valid_virt + (1 * x64::page_size);
732  auto &&virt3 = valid_virt + (2 * x64::page_size);
733  auto &&virt4 = valid_virt + (3 * x64::page_size);
734  auto &&virt5 = valid_virt + (4 * x64::page_size);
735  auto &&virt6 = valid_virt + (5 * x64::page_size);
736 
737  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
738  {
740 
741  g_flushed.clear();
742  map.flush();
743 
744  this->expect_true(g_flushed[make_ptr(virt1)]);
745  this->expect_true(g_flushed[make_ptr(virt2)]);
746  this->expect_true(g_flushed[make_ptr(virt3)]);
747  this->expect_true(g_flushed[make_ptr(virt4)]);
748  this->expect_true(g_flushed[make_ptr(virt5)]);
749  this->expect_true(g_flushed[make_ptr(virt6)]);
750  });
751 }
752 
753 void
754 memory_manager_ut::test_unique_map_ptr_x64_cache_flush()
755 {
756  MockRepository mocks;
757  setup_mm(mocks);
758  setup_pt(mocks);
759 
760  auto &&phys_range_1 = std::make_pair(0x1111000000000010UL, x64::page_size * 2UL);
761  auto &&phys_range_2 = std::make_pair(0x1111000000004000UL, x64::page_size * 2UL);
762  auto &&phys_range_3 = std::make_pair(0x1111000000008000UL, x64::page_size * 2UL);
763  auto &&list = {phys_range_1, phys_range_2, phys_range_3};
764 
765  auto &&virt1 = valid_virt + (0 * x64::page_size);
766  auto &&virt2 = valid_virt + (1 * x64::page_size);
767  auto &&virt3 = valid_virt + (2 * x64::page_size);
768  auto &&virt4 = valid_virt + (3 * x64::page_size);
769  auto &&virt5 = valid_virt + (4 * x64::page_size);
770  auto &&virt6 = valid_virt + (5 * x64::page_size);
771 
772  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
773  {
775 
776  g_cache_flushed.clear();
777  map.cache_flush();
778 
779  this->expect_true(g_cache_flushed[make_ptr(virt1)]);
780  this->expect_true(g_cache_flushed[make_ptr(virt2)]);
781  this->expect_true(g_cache_flushed[make_ptr(virt3)]);
782  this->expect_true(g_cache_flushed[make_ptr(virt4)]);
783  this->expect_true(g_cache_flushed[make_ptr(virt5)]);
784  this->expect_true(g_cache_flushed[make_ptr(virt6)]);
785  });
786 }
787 
788 void
789 memory_manager_ut::test_unique_map_ptr_x64_comparison()
790 {
791  MockRepository mocks;
792  setup_mm(mocks);
793  setup_pt(mocks);
794 
795  auto &&virt1 = valid_virt + (0 * x64::page_size);
796  auto &&virt2 = valid_virt + (1 * x64::page_size);
797 
798  auto &&phys1 = 0x1111000000000000UL;
799  auto &&phys2 = 0x1111000000001000UL;
800 
801  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
802  {
803  auto &&map1 = bfn::unique_map_ptr_x64<int>(virt1, phys1, read_write);
804  auto &&map2 = bfn::unique_map_ptr_x64<int>(virt1, phys1, read_write);
805  auto &&map3 = bfn::unique_map_ptr_x64<int>(virt2, phys2, read_write);
806  auto &&map4 = bfn::unique_map_ptr_x64<int>(virt2, phys2, read_write);
807 
808  this->expect_true(map1 == map2);
809  this->expect_true(map3 == map4);
810  this->expect_true(map1 != map4);
811  this->expect_true(map3 != map2);
812  this->expect_true(map1 < map3);
813  this->expect_true(map3 > map1);
814  this->expect_true(map1 <= map2);
815  this->expect_true(map1 <= map3);
816  this->expect_true(map2 >= map1);
817  this->expect_true(map3 >= map1);
818  this->expect_false(map1 == nullptr);
819  this->expect_true(map1 != nullptr);
820  this->expect_false(nullptr == map1);
821  this->expect_true(nullptr != map1);
822  });
823 }
824 
825 void
826 memory_manager_ut::test_unique_map_ptr_x64_make_failure()
827 {
828  MockRepository mocks;
829  setup_mm(mocks);
830  setup_pt(mocks);
831 
832  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
833  {
834  g_freed.clear();
835  this->expect_exception([&]{ bfn::make_unique_map_x64<int>(nullptr); }, ""_ut_ffe);
836  this->expect_true(g_freed[dummy_pt.get()]);
837 
838  g_freed.clear();
839  this->expect_exception([&]{ bfn::make_unique_map_x64<int>(0UL); }, ""_ut_ffe);
840  this->expect_true(g_freed[dummy_pt.get()]);
841 
842  g_freed.clear();
843  this->expect_exception([&]{ bfn::make_unique_map_x64<int>({std::make_pair(0UL, 0UL)}); }, ""_ut_ffe);
844  this->expect_true(g_freed[dummy_pt.get()]);
845 
846  g_freed.clear();
847  this->expect_exception([&]{ bfn::make_unique_map_x64<int>(0UL, 0UL, 0UL, 0UL); }, ""_ut_ffe);
848  this->expect_true(g_freed[dummy_pt.get()]);
849  });
850 }
851 
852 void
853 memory_manager_ut::test_virt_to_phys_with_cr3_invalid()
854 {
855  this->expect_exception([&] { bfn::virt_to_phys_with_cr3(invalid_virt, valid_phys); }, ""_ut_ffe);
856  this->expect_exception([&] { bfn::virt_to_phys_with_cr3(valid_virt, invalid_phys); }, ""_ut_ffe);
857  this->expect_exception([&] { bfn::virt_to_phys_with_cr3(valid_virt, valid_phys + phys_offset); }, ""_ut_ffe);
858 }
859 
860 void
861 memory_manager_ut::test_virt_to_phys_with_cr3_1g()
862 {
863  MockRepository mocks;
864  setup_mm(mocks);
865  setup_pt(mocks);
866 
867  g_pte_large_page = true;
870  auto ___ = gsl::finally([&] { g_pte_large_page = false; });
871 
872  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
873  {
874  auto &&phys = bfn::virt_to_phys_with_cr3(valid_virt, valid_phys);
875  this->expect_true(phys == valid_phys);
876  });
877 }
878 
879 void
880 memory_manager_ut::test_virt_to_phys_with_cr3_2m()
881 {
882  MockRepository mocks;
883  setup_mm(mocks);
884  setup_pt(mocks);
885 
886  g_pte_large_page = true;
889  auto ___ = gsl::finally([&] { g_pte_large_page = false; });
890 
891  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
892  {
893  auto &&phys = bfn::virt_to_phys_with_cr3(valid_virt, valid_phys);
894  this->expect_true(phys == valid_phys);
895  });
896 }
897 
898 void
899 memory_manager_ut::test_virt_to_phys_with_cr3_4k()
900 {
901  MockRepository mocks;
902  setup_mm(mocks);
903  setup_pt(mocks);
904 
905  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
906  {
907  auto &&phys = bfn::virt_to_phys_with_cr3(valid_virt, valid_phys);
908  this->expect_true(phys == valid_phys);
909  });
910 }
virtual pointer alloc_map(size_type size) noexcept
#define expect_exception(f, e)
Definition: unittest.h:162
auto g_pte_valid_phys_addr
std::map< const void *, bool > g_cache_flushed
#define RUN_UNITTEST_WITH_MOCKS(a, b)
Definition: unittest.h:229
virtual size_type size() const noexcept
Definition: map_ptr_x64.h:714
auto g_pte_large_page_reset
constexpr const auto num_entries
constexpr const auto invalid_virt
constexpr const auto phys_offset
void __invlpg(const void *virt) noexcept
auto g_pte_large_page
constexpr const auto invalid_phys
#define expect_no_exception(f)
Definition: unittest.h:198
std::map< const void *, bool > g_freed
constexpr const auto valid_phys
constexpr const auto valid_virt
auto g_pte_large_page_count
void set_present(bool enabled) noexcept
constexpr const auto pt
Definition: mem_attr_x64.h:41
bool list() override
Definition: test.cpp:44
constexpr const auto size
void uint64_t uint64_t uint64_t *rdx noexcept
auto g_pte_valid_present
virtual void map_4k(integer_pointer virt, integer_pointer phys, attr_type attr)
constexpr const auto addr
Definition: cpuid_x64.h:80
virtual void unmap(integer_pointer virt) noexcept
constexpr const auto rw_wb
Definition: mem_attr_x64.h:47
auto make_ptr(const T ptr)
Definition: unittest.h:77
x64::memory_attr::attr_type read_write
uint64_t attr_type
Definition: mem_attr_x64.h:35
static memory_manager_x64 * instance() noexcept
decltype(memory_descriptor::type) attr_type
void swap(unique_map_ptr_x64 &other) noexcept
Definition: map_ptr_x64.h:809
constexpr page_table_x64::integer_pointer virt
auto release() noexcept
Definition: map_ptr_x64.h:733
void flush() noexcept
Definition: map_ptr_x64.h:826
constexpr const auto page_size
Definition: x64.h:35
uintptr_t virt_to_phys_with_cr3(uintptr_t virt, uintptr_t cr3)
Definition: map_ptr_x64.h:919
virtual pointer get() const noexcept
Definition: map_ptr_x64.h:693
void reset(pointer ptr=pointer(), size_type size=size_type(), size_type unaligned_size=size_type()) noexcept
Definition: map_ptr_x64.h:768
#define expect_false(a)
void __clflush(void *addr) noexcept
void cache_flush() noexcept
Definition: map_ptr_x64.h:842
virtual void free_map(pointer ptr) noexcept
std::map< memory_manager_x64::integer_pointer, bool > g_unmapped
void swap(unique_map_ptr_x64< T > &x, unique_map_ptr_x64< T > &y) noexcept
Definition: map_ptr_x64.h:876
constexpr const auto valid_map
std::map< const void *, bool > g_flushed
#define expect_true(a)
std::map< memory_manager_x64::integer_pointer, memory_manager_x64::integer_pointer > g_mapped
root_page_table_x64 * root_pt() noexcept