1// Copyright 2017 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <assert.h>
8#include <err.h>
9#include <hypervisor/guest_physical_address_space.h>
10#include <lib/unittest/unittest.h>
11#include <vm/pmm.h>
12#include <vm/vm.h>
13#include <vm/vm_address_region.h>
14#include <vm/vm_aspace.h>
15#include <vm/vm_object.h>
16#include <vm/vm_object_paged.h>
17
18static constexpr uint kMmuFlags =
19    ARCH_MMU_FLAG_PERM_READ |
20    ARCH_MMU_FLAG_PERM_WRITE |
21    ARCH_MMU_FLAG_PERM_EXECUTE;
22
23static bool hypervisor_supported() {
24#if ARCH_ARM64
25    if (arm64_get_boot_el() < 2) {
26        unittest_printf("Hypervisor not supported\n");
27        return false;
28    }
29#endif
30    return true;
31}
32
33static zx_status_t get_paddr(void* context, size_t offset, size_t index, paddr_t pa) {
34    *static_cast<paddr_t*>(context) = pa;
35    return ZX_OK;
36}
37
38static zx_status_t create_vmo(size_t vmo_size, fbl::RefPtr<VmObject>* vmo) {
39    return VmObjectPaged::Create(PMM_ALLOC_FLAG_ANY, 0u, vmo_size, vmo);
40}
41
42static zx_status_t commit_vmo(fbl::RefPtr<VmObject> vmo) {
43    uint64_t committed = 0;
44    zx_status_t status = vmo->CommitRange(0, vmo->size(), &committed);
45    if (status != ZX_OK) {
46        return status;
47    }
48    if (committed != vmo->size()) {
49        return ZX_ERR_BAD_STATE;
50    }
51    return ZX_OK;
52}
53
54static zx_status_t create_gpas(fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace>* gpas) {
55#if ARCH_ARM64
56    return hypervisor::GuestPhysicalAddressSpace::Create(1 /* vmid */, gpas);
57#elif ARCH_X86
58    return hypervisor::GuestPhysicalAddressSpace::Create(gpas);
59#endif
60}
61
62static zx_status_t create_mapping(fbl::RefPtr<VmAddressRegion> vmar, fbl::RefPtr<VmObject> vmo,
63                                  zx_gpaddr_t addr, uint mmu_flags = kMmuFlags) {
64    fbl::RefPtr<VmMapping> mapping;
65    return vmar->CreateVmMapping(addr, vmo->size(), 0 /* align_pow2 */, VMAR_FLAG_SPECIFIC, vmo,
66                                 0 /* vmo_offset */, mmu_flags, "vmo", &mapping);
67}
68
69static zx_status_t create_sub_vmar(fbl::RefPtr<VmAddressRegion> vmar, size_t offset, size_t size,
70                                   fbl::RefPtr<VmAddressRegion>* sub_vmar) {
71    return vmar->CreateSubVmar(offset, size, 0 /* align_pow2 */, vmar->flags() | VMAR_FLAG_SPECIFIC,
72                               "vmar", sub_vmar);
73}
74
75static bool guest_physical_address_space_unmap_range() {
76    BEGIN_TEST;
77
78    if (!hypervisor_supported()) {
79        return true;
80    }
81
82    // Setup.
83    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
84    zx_status_t status = create_gpas(&gpas);
85    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
86    fbl::RefPtr<VmObject> vmo;
87    status = create_vmo(PAGE_SIZE, &vmo);
88    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
89    status = create_mapping(gpas->RootVmar(), vmo, 0);
90    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
91
92    // Unmap page.
93    status = gpas->UnmapRange(0, PAGE_SIZE);
94    EXPECT_EQ(ZX_OK, status, "Failed to unmap page from GuestPhysicalAddressSpace\n");
95
96    // Verify GetPage for unmapped address fails.
97    zx_paddr_t gpas_paddr;
98    status = gpas->GetPage(0, &gpas_paddr);
99    EXPECT_EQ(ZX_ERR_NOT_FOUND, status,
100              "GetPage returning unexpected value for unmapped address\n");
101
102    END_TEST;
103}
104
105static bool guest_physical_address_space_unmap_range_outside_of_mapping() {
106    BEGIN_TEST;
107
108    if (!hypervisor_supported()) {
109        return true;
110    }
111
112    // Setup.
113    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
114    zx_status_t status = create_gpas(&gpas);
115    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
116    fbl::RefPtr<VmObject> vmo;
117    status = create_vmo(PAGE_SIZE, &vmo);
118    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
119    status = create_mapping(gpas->RootVmar(), vmo, 0);
120    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
121
122    // Unmap page.
123    status = gpas->UnmapRange(PAGE_SIZE * 8, PAGE_SIZE);
124    EXPECT_EQ(ZX_OK, status, "Failed to unmap page from GuestPhysicalAddressSpace\n");
125
126    END_TEST;
127}
128
129static bool guest_physical_address_space_unmap_range_multiple_mappings() {
130    BEGIN_TEST;
131
132    if (!hypervisor_supported()) {
133        return true;
134    }
135
136    // Setup.
137    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
138    zx_status_t status = create_gpas(&gpas);
139    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
140
141    fbl::RefPtr<VmObject> vmo1;
142    status = create_vmo(PAGE_SIZE * 2, &vmo1);
143    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
144    status = create_mapping(gpas->RootVmar(), vmo1, 0);
145    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
146
147    fbl::RefPtr<VmObject> vmo2;
148    status = create_vmo(PAGE_SIZE * 2, &vmo2);
149    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
150    status = create_mapping(gpas->RootVmar(), vmo2, PAGE_SIZE * 3);
151    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
152
153    // Unmap pages.
154    status = gpas->UnmapRange(PAGE_SIZE, PAGE_SIZE * 3);
155    EXPECT_EQ(ZX_OK, status, "Failed to multiple unmap pages from GuestPhysicalAddressSpace\n");
156
157    // Verify GetPage for unmapped addresses fails.
158    zx_paddr_t gpas_paddr = 0;
159    for (zx_gpaddr_t addr = PAGE_SIZE; addr < PAGE_SIZE * 4; addr += PAGE_SIZE) {
160        status = gpas->GetPage(addr, &gpas_paddr);
161        EXPECT_EQ(ZX_ERR_NOT_FOUND, status,
162                  "GetPage returning unexpected value for unmapped address\n");
163    }
164
165    // Verify GetPage for mapped addresses succeeds.
166    status = gpas->GetPage(0, &gpas_paddr);
167    EXPECT_EQ(ZX_OK, status, "Failed to read page from GuestPhysicalAddressSpace\n");
168    status = gpas->GetPage(PAGE_SIZE * 4, &gpas_paddr);
169    EXPECT_EQ(ZX_OK, status, "Failed to read page from GuestPhysicalAddressSpace\n");
170
171    END_TEST;
172}
173
174static bool guest_physical_address_space_unmap_range_sub_region() {
175    BEGIN_TEST;
176
177    if (!hypervisor_supported()) {
178        return true;
179    }
180
181    // Setup.
182    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
183    zx_status_t status = create_gpas(&gpas);
184    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
185    fbl::RefPtr<VmAddressRegion> root_vmar = gpas->RootVmar();
186    // To test partial unmapping within sub-VMAR:
187    // Sub-VMAR from [0, PAGE_SIZE * 2).
188    // Map within sub-VMAR from [PAGE_SIZE, PAGE_SIZE * 2).
189    fbl::RefPtr<VmAddressRegion> sub_vmar1;
190    status = create_sub_vmar(root_vmar, 0, PAGE_SIZE * 2, &sub_vmar1);
191    EXPECT_EQ(ZX_OK, status, "Failed to create sub-VMAR\n");
192    EXPECT_TRUE(sub_vmar1->has_parent(), "Sub-VMAR does not have a parent");
193    fbl::RefPtr<VmObject> vmo1;
194    status = create_vmo(PAGE_SIZE, &vmo1);
195    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
196    status = create_mapping(sub_vmar1, vmo1, PAGE_SIZE);
197    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
198    // To test destroying of sub-VMAR:
199    // Sub-VMAR from [PAGE_SIZE * 2, PAGE_SIZE * 3).
200    // Map within sub-VMAR from [0, PAGE_SIZE).
201    fbl::RefPtr<VmAddressRegion> sub_vmar2;
202    status = create_sub_vmar(root_vmar, PAGE_SIZE * 2, PAGE_SIZE, &sub_vmar2);
203    EXPECT_EQ(ZX_OK, status, "Failed to create sub-VMAR\n");
204    EXPECT_TRUE(sub_vmar2->has_parent(), "Sub-VMAR does not have a parent");
205    fbl::RefPtr<VmObject> vmo2;
206    status = create_vmo(PAGE_SIZE, &vmo2);
207    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
208    status = create_mapping(sub_vmar2, vmo2, 0);
209    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
210    // To test partial unmapping within root-VMAR:
211    // Map within root-VMAR from [PAGE_SIZE * 3, PAGE_SIZE * 5).
212    fbl::RefPtr<VmObject> vmo3;
213    status = create_vmo(PAGE_SIZE * 2, &vmo3);
214    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
215    status = create_mapping(root_vmar, vmo3, PAGE_SIZE * 3);
216    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
217
218    // Unmap pages from [PAGE_SIZE, PAGE_SIZE * 4).
219    status = gpas->UnmapRange(PAGE_SIZE, PAGE_SIZE * 3);
220    EXPECT_EQ(ZX_OK, status, "Failed to multiple unmap pages from GuestPhysicalAddressSpace\n");
221
222    // Verify GetPage for unmapped addresses fails.
223    zx_paddr_t gpas_paddr = 0;
224    for (zx_gpaddr_t addr = 0; addr < PAGE_SIZE * 4; addr += PAGE_SIZE) {
225        status = gpas->GetPage(addr, &gpas_paddr);
226        EXPECT_EQ(ZX_ERR_NOT_FOUND, status,
227                  "GetPage returning unexpected value for unmapped address\n");
228    }
229
230    // Verify GetPage for mapped addresses succeeds.
231    status = gpas->GetPage(PAGE_SIZE * 4, &gpas_paddr);
232    EXPECT_EQ(ZX_OK, status, "Failed to read page from GuestPhysicalAddressSpace\n");
233
234    // Verify that sub-VMARs still have a parent.
235    EXPECT_TRUE(sub_vmar1->has_parent(), "Sub-VMAR does not have a parent");
236    EXPECT_TRUE(sub_vmar2->has_parent(), "Sub-VMAR does not have a parent");
237
238    END_TEST;
239}
240
241static bool guest_physical_address_space_get_page() {
242    BEGIN_TEST;
243
244    if (!hypervisor_supported()) {
245        return true;
246    }
247
248    // Setup.
249    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
250    zx_status_t status = create_gpas(&gpas);
251    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
252    fbl::RefPtr<VmObject> vmo;
253    status = create_vmo(PAGE_SIZE, &vmo);
254    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
255    status = create_mapping(gpas->RootVmar(), vmo, 0);
256    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
257
258    // Commit VMO.
259    status = commit_vmo(vmo);
260    EXPECT_EQ(ZX_OK, status, "Failed to commit VMO\n");
261
262    // Read expected physical address from the VMO.
263    zx_paddr_t vmo_paddr = 0;
264    status = vmo->Lookup(0, PAGE_SIZE, 0, get_paddr, &vmo_paddr);
265    EXPECT_EQ(ZX_OK, status, "Failed to lookup physical address of VMO\n");
266    EXPECT_NE(0u, vmo_paddr, "Failed to lookup physical address of VMO\n");
267
268    // Read physical address from GPAS & compare with address read from VMO.
269    zx_paddr_t gpas_paddr = 0;
270    status = gpas->GetPage(0, &gpas_paddr);
271    EXPECT_EQ(ZX_OK, status, "Failed to read page from GuestPhysicalAddressSpace\n");
272    EXPECT_EQ(vmo_paddr, gpas_paddr,
273              "Incorrect physical address returned from GuestPhysicalAddressSpace::GetPage\n");
274
275    END_TEST;
276}
277
278static bool guest_physical_address_space_get_page_complex() {
279    BEGIN_TEST;
280
281    if (!hypervisor_supported()) {
282        return true;
283    }
284
285    // Test GetPage with a less trivial VMAR configuration.
286    //
287    //                  0 -->+--------+
288    //                       |  Root  |
289    //                       |  VMO   |
290    //      ROOT_VMO_SIZE -->---------+ +--------+
291    //                       |        | | Second |
292    // ROOT_VMO_SIZE +       |        | | VMO    |
293    //    SECOND_VMO_SIZE -->---------+ +--------+
294    //                       |  Root  | | Shadow |
295    //                       |  VMAR  | | VMAR   |
296    //                        ~~~~~~~~   ~~~~~~~~
297    //
298    // The 'Root VMO/VMAR' is the default configuration when initializing
299    // GuestPhysicalAddressSpace with a VMO size of 'PAGE_SIZE'. This test
300    // allocates a second VMAR and VMO and attaches them both into the 'Root
301    // VMAR' to ensure we correctly locate addresses in these structures.
302    const uint ROOT_VMO_SIZE = PAGE_SIZE;
303    const uint SECOND_VMO_SIZE = PAGE_SIZE;
304
305    // Setup.
306    fbl::RefPtr<VmObject> vmo1;
307    zx_status_t status = create_vmo(ROOT_VMO_SIZE, &vmo1);
308    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
309    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
310    status = create_gpas(&gpas);
311    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
312    fbl::RefPtr<VmAddressRegion> root_vmar = gpas->RootVmar();
313    status = create_mapping(root_vmar, vmo1, 0);
314    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
315
316    // Commit first VMO.
317    status = commit_vmo(vmo1);
318    EXPECT_EQ(ZX_OK, status, "Failed to commit VMO\n");
319
320    // Allocate second VMAR, offset one page into the root.
321    fbl::RefPtr<VmAddressRegion> shadow_vmar;
322    status = create_sub_vmar(root_vmar, ROOT_VMO_SIZE, root_vmar->size() - ROOT_VMO_SIZE,
323                             &shadow_vmar);
324    EXPECT_EQ(ZX_OK, status, "Failed to create shadow VMAR\n");
325
326    // Allocate second VMO; we'll map the original VMO on top of this one.
327    fbl::RefPtr<VmObject> vmo2;
328    status = create_vmo(SECOND_VMO_SIZE, &vmo2);
329    EXPECT_EQ(ZX_OK, status, "Failed allocate second VMO\n");
330
331    // Commit second VMO.
332    status = commit_vmo(vmo2);
333    EXPECT_EQ(ZX_OK, status, "Failed to commit second VMO\n");
334
335    // Map second VMO into second VMAR.
336    status = create_mapping(shadow_vmar, vmo2, 0);
337    EXPECT_EQ(ZX_OK, status, "Failed to map vmo into shadow vmar\n");
338
339    // Read expected physical address from the VMO.
340    zx_paddr_t vmo_paddr = 0;
341    status = vmo2->Lookup(0, PAGE_SIZE, 0, get_paddr, &vmo_paddr);
342    EXPECT_EQ(ZX_OK, status, "Failed to lookup physical address of VMO\n");
343    EXPECT_NE(0u, vmo_paddr, "Failed to lookup physical address of VMO\n");
344
345    // Read physical address from GPAS.
346    zx_paddr_t gpas_paddr = 0;
347    status = gpas->GetPage(ROOT_VMO_SIZE, &gpas_paddr);
348    EXPECT_EQ(ZX_OK, status, "Failed to read page from GuestPhysicalAddressSpace\n");
349    EXPECT_EQ(vmo_paddr, gpas_paddr,
350              "Incorrect physical address returned from GuestPhysicalAddressSpace::GetPage\n");
351    END_TEST;
352}
353
354static bool guest_physical_address_space_get_page_not_present() {
355    BEGIN_TEST;
356
357    if (!hypervisor_supported()) {
358        return true;
359    }
360
361    // Setup.
362    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
363    zx_status_t status = create_gpas(&gpas);
364    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
365    fbl::RefPtr<VmObject> vmo;
366    status = create_vmo(PAGE_SIZE, &vmo);
367    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
368    status = create_mapping(gpas->RootVmar(), vmo, 0);
369    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
370
371    // Commit VMO.
372    status = commit_vmo(vmo);
373    EXPECT_EQ(ZX_OK, status, "Failed to commit VMO\n");
374
375    // Query unmapped address.
376    zx_paddr_t gpas_paddr = 0;
377    status = gpas->GetPage(UINTPTR_MAX, &gpas_paddr);
378    EXPECT_EQ(ZX_ERR_NOT_FOUND, status,
379              "GetPage returning unexpected value for unmapped address\n");
380
381    END_TEST;
382}
383
384static bool guest_physical_address_space_page_fault() {
385    BEGIN_TEST;
386
387    if (!hypervisor_supported()) {
388        return true;
389    }
390
391    // Setup.
392    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
393    zx_status_t status = create_gpas(&gpas);
394    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
395    fbl::RefPtr<VmObject> vmo;
396    status = create_vmo(PAGE_SIZE, &vmo);
397    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
398    status = create_mapping(gpas->RootVmar(), vmo, 0);
399    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
400    status = create_mapping(gpas->RootVmar(), vmo, PAGE_SIZE, ARCH_MMU_FLAG_PERM_READ);
401    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
402    status = create_mapping(gpas->RootVmar(), vmo, PAGE_SIZE * 2,
403                            ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE);
404    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
405    status = create_mapping(gpas->RootVmar(), vmo, PAGE_SIZE * 3,
406                            ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_EXECUTE);
407    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
408
409    // Fault in each page.
410    for (zx_gpaddr_t addr = 0; addr < PAGE_SIZE * 4; addr += PAGE_SIZE) {
411      status = gpas->PageFault(addr);
412      EXPECT_EQ(ZX_OK, status, "Failed to fault page\n");
413    }
414
415    END_TEST;
416}
417
418static bool guest_physical_address_space_map_interrupt_controller() {
419    BEGIN_TEST;
420
421    if (!hypervisor_supported()) {
422        return true;
423    }
424
425    // Setup.
426    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
427    zx_status_t status = create_gpas(&gpas);
428    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
429    fbl::RefPtr<VmObject> vmo;
430    status = create_vmo(PAGE_SIZE, &vmo);
431    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
432    status = create_mapping(gpas->RootVmar(), vmo, 0);
433    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
434
435    // Allocate a page to use as the APIC page.
436    paddr_t paddr = 0;
437    vm_page* vm_page;
438    status = pmm_alloc_page(0, &vm_page, &paddr);
439    EXPECT_EQ(ZX_OK, status, "Unable to allocate a page\n");
440
441    // Map APIC page in an arbitrary location.
442    const vaddr_t APIC_ADDRESS = 0xffff0000;
443    status = gpas->MapInterruptController(APIC_ADDRESS, paddr, PAGE_SIZE);
444    EXPECT_EQ(ZX_OK, status, "Failed to map APIC page\n");
445
446    // Cleanup
447    pmm_free_page(vm_page);
448    END_TEST;
449}
450
451static bool guest_physical_address_space_uncached() {
452    BEGIN_TEST;
453
454    if (!hypervisor_supported()) {
455        return true;
456    }
457
458    // Setup.
459    fbl::RefPtr<VmObject> vmo;
460    zx_status_t status = create_vmo(PAGE_SIZE, &vmo);
461    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
462    status = vmo->SetMappingCachePolicy(ZX_CACHE_POLICY_UNCACHED);
463    EXPECT_EQ(ZX_OK, status, "Failed to set cache policy\n");
464
465    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
466    status = create_gpas(&gpas);
467    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
468    status = create_mapping(gpas->RootVmar(), vmo, 0);
469    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
470
471    END_TEST;
472}
473
474static bool guest_physical_address_space_uncached_device() {
475    BEGIN_TEST;
476
477    if (!hypervisor_supported()) {
478        return true;
479    }
480
481    // Setup.
482    fbl::RefPtr<VmObject> vmo;
483    zx_status_t status = create_vmo(PAGE_SIZE, &vmo);
484    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
485    status = vmo->SetMappingCachePolicy(ZX_CACHE_POLICY_UNCACHED_DEVICE);
486    EXPECT_EQ(ZX_OK, status, "Failed to set cache policy\n");
487
488    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
489    status = create_gpas(&gpas);
490    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
491    status = create_mapping(gpas->RootVmar(), vmo, 0);
492    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
493
494    END_TEST;
495}
496
497static bool guest_physical_address_space_write_combining() {
498    BEGIN_TEST;
499
500    if (!hypervisor_supported()) {
501        return true;
502    }
503
504    // Setup.
505    fbl::RefPtr<VmObject> vmo;
506    zx_status_t status = create_vmo(PAGE_SIZE, &vmo);
507    EXPECT_EQ(ZX_OK, status, "Failed to create VMO\n");
508    status = vmo->SetMappingCachePolicy(ZX_CACHE_POLICY_WRITE_COMBINING);
509    EXPECT_EQ(ZX_OK, status, "Failed to set cache policy\n");
510
511    fbl::unique_ptr<hypervisor::GuestPhysicalAddressSpace> gpas;
512    status = create_gpas(&gpas);
513    EXPECT_EQ(ZX_OK, status, "Failed to create GuestPhysicalAddressSpace\n");
514    status = create_mapping(gpas->RootVmar(), vmo, 0);
515    EXPECT_EQ(ZX_OK, status, "Failed to create mapping\n");
516
517    END_TEST;
518}
519
520// Use the function name as the test name
521#define HYPERVISOR_UNITTEST(fname) UNITTEST(#fname, fname)
522
523UNITTEST_START_TESTCASE(hypervisor)
524HYPERVISOR_UNITTEST(guest_physical_address_space_unmap_range)
525HYPERVISOR_UNITTEST(guest_physical_address_space_unmap_range_outside_of_mapping)
526HYPERVISOR_UNITTEST(guest_physical_address_space_unmap_range_multiple_mappings)
527HYPERVISOR_UNITTEST(guest_physical_address_space_unmap_range_sub_region)
528HYPERVISOR_UNITTEST(guest_physical_address_space_get_page)
529HYPERVISOR_UNITTEST(guest_physical_address_space_get_page_complex)
530HYPERVISOR_UNITTEST(guest_physical_address_space_get_page_not_present)
531HYPERVISOR_UNITTEST(guest_physical_address_space_page_fault)
532HYPERVISOR_UNITTEST(guest_physical_address_space_map_interrupt_controller)
533HYPERVISOR_UNITTEST(guest_physical_address_space_uncached)
534HYPERVISOR_UNITTEST(guest_physical_address_space_uncached_device)
535HYPERVISOR_UNITTEST(guest_physical_address_space_write_combining)
536UNITTEST_END_TESTCASE(hypervisor, "hypervisor", "Hypervisor unit tests.");
537