Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <Kernel/Memory/AllocationStrategy.h>
10#include <Kernel/Memory/MemoryManager.h>
11#include <Kernel/Memory/PageFaultResponse.h>
12#include <Kernel/Memory/VMObject.h>
13#include <Kernel/PhysicalAddress.h>
14
15namespace Kernel::Memory {
16
17class AnonymousVMObject final : public VMObject {
18public:
19 virtual ~AnonymousVMObject() override;
20
21 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_with_size(size_t, AllocationStrategy);
22 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_for_physical_range(PhysicalAddress paddr, size_t size);
23 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_with_physical_pages(Span<NonnullRefPtr<PhysicalPage>>);
24 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_purgeable_with_size(size_t, AllocationStrategy);
25 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_physically_contiguous_with_size(size_t);
26 virtual ErrorOr<NonnullLockRefPtr<VMObject>> try_clone() override;
27
28 [[nodiscard]] NonnullRefPtr<PhysicalPage> allocate_committed_page(Badge<Region>);
29 PageFaultResponse handle_cow_fault(size_t, VirtualAddress);
30 size_t cow_pages() const;
31 bool should_cow(size_t page_index, bool) const;
32 ErrorOr<void> set_should_cow(size_t page_index, bool);
33
34 bool is_purgeable() const { return m_purgeable; }
35 bool is_volatile() const { return m_volatile; }
36
37 ErrorOr<void> set_volatile(bool is_volatile, bool& was_purged);
38
39 size_t purge();
40
41private:
42 class SharedCommittedCowPages;
43
44 static ErrorOr<NonnullLockRefPtr<AnonymousVMObject>> try_create_with_shared_cow(AnonymousVMObject const&, NonnullLockRefPtr<SharedCommittedCowPages>, FixedArray<RefPtr<PhysicalPage>>&&);
45
46 explicit AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&&, AllocationStrategy, Optional<CommittedPhysicalPageSet>);
47 explicit AnonymousVMObject(PhysicalAddress, FixedArray<RefPtr<PhysicalPage>>&&);
48 explicit AnonymousVMObject(FixedArray<RefPtr<PhysicalPage>>&&);
49 explicit AnonymousVMObject(LockWeakPtr<AnonymousVMObject>, NonnullLockRefPtr<SharedCommittedCowPages>, FixedArray<RefPtr<PhysicalPage>>&&);
50
51 virtual StringView class_name() const override { return "AnonymousVMObject"sv; }
52
53 AnonymousVMObject& operator=(AnonymousVMObject const&) = delete;
54 AnonymousVMObject& operator=(AnonymousVMObject&&) = delete;
55 AnonymousVMObject(AnonymousVMObject&&) = delete;
56
57 virtual bool is_anonymous() const override { return true; }
58
59 ErrorOr<void> ensure_cow_map();
60 ErrorOr<void> ensure_or_reset_cow_map();
61
62 Optional<CommittedPhysicalPageSet> m_unused_committed_pages;
63 Bitmap m_cow_map;
64
65 // AnonymousVMObject shares committed COW pages with cloned children (happens on fork)
66 class SharedCommittedCowPages final : public AtomicRefCounted<SharedCommittedCowPages> {
67 AK_MAKE_NONCOPYABLE(SharedCommittedCowPages);
68
69 public:
70 SharedCommittedCowPages() = delete;
71
72 explicit SharedCommittedCowPages(CommittedPhysicalPageSet&&);
73 ~SharedCommittedCowPages();
74
75 [[nodiscard]] bool is_empty() const { return m_committed_pages.is_empty(); }
76
77 [[nodiscard]] NonnullRefPtr<PhysicalPage> take_one();
78 void uncommit_one();
79
80 private:
81 Spinlock<LockRank::None> m_lock {};
82 CommittedPhysicalPageSet m_committed_pages;
83 };
84
85 LockWeakPtr<AnonymousVMObject> m_cow_parent;
86 LockRefPtr<SharedCommittedCowPages> m_shared_committed_cow_pages;
87
88 bool m_purgeable { false };
89 bool m_volatile { false };
90 bool m_was_purged { false };
91};
92
93}