memmap.cc 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include "memmap.hh"
  2. #include <numeric>
  3. mem_slot::mem_slot(mem_map& map, uint64_t gpa, uint64_t size, void* hva)
  4. : _map(map)
  5. , _slot(map._free_slots.top())
  6. , _gpa(gpa)
  7. , _size(size)
  8. , _hva(hva)
  9. , _dirty_log_enabled(false)
  10. , _log()
  11. {
  12. map._free_slots.pop();
  13. if (_size) {
  14. update();
  15. }
  16. }
  17. mem_slot::~mem_slot()
  18. {
  19. if (!_size) {
  20. return;
  21. }
  22. _size = 0;
  23. try {
  24. update();
  25. _map._free_slots.push(_slot);
  26. } catch (...) {
  27. // can't do much if we can't undo slot registration - leak the slot
  28. }
  29. }
  30. void mem_slot::set_dirty_logging(bool enabled)
  31. {
  32. if (_dirty_log_enabled != enabled) {
  33. _dirty_log_enabled = enabled;
  34. if (enabled) {
  35. int logsize = ((_size >> 12) + bits_per_word - 1) / bits_per_word;
  36. _log.resize(logsize);
  37. } else {
  38. _log.resize(0);
  39. }
  40. if (_size) {
  41. update();
  42. }
  43. }
  44. }
  45. void mem_slot::update()
  46. {
  47. uint32_t flags = 0;
  48. if (_dirty_log_enabled) {
  49. flags |= KVM_MEM_LOG_DIRTY_PAGES;
  50. }
  51. _map._vm.set_memory_region(_slot, _hva, _gpa, _size, flags);
  52. }
  53. bool mem_slot::dirty_logging() const
  54. {
  55. return _dirty_log_enabled;
  56. }
  57. static inline int hweight(uint64_t w)
  58. {
  59. w -= (w >> 1) & 0x5555555555555555;
  60. w = (w & 0x3333333333333333) + ((w >> 2) & 0x3333333333333333);
  61. w = (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0f;
  62. return (w * 0x0101010101010101) >> 56;
  63. }
  64. int mem_slot::update_dirty_log()
  65. {
  66. _map._vm.get_dirty_log(_slot, &_log[0]);
  67. return std::accumulate(_log.begin(), _log.end(), 0,
  68. [] (int prev, ulong elem) -> int {
  69. return prev + hweight(elem);
  70. });
  71. }
  72. bool mem_slot::is_dirty(uint64_t gpa) const
  73. {
  74. uint64_t pagenr = (gpa - _gpa) >> 12;
  75. ulong wordnr = pagenr / bits_per_word;
  76. ulong bit = 1ULL << (pagenr % bits_per_word);
  77. return _log[wordnr] & bit;
  78. }
  79. mem_map::mem_map(kvm::vm& vm)
  80. : _vm(vm)
  81. {
  82. int nr_slots = vm.sys().get_extension_int(KVM_CAP_NR_MEMSLOTS);
  83. for (int i = 0; i < nr_slots; ++i) {
  84. _free_slots.push(i);
  85. }
  86. }