Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions tests/unit/mmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <tinykvm/machine.hpp>
extern std::vector<uint8_t> 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<std::string> env{
"LC_TYPE=C", "LC_ALL=C", "USER=root"};

Expand All @@ -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 <stdio.h>
#include <sys/mman.h>
Expand All @@ -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);
Expand All @@ -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);
}
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down
Loading