AddressSpace.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <Kernel/Locking/Spinlock.h>
  8. #include <Kernel/Memory/AddressSpace.h>
  9. #include <Kernel/Memory/AnonymousVMObject.h>
  10. #include <Kernel/Memory/InodeVMObject.h>
  11. #include <Kernel/Memory/MemoryManager.h>
  12. #include <Kernel/PerformanceManager.h>
  13. #include <Kernel/Process.h>
  14. namespace Kernel::Memory {
  15. OwnPtr<AddressSpace> AddressSpace::try_create(AddressSpace const* parent)
  16. {
  17. auto page_directory = PageDirectory::try_create_for_userspace(parent ? &parent->page_directory().range_allocator() : nullptr);
  18. if (!page_directory)
  19. return {};
  20. auto space = adopt_own_if_nonnull(new (nothrow) AddressSpace(page_directory.release_nonnull()));
  21. if (!space)
  22. return {};
  23. space->page_directory().set_space({}, *space);
  24. return space;
  25. }
  26. AddressSpace::AddressSpace(NonnullRefPtr<PageDirectory> page_directory)
  27. : m_page_directory(move(page_directory))
  28. {
  29. }
  30. AddressSpace::~AddressSpace()
  31. {
  32. }
  33. KResult AddressSpace::unmap_mmap_range(VirtualAddress addr, size_t size)
  34. {
  35. if (!size)
  36. return EINVAL;
  37. auto range_or_error = VirtualRange::expand_to_page_boundaries(addr.get(), size);
  38. if (range_or_error.is_error())
  39. return range_or_error.error();
  40. auto range_to_unmap = range_or_error.value();
  41. if (!is_user_range(range_to_unmap))
  42. return EFAULT;
  43. if (auto* whole_region = find_region_from_range(range_to_unmap)) {
  44. if (!whole_region->is_mmap())
  45. return EPERM;
  46. PerformanceManager::add_unmap_perf_event(Process::current(), whole_region->range());
  47. deallocate_region(*whole_region);
  48. return KSuccess;
  49. }
  50. if (auto* old_region = find_region_containing(range_to_unmap)) {
  51. if (!old_region->is_mmap())
  52. return EPERM;
  53. // Remove the old region from our regions tree, since were going to add another region
  54. // with the exact same start address, but don't deallocate it yet.
  55. auto region = take_region(*old_region);
  56. // We manually unmap the old region here, specifying that we *don't* want the VM deallocated.
  57. region->unmap(Region::ShouldDeallocateVirtualRange::No);
  58. auto new_regions_or_error = try_split_region_around_range(*region, range_to_unmap);
  59. if (new_regions_or_error.is_error())
  60. return new_regions_or_error.error();
  61. auto& new_regions = new_regions_or_error.value();
  62. // Instead we give back the unwanted VM manually.
  63. page_directory().range_allocator().deallocate(range_to_unmap);
  64. // And finally we map the new region(s) using our page directory (they were just allocated and don't have one).
  65. for (auto* new_region : new_regions) {
  66. // TODO: Ideally we should do this in a way that can be rolled back on failure, as failing here
  67. // leaves the caller in an undefined state.
  68. if (!new_region->map(page_directory()))
  69. return ENOMEM;
  70. }
  71. PerformanceManager::add_unmap_perf_event(Process::current(), range_to_unmap);
  72. return KSuccess;
  73. }
  74. // Try again while checking multiple regions at a time.
  75. auto const& regions = find_regions_intersecting(range_to_unmap);
  76. if (regions.is_empty())
  77. return KSuccess;
  78. // Check if any of the regions is not mmap'ed, to not accidentally
  79. // error out with just half a region map left.
  80. for (auto* region : regions) {
  81. if (!region->is_mmap())
  82. return EPERM;
  83. }
  84. Vector<Region*, 2> new_regions;
  85. for (auto* old_region : regions) {
  86. // If it's a full match we can remove the entire old region.
  87. if (old_region->range().intersect(range_to_unmap).size() == old_region->size()) {
  88. deallocate_region(*old_region);
  89. continue;
  90. }
  91. // Remove the old region from our regions tree, since were going to add another region
  92. // with the exact same start address, but don't deallocate it yet.
  93. auto region = take_region(*old_region);
  94. // We manually unmap the old region here, specifying that we *don't* want the VM deallocated.
  95. region->unmap(Region::ShouldDeallocateVirtualRange::No);
  96. // Otherwise, split the regions and collect them for future mapping.
  97. auto split_regions_or_error = try_split_region_around_range(*region, range_to_unmap);
  98. if (split_regions_or_error.is_error())
  99. return split_regions_or_error.error();
  100. if (new_regions.try_extend(split_regions_or_error.value()))
  101. return ENOMEM;
  102. }
  103. // Give back any unwanted VM to the range allocator.
  104. page_directory().range_allocator().deallocate(range_to_unmap);
  105. // And finally map the new region(s) into our page directory.
  106. for (auto* new_region : new_regions) {
  107. // TODO: Ideally we should do this in a way that can be rolled back on failure, as failing here
  108. // leaves the caller in an undefined state.
  109. if (!new_region->map(page_directory()))
  110. return ENOMEM;
  111. }
  112. PerformanceManager::add_unmap_perf_event(Process::current(), range_to_unmap);
  113. return KSuccess;
  114. }
  115. Optional<VirtualRange> AddressSpace::allocate_range(VirtualAddress vaddr, size_t size, size_t alignment)
  116. {
  117. vaddr.mask(PAGE_MASK);
  118. size = page_round_up(size);
  119. if (vaddr.is_null())
  120. return page_directory().range_allocator().allocate_anywhere(size, alignment);
  121. return page_directory().range_allocator().allocate_specific(vaddr, size);
  122. }
  123. KResultOr<Region*> AddressSpace::try_allocate_split_region(Region const& source_region, VirtualRange const& range, size_t offset_in_vmobject)
  124. {
  125. auto maybe_new_region = Region::try_create_user_accessible(
  126. range, source_region.vmobject(), offset_in_vmobject, KString::try_create(source_region.name()), source_region.access(), source_region.is_cacheable() ? Region::Cacheable::Yes : Region::Cacheable::No, source_region.is_shared());
  127. if (maybe_new_region.is_error())
  128. return maybe_new_region.error();
  129. auto* region = add_region(maybe_new_region.release_value());
  130. if (!region)
  131. return ENOMEM;
  132. region->set_syscall_region(source_region.is_syscall_region());
  133. region->set_mmap(source_region.is_mmap());
  134. region->set_stack(source_region.is_stack());
  135. size_t page_offset_in_source_region = (offset_in_vmobject - source_region.offset_in_vmobject()) / PAGE_SIZE;
  136. for (size_t i = 0; i < region->page_count(); ++i) {
  137. if (source_region.should_cow(page_offset_in_source_region + i))
  138. region->set_should_cow(i, true);
  139. }
  140. return region;
  141. }
  142. KResultOr<Region*> AddressSpace::allocate_region(VirtualRange const& range, StringView name, int prot, AllocationStrategy strategy)
  143. {
  144. VERIFY(range.is_valid());
  145. auto maybe_vmobject = AnonymousVMObject::try_create_with_size(range.size(), strategy);
  146. if (maybe_vmobject.is_error())
  147. return maybe_vmobject.error();
  148. auto maybe_region = Region::try_create_user_accessible(range, maybe_vmobject.release_value(), 0, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, false);
  149. if (maybe_region.is_error())
  150. return maybe_region.error();
  151. auto region = maybe_region.release_value();
  152. if (!region->map(page_directory()))
  153. return ENOMEM;
  154. auto* added_region = add_region(move(region));
  155. if (!added_region)
  156. return ENOMEM;
  157. return added_region;
  158. }
  159. KResultOr<Region*> AddressSpace::allocate_region_with_vmobject(VirtualRange const& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, StringView name, int prot, bool shared)
  160. {
  161. VERIFY(range.is_valid());
  162. size_t end_in_vmobject = offset_in_vmobject + range.size();
  163. if (end_in_vmobject <= offset_in_vmobject) {
  164. dbgln("allocate_region_with_vmobject: Overflow (offset + size)");
  165. return EINVAL;
  166. }
  167. if (offset_in_vmobject >= vmobject->size()) {
  168. dbgln("allocate_region_with_vmobject: Attempt to allocate a region with an offset past the end of its VMObject.");
  169. return EINVAL;
  170. }
  171. if (end_in_vmobject > vmobject->size()) {
  172. dbgln("allocate_region_with_vmobject: Attempt to allocate a region with an end past the end of its VMObject.");
  173. return EINVAL;
  174. }
  175. offset_in_vmobject &= PAGE_MASK;
  176. auto maybe_region = Region::try_create_user_accessible(range, move(vmobject), offset_in_vmobject, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, shared);
  177. if (maybe_region.is_error()) {
  178. dbgln("allocate_region_with_vmobject: Unable to allocate Region");
  179. return maybe_region.error();
  180. }
  181. auto* added_region = add_region(maybe_region.release_value());
  182. if (!added_region)
  183. return ENOMEM;
  184. if (!added_region->map(page_directory()))
  185. return ENOMEM;
  186. return added_region;
  187. }
  188. void AddressSpace::deallocate_region(Region& region)
  189. {
  190. take_region(region);
  191. }
  192. NonnullOwnPtr<Region> AddressSpace::take_region(Region& region)
  193. {
  194. SpinlockLocker lock(m_lock);
  195. if (m_region_lookup_cache.region.unsafe_ptr() == &region)
  196. m_region_lookup_cache.region = nullptr;
  197. auto found_region = m_regions.unsafe_remove(region.vaddr().get());
  198. VERIFY(found_region.ptr() == &region);
  199. return found_region;
  200. }
  201. Region* AddressSpace::find_region_from_range(VirtualRange const& range)
  202. {
  203. SpinlockLocker lock(m_lock);
  204. if (m_region_lookup_cache.range.has_value() && m_region_lookup_cache.range.value() == range && m_region_lookup_cache.region)
  205. return m_region_lookup_cache.region.unsafe_ptr();
  206. auto found_region = m_regions.find(range.base().get());
  207. if (!found_region)
  208. return nullptr;
  209. auto& region = *found_region;
  210. size_t size = page_round_up(range.size());
  211. if (region->size() != size)
  212. return nullptr;
  213. m_region_lookup_cache.range = range;
  214. m_region_lookup_cache.region = *region;
  215. return region;
  216. }
  217. Region* AddressSpace::find_region_containing(VirtualRange const& range)
  218. {
  219. SpinlockLocker lock(m_lock);
  220. auto candidate = m_regions.find_largest_not_above(range.base().get());
  221. if (!candidate)
  222. return nullptr;
  223. return (*candidate)->range().contains(range) ? candidate->ptr() : nullptr;
  224. }
  225. Vector<Region*> AddressSpace::find_regions_intersecting(VirtualRange const& range)
  226. {
  227. Vector<Region*> regions = {};
  228. size_t total_size_collected = 0;
  229. SpinlockLocker lock(m_lock);
  230. auto found_region = m_regions.find_largest_not_above(range.base().get());
  231. if (!found_region)
  232. return regions;
  233. for (auto iter = m_regions.begin_from((*found_region)->vaddr().get()); !iter.is_end(); ++iter) {
  234. if ((*iter)->range().base() < range.end() && (*iter)->range().end() > range.base()) {
  235. regions.append(*iter);
  236. total_size_collected += (*iter)->size() - (*iter)->range().intersect(range).size();
  237. if (total_size_collected == range.size())
  238. break;
  239. }
  240. }
  241. return regions;
  242. }
  243. Region* AddressSpace::add_region(NonnullOwnPtr<Region> region)
  244. {
  245. auto* ptr = region.ptr();
  246. SpinlockLocker lock(m_lock);
  247. auto success = m_regions.try_insert(region->vaddr().get(), move(region));
  248. return success ? ptr : nullptr;
  249. }
  250. // Carve out a virtual address range from a region and return the two regions on either side
  251. KResultOr<Vector<Region*, 2>> AddressSpace::try_split_region_around_range(const Region& source_region, VirtualRange const& desired_range)
  252. {
  253. VirtualRange old_region_range = source_region.range();
  254. auto remaining_ranges_after_unmap = old_region_range.carve(desired_range);
  255. VERIFY(!remaining_ranges_after_unmap.is_empty());
  256. auto try_make_replacement_region = [&](VirtualRange const& new_range) -> KResultOr<Region*> {
  257. VERIFY(old_region_range.contains(new_range));
  258. size_t new_range_offset_in_vmobject = source_region.offset_in_vmobject() + (new_range.base().get() - old_region_range.base().get());
  259. return try_allocate_split_region(source_region, new_range, new_range_offset_in_vmobject);
  260. };
  261. Vector<Region*, 2> new_regions;
  262. for (auto& new_range : remaining_ranges_after_unmap) {
  263. auto new_region_or_error = try_make_replacement_region(new_range);
  264. if (new_region_or_error.is_error())
  265. return new_region_or_error.error();
  266. new_regions.unchecked_append(new_region_or_error.value());
  267. }
  268. return new_regions;
  269. }
  270. void AddressSpace::dump_regions()
  271. {
  272. dbgln("Process regions:");
  273. #if ARCH(I386)
  274. auto addr_padding = "";
  275. #else
  276. auto addr_padding = " ";
  277. #endif
  278. dbgln("BEGIN{} END{} SIZE{} ACCESS NAME",
  279. addr_padding, addr_padding, addr_padding);
  280. SpinlockLocker lock(m_lock);
  281. for (auto& sorted_region : m_regions) {
  282. auto& region = *sorted_region;
  283. dbgln("{:p} -- {:p} {:p} {:c}{:c}{:c}{:c}{:c}{:c} {}", region.vaddr().get(), region.vaddr().offset(region.size() - 1).get(), region.size(),
  284. region.is_readable() ? 'R' : ' ',
  285. region.is_writable() ? 'W' : ' ',
  286. region.is_executable() ? 'X' : ' ',
  287. region.is_shared() ? 'S' : ' ',
  288. region.is_stack() ? 'T' : ' ',
  289. region.is_syscall_region() ? 'C' : ' ',
  290. region.name());
  291. }
  292. MM.dump_kernel_regions();
  293. }
  294. void AddressSpace::remove_all_regions(Badge<Process>)
  295. {
  296. SpinlockLocker lock(m_lock);
  297. m_regions.clear();
  298. }
  299. size_t AddressSpace::amount_dirty_private() const
  300. {
  301. SpinlockLocker lock(m_lock);
  302. // FIXME: This gets a bit more complicated for Regions sharing the same underlying VMObject.
  303. // The main issue I'm thinking of is when the VMObject has physical pages that none of the Regions are mapping.
  304. // That's probably a situation that needs to be looked at in general.
  305. size_t amount = 0;
  306. for (auto& region : m_regions) {
  307. if (!region->is_shared())
  308. amount += region->amount_dirty();
  309. }
  310. return amount;
  311. }
  312. size_t AddressSpace::amount_clean_inode() const
  313. {
  314. SpinlockLocker lock(m_lock);
  315. HashTable<const InodeVMObject*> vmobjects;
  316. for (auto& region : m_regions) {
  317. if (region->vmobject().is_inode())
  318. vmobjects.set(&static_cast<const InodeVMObject&>(region->vmobject()));
  319. }
  320. size_t amount = 0;
  321. for (auto& vmobject : vmobjects)
  322. amount += vmobject->amount_clean();
  323. return amount;
  324. }
  325. size_t AddressSpace::amount_virtual() const
  326. {
  327. SpinlockLocker lock(m_lock);
  328. size_t amount = 0;
  329. for (auto& region : m_regions) {
  330. amount += region->size();
  331. }
  332. return amount;
  333. }
  334. size_t AddressSpace::amount_resident() const
  335. {
  336. SpinlockLocker lock(m_lock);
  337. // FIXME: This will double count if multiple regions use the same physical page.
  338. size_t amount = 0;
  339. for (auto& region : m_regions) {
  340. amount += region->amount_resident();
  341. }
  342. return amount;
  343. }
  344. size_t AddressSpace::amount_shared() const
  345. {
  346. SpinlockLocker lock(m_lock);
  347. // FIXME: This will double count if multiple regions use the same physical page.
  348. // FIXME: It doesn't work at the moment, since it relies on PhysicalPage ref counts,
  349. // and each PhysicalPage is only reffed by its VMObject. This needs to be refactored
  350. // so that every Region contributes +1 ref to each of its PhysicalPages.
  351. size_t amount = 0;
  352. for (auto& region : m_regions) {
  353. amount += region->amount_shared();
  354. }
  355. return amount;
  356. }
  357. size_t AddressSpace::amount_purgeable_volatile() const
  358. {
  359. SpinlockLocker lock(m_lock);
  360. size_t amount = 0;
  361. for (auto& region : m_regions) {
  362. if (!region->vmobject().is_anonymous())
  363. continue;
  364. auto const& vmobject = static_cast<AnonymousVMObject const&>(region->vmobject());
  365. if (vmobject.is_purgeable() && vmobject.is_volatile())
  366. amount += region->amount_resident();
  367. }
  368. return amount;
  369. }
  370. size_t AddressSpace::amount_purgeable_nonvolatile() const
  371. {
  372. SpinlockLocker lock(m_lock);
  373. size_t amount = 0;
  374. for (auto& region : m_regions) {
  375. if (!region->vmobject().is_anonymous())
  376. continue;
  377. auto const& vmobject = static_cast<AnonymousVMObject const&>(region->vmobject());
  378. if (vmobject.is_purgeable() && !vmobject.is_volatile())
  379. amount += region->amount_resident();
  380. }
  381. return amount;
  382. }
  383. }