diff --git a/tests/unit/mmap.cpp b/tests/unit/mmap.cpp index 8d995a3..05ac9a6 100644 --- a/tests/unit/mmap.cpp +++ b/tests/unit/mmap.cpp @@ -2,7 +2,8 @@ #include extern std::vector build_and_load(const std::string &code); -static const uint64_t MAX_MEMORY = 8ul << 20; /* 8MB */ +/* mmap tests touch mapped pages from guest code; keep enough physical headroom. */ +static const uint64_t MAX_MEMORY = 64ul << 20; /* 64MB */ static const std::vector env{ "LC_TYPE=C", "LC_ALL=C", "USER=root"}; @@ -14,6 +15,7 @@ TEST_CASE("Initialize KVM", "[Initialize]") TEST_CASE("Basic mmap and munmap", "[MMAP]") { + constexpr size_t map_size = 0x1000; const auto binary = build_and_load(R"M( #include #include @@ -26,6 +28,11 @@ void* do_mmap(size_t size) { //fflush(stdout); return res; } +int touch_byte(void* addr, int value) { + volatile unsigned char* p = (volatile unsigned char*)addr; + p[0] = (unsigned char)value; + return (int)p[0]; +} int do_munmap(void* addr, size_t size) { int res = munmap(addr, size); //printf("munmap(%p, %zu) = %d\n", addr, size, res); @@ -43,31 +50,30 @@ int do_munmap(void* addr, size_t size) { for (int i = 0; i < 10; ++i) { // Make a single mmap call - machine.vmcall("do_mmap", 0x1000000); + machine.vmcall("do_mmap", map_size); const uint64_t guest_mmap_addr = machine.return_value(); REQUIRE(guest_mmap_addr >= machine.mmap_start()); REQUIRE(guest_mmap_addr != ~0UL); REQUIRE((guest_mmap_addr & 0xFFF) == 0); - // Since this is a single page, we can use writable_memview - // on a page (which must be sequential in memory) - auto mmap_page = machine.writable_memview(guest_mmap_addr, 0x1000); - REQUIRE(!mmap_page.empty()); - // We can memset the entire page - std::memset(mmap_page.data(), 0xFF, mmap_page.size()); + // Validate mapping by writing/reading from guest code. + machine.vmcall("touch_byte", guest_mmap_addr, 0x7F); + REQUIRE(machine.return_value() == 0x7F); - // Unmapping and then mapping again should return the same address - machine.vmcall("do_munmap", guest_mmap_addr, 0x1000000); + // Unmap and map again; address reuse is not guaranteed unless MAP_FIXED is used. + machine.vmcall("do_munmap", guest_mmap_addr, map_size); REQUIRE(machine.return_value() == 0); - machine.vmcall("do_mmap", 0x1000000); + machine.vmcall("do_mmap", map_size); const uint64_t new_guest_mmap_addr = machine.return_value(); - REQUIRE(new_guest_mmap_addr == guest_mmap_addr); - // Check that the address is still valid - auto mmap_page_after_unmap = machine.writable_memview(new_guest_mmap_addr, 0x1000); - REQUIRE(!mmap_page_after_unmap.empty()); + REQUIRE(new_guest_mmap_addr >= machine.mmap_start()); + REQUIRE(new_guest_mmap_addr != ~0UL); + REQUIRE((new_guest_mmap_addr & 0xFFF) == 0); + // Check that remapped memory is writable/readable from guest code. + machine.vmcall("touch_byte", new_guest_mmap_addr, 0x5A); + REQUIRE(machine.return_value() == 0x5A); // Unmap the page - machine.vmcall("do_munmap", new_guest_mmap_addr, 0x1000000); + machine.vmcall("do_munmap", new_guest_mmap_addr, map_size); } } @@ -84,7 +90,7 @@ void* do_mmap(size_t size) { return res; } void* do_fixed_mmap(void* m, size_t size) { - void *res = mmap(m, size, 0x7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + void *res = mmap(m, size, 0x7, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); return res; } int do_munmap(void* addr, size_t size) { @@ -186,6 +192,7 @@ int do_munmap(void* addr, size_t size) { const auto& m = mappings[index]; machine.vmcall("do_fixed_mmap", m.addr, m.size); const uint64_t guest_mmap_addr = machine.return_value(); + REQUIRE(guest_mmap_addr != ~0UL); REQUIRE(guest_mmap_addr == m.addr); } else if (do_munmap_lower_half || do_munmap_upper_half)