Region.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include <Kernel/Process.h>
  2. #include <Kernel/Thread.h>
  3. #include <Kernel/VM/MemoryManager.h>
  4. #include <Kernel/VM/Region.h>
  5. #include <Kernel/VM/VMObject.h>
  6. Region::Region(const Range& range, const String& name, byte access, bool cow)
  7. : m_range(range)
  8. , m_vmo(VMObject::create_anonymous(size()))
  9. , m_name(name)
  10. , m_access(access)
  11. , m_cow_map(Bitmap::create(m_vmo->page_count(), cow))
  12. {
  13. m_vmo->set_name(m_name);
  14. MM.register_region(*this);
  15. }
  16. Region::Region(const Range& range, RetainPtr<Inode>&& inode, const String& name, byte access)
  17. : m_range(range)
  18. , m_vmo(VMObject::create_file_backed(move(inode)))
  19. , m_name(name)
  20. , m_access(access)
  21. , m_cow_map(Bitmap::create(m_vmo->page_count()))
  22. {
  23. MM.register_region(*this);
  24. }
  25. Region::Region(const Range& range, Retained<VMObject>&& vmo, size_t offset_in_vmo, const String& name, byte access, bool cow)
  26. : m_range(range)
  27. , m_offset_in_vmo(offset_in_vmo)
  28. , m_vmo(move(vmo))
  29. , m_name(name)
  30. , m_access(access)
  31. , m_cow_map(Bitmap::create(m_vmo->page_count(), cow))
  32. {
  33. MM.register_region(*this);
  34. }
  35. Region::~Region()
  36. {
  37. if (m_page_directory) {
  38. MM.unmap_region(*this);
  39. ASSERT(!m_page_directory);
  40. }
  41. MM.unregister_region(*this);
  42. }
  43. bool Region::page_in()
  44. {
  45. ASSERT(m_page_directory);
  46. ASSERT(!vmo().is_anonymous());
  47. ASSERT(vmo().inode());
  48. #ifdef MM_DEBUG
  49. dbgprintf("MM: page_in %u pages\n", page_count());
  50. #endif
  51. for (size_t i = 0; i < page_count(); ++i) {
  52. auto& vmo_page = vmo().physical_pages()[first_page_index() + i];
  53. if (vmo_page.is_null()) {
  54. bool success = MM.page_in_from_inode(*this, i);
  55. if (!success)
  56. return false;
  57. continue;
  58. }
  59. MM.remap_region_page(*this, i, true);
  60. }
  61. return true;
  62. }
  63. Retained<Region> Region::clone()
  64. {
  65. ASSERT(current);
  66. if (m_shared || (is_readable() && !is_writable())) {
  67. #ifdef MM_DEBUG
  68. dbgprintf("%s<%u> Region::clone(): sharing %s (L%x)\n",
  69. current->process().name().characters(),
  70. current->pid(),
  71. m_name.characters(),
  72. vaddr().get());
  73. #endif
  74. // Create a new region backed by the same VMObject.
  75. return adopt(*new Region(m_range, m_vmo.copy_ref(), m_offset_in_vmo, String(m_name), m_access));
  76. }
  77. #ifdef MM_DEBUG
  78. dbgprintf("%s<%u> Region::clone(): cowing %s (L%x)\n",
  79. current->process().name().characters(),
  80. current->pid(),
  81. m_name.characters(),
  82. vaddr().get());
  83. #endif
  84. // Set up a COW region. The parent (this) region becomes COW as well!
  85. m_cow_map.fill(true);
  86. MM.remap_region(current->process().page_directory(), *this);
  87. return adopt(*new Region(m_range, m_vmo->clone(), m_offset_in_vmo, String(m_name), m_access, true));
  88. }
  89. int Region::commit()
  90. {
  91. InterruptDisabler disabler;
  92. #ifdef MM_DEBUG
  93. dbgprintf("MM: commit %u pages in Region %p (VMO=%p) at L%x\n", vmo().page_count(), this, &vmo(), vaddr().get());
  94. #endif
  95. for (size_t i = first_page_index(); i <= last_page_index(); ++i) {
  96. if (!vmo().physical_pages()[i].is_null())
  97. continue;
  98. auto physical_page = MM.allocate_user_physical_page(MemoryManager::ShouldZeroFill::Yes);
  99. if (!physical_page) {
  100. kprintf("MM: commit was unable to allocate a physical page\n");
  101. return -ENOMEM;
  102. }
  103. vmo().physical_pages()[i] = move(physical_page);
  104. MM.remap_region_page(*this, i, true);
  105. }
  106. return 0;
  107. }
  108. size_t Region::amount_resident() const
  109. {
  110. size_t bytes = 0;
  111. for (size_t i = 0; i < page_count(); ++i) {
  112. if (m_vmo->physical_pages()[first_page_index() + i])
  113. bytes += PAGE_SIZE;
  114. }
  115. return bytes;
  116. }
  117. size_t Region::amount_shared() const
  118. {
  119. size_t bytes = 0;
  120. for (size_t i = 0; i < page_count(); ++i) {
  121. auto& physical_page = m_vmo->physical_pages()[first_page_index() + i];
  122. if (physical_page && physical_page->retain_count() > 1)
  123. bytes += PAGE_SIZE;
  124. }
  125. return bytes;
  126. }