Spaces:
Runtime error
Runtime error
| mem_slot::mem_slot(mem_map& map, uint64_t gpa, uint64_t size, void* hva) | |
| : _map(map) | |
| , _slot(map._free_slots.top()) | |
| , _gpa(gpa) | |
| , _size(size) | |
| , _hva(hva) | |
| , _dirty_log_enabled(false) | |
| , _log() | |
| { | |
| map._free_slots.pop(); | |
| if (_size) { | |
| update(); | |
| } | |
| } | |
| mem_slot::~mem_slot() | |
| { | |
| if (!_size) { | |
| return; | |
| } | |
| _size = 0; | |
| try { | |
| update(); | |
| _map._free_slots.push(_slot); | |
| } catch (...) { | |
| // can't do much if we can't undo slot registration - leak the slot | |
| } | |
| } | |
| void mem_slot::set_dirty_logging(bool enabled) | |
| { | |
| if (_dirty_log_enabled != enabled) { | |
| _dirty_log_enabled = enabled; | |
| if (enabled) { | |
| int logsize = ((_size >> 12) + bits_per_word - 1) / bits_per_word; | |
| _log.resize(logsize); | |
| } else { | |
| _log.resize(0); | |
| } | |
| if (_size) { | |
| update(); | |
| } | |
| } | |
| } | |
| void mem_slot::update() | |
| { | |
| uint32_t flags = 0; | |
| if (_dirty_log_enabled) { | |
| flags |= KVM_MEM_LOG_DIRTY_PAGES; | |
| } | |
| _map._vm.set_memory_region(_slot, _hva, _gpa, _size, flags); | |
| } | |
| bool mem_slot::dirty_logging() const | |
| { | |
| return _dirty_log_enabled; | |
| } | |
| static inline int hweight(uint64_t w) | |
| { | |
| w -= (w >> 1) & 0x5555555555555555; | |
| w = (w & 0x3333333333333333) + ((w >> 2) & 0x3333333333333333); | |
| w = (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0f; | |
| return (w * 0x0101010101010101) >> 56; | |
| } | |
| int mem_slot::update_dirty_log() | |
| { | |
| _map._vm.get_dirty_log(_slot, &_log[0]); | |
| return std::accumulate(_log.begin(), _log.end(), 0, | |
| [] (int prev, ulong elem) -> int { | |
| return prev + hweight(elem); | |
| }); | |
| } | |
| bool mem_slot::is_dirty(uint64_t gpa) const | |
| { | |
| uint64_t pagenr = (gpa - _gpa) >> 12; | |
| ulong wordnr = pagenr / bits_per_word; | |
| ulong bit = 1ULL << (pagenr % bits_per_word); | |
| return _log[wordnr] & bit; | |
| } | |
| mem_map::mem_map(kvm::vm& vm) | |
| : _vm(vm) | |
| { | |
| int nr_slots = vm.sys().get_extension_int(KVM_CAP_NR_MEMSLOTS); | |
| for (int i = 0; i < nr_slots; ++i) { | |
| _free_slots.push(i); | |
| } | |
| } | |