diff --git a/lib/tinykvm/amd64/paging.cpp b/lib/tinykvm/amd64/paging.cpp index d8f9008..70f93c1 100644 --- a/lib/tinykvm/amd64/paging.cpp +++ b/lib/tinykvm/amd64/paging.cpp @@ -531,13 +531,13 @@ void foreach_page_makecow(vMemory& mem, uint64_t kernel_end, uint64_t shared_mem entry &= ~PDE64_ACCESSED; }); } -std::vector get_accessed_pages(const vMemory& memory) +std::vector> get_accessed_pages(const vMemory& memory) { - std::vector accessed_pages; + std::vector> accessed_pages; foreach_page(memory, - [&accessed_pages] (uint64_t addr, uint64_t& entry, size_t /*size*/) { - if ((entry & (PDE64_ACCESSED | PDE64_PRESENT)) == (PDE64_ACCESSED | PDE64_PRESENT)) { - accessed_pages.push_back(addr & PDE64_ADDR_MASK); + [&accessed_pages] (uint64_t addr, uint64_t& entry, size_t size) { + if ((entry & (PDE64_PS | PDE64_ACCESSED | PDE64_PRESENT)) == (PDE64_PS | PDE64_ACCESSED | PDE64_PRESENT)) { + accessed_pages.push_back({addr & PDE64_ADDR_MASK, size}); } }, false); return accessed_pages; diff --git a/lib/tinykvm/amd64/paging.hpp b/lib/tinykvm/amd64/paging.hpp index 8593fdc..d399892 100644 --- a/lib/tinykvm/amd64/paging.hpp +++ b/lib/tinykvm/amd64/paging.hpp @@ -14,7 +14,7 @@ using foreach_page_t = std::function; extern void foreach_page(vMemory&, foreach_page_t callback, bool skip_oob_addresses = true); extern void foreach_page(const vMemory&, foreach_page_t callback, bool skip_oob_addresses = true); extern void foreach_page_makecow(vMemory&, uint64_t kernel_end, uint64_t shared_memory_boundary); -extern std::vector get_accessed_pages(const vMemory& memory); +extern std::vector> get_accessed_pages(const vMemory& memory); extern void page_at(vMemory&, uint64_t addr, foreach_page_t, bool ignore_missing = false); struct WritablePage { diff --git a/lib/tinykvm/machine.hpp b/lib/tinykvm/machine.hpp index 3e0a2cb..2831926 100644 --- a/lib/tinykvm/machine.hpp +++ b/lib/tinykvm/machine.hpp @@ -245,7 +245,7 @@ struct Machine void set_main_memory_writable(bool v) { memory.main_memory_writes = v; } bool is_forked() const noexcept { return m_forked; } bool uses_cow_memory() const noexcept { return m_forked || m_prepped; } - std::vector get_accessed_pages() const; + std::vector> get_accessed_pages() const; /* Remote VM through address space merging */ void remote_connect(Machine& other, bool connect_now = false); @@ -299,7 +299,7 @@ struct Machine /* Store non-memory VM state to the already existing cold start state area in memory. Any failure will throw an exception. The memory must have been pre-allocated. */ - void save_snapshot_state_now(const std::vector& populate_pages = {}) const; + void save_snapshot_state_now(const std::vector>& populate_pages = {}) const; /* Check if the VM was loaded from a snapshot state. */ bool has_snapshot_state() const noexcept { return m_loaded_from_snapshot; } /* Get pointer to user area in snapshot state memory, or nullptr diff --git a/lib/tinykvm/machine_state.cpp b/lib/tinykvm/machine_state.cpp index d3f6161..7509d46 100644 --- a/lib/tinykvm/machine_state.cpp +++ b/lib/tinykvm/machine_state.cpp @@ -208,7 +208,7 @@ bool Machine::load_snapshot_state() } return true; } -void Machine::save_snapshot_state_now(const std::vector& populate_pages) const +void Machine::save_snapshot_state_now(const std::vector>& populate_pages) const { if (this->is_forked()) { throw std::runtime_error("Cannot save snapshot state of a forked VM"); @@ -242,12 +242,12 @@ void Machine::save_snapshot_state_now(const std::vector& populate_page if (!populate_pages.empty()) { uint64_t current_begin = 0; uint64_t current_end = 0; - for (uint64_t page_addr : populate_pages) { + for (const auto& [page_addr, size] : populate_pages) { if (page_addr >= MemoryBanks::ARENA_BASE_ADDRESS || page_addr < kernel_end_address()) continue; // Merge contiguous ranges if (current_end == page_addr) { - current_end += vMemory::PageSize(); + current_end += size; continue; } // Store previous range @@ -259,7 +259,7 @@ void Machine::save_snapshot_state_now(const std::vector& populate_page } // Start new range current_begin = page_addr; - current_end = page_addr; + current_end = page_addr + size; } // Store last range if (current_end != current_begin) { diff --git a/lib/tinykvm/memory.cpp b/lib/tinykvm/memory.cpp index 630a973..a18c1a3 100644 --- a/lib/tinykvm/memory.cpp +++ b/lib/tinykvm/memory.cpp @@ -397,9 +397,15 @@ vMemory::AllocationResult if (filename.empty()) { throw std::runtime_error("No VM snapshot file specified"); } - const int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); + int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC); if (fd < 0) { - throw std::runtime_error("Failed to open VM snapshot file: " + filename); + if (errno != ENOENT) { + throw std::runtime_error("Failed to open VM snapshot file: " + filename); + } + fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); + if (fd < 0) { + throw std::runtime_error("Failed to create VM snapshot file: " + filename); + } } struct stat st; if (fstat(fd, &st) != 0) { @@ -512,7 +518,7 @@ char* vMemory::get_userpage_at(uint64_t addr) const #endif } -std::vector Machine::get_accessed_pages() const +std::vector> Machine::get_accessed_pages() const { return tinykvm::get_accessed_pages(this->main_memory()); }