summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2022-05-13 03:22:23 +0300
committerLinus Groh <mail@linusgroh.de>2022-06-06 20:11:05 +0100
commit3d22917548bd94e7ad5162986d801d5bea69b197 (patch)
treed8cffb26d474b973ba994406d3d14525f2352dda /Kernel
parentec925cbb8991157509acfe2e64ab13f68b6f77af (diff)
downloadserenity-3d22917548bd94e7ad5162986d801d5bea69b197.zip
Kernel/Memory: Introduce the SharedFramebufferVMObject class
This new type of VMObject will be used to coordinate switching safely from graphical mode to text mode and vice-versa, by supplying a way to remap all Regions that were created with this object, so mappings can be changed according to the given state of system mode. This makes it quite easy to give applications like WindowServer the feeling of having full access to the framebuffer device from a DisplayConnector, but still keep the Kernel in control to be able to safely switch to text console.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/CMakeLists.txt1
-rw-r--r--Kernel/Forward.h1
-rw-r--r--Kernel/Memory/SharedFramebufferVMObject.cpp120
-rw-r--r--Kernel/Memory/SharedFramebufferVMObject.h94
-rw-r--r--Kernel/Memory/VMObject.h5
5 files changed, 219 insertions, 2 deletions
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 2e52cea77c..2e4bfe317c 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -181,6 +181,7 @@ set(KERNEL_SOURCES
Memory/RingBuffer.cpp
Memory/ScatterGatherList.cpp
Memory/ScopedAddressSpaceSwitcher.cpp
+ Memory/SharedFramebufferVMObject.cpp
Memory/SharedInodeVMObject.cpp
Memory/VMObject.cpp
Memory/VirtualRange.cpp
diff --git a/Kernel/Forward.h b/Kernel/Forward.h
index 7fcedb1d2a..667fd605bf 100644
--- a/Kernel/Forward.h
+++ b/Kernel/Forward.h
@@ -25,6 +25,7 @@ class DiskCache;
class DoubleBuffer;
class File;
class OpenFileDescription;
+class DisplayConnector;
class FileSystem;
class FutexQueue;
class IPv4Socket;
diff --git a/Kernel/Memory/SharedFramebufferVMObject.cpp b/Kernel/Memory/SharedFramebufferVMObject.cpp
new file mode 100644
index 0000000000..f0ea27e874
--- /dev/null
+++ b/Kernel/Memory/SharedFramebufferVMObject.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/Locking/Spinlock.h>
+#include <Kernel/Memory/SharedFramebufferVMObject.h>
+
+namespace Kernel::Memory {
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> SharedFramebufferVMObject::try_create_for_physical_range(PhysicalAddress paddr, size_t size)
+{
+ auto real_framebuffer_vmobject = TRY(AnonymousVMObject::try_create_for_physical_range(paddr, size));
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
+ auto committed_pages = TRY(MM.commit_user_physical_pages(ceil_div(size, static_cast<size_t>(PAGE_SIZE))));
+ auto vm_object = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SharedFramebufferVMObject(move(new_physical_pages), move(committed_pages), real_framebuffer_vmobject)));
+ TRY(vm_object->create_fake_writes_framebuffer_vm_object());
+ TRY(vm_object->create_real_writes_framebuffer_vm_object());
+ return vm_object;
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> SharedFramebufferVMObject::try_create_at_arbitrary_physical_range(size_t size)
+{
+ auto real_framebuffer_vmobject = TRY(AnonymousVMObject::try_create_with_size(size, AllocationStrategy::AllocateNow));
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
+ auto committed_pages = TRY(MM.commit_user_physical_pages(ceil_div(size, static_cast<size_t>(PAGE_SIZE))));
+ auto vm_object = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SharedFramebufferVMObject(move(new_physical_pages), move(committed_pages), real_framebuffer_vmobject)));
+ TRY(vm_object->create_fake_writes_framebuffer_vm_object());
+ TRY(vm_object->create_real_writes_framebuffer_vm_object());
+ return vm_object;
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject::FakeWritesFramebufferVMObject>> SharedFramebufferVMObject::FakeWritesFramebufferVMObject::try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object)
+{
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(0));
+ return adopt_nonnull_ref_or_enomem(new (nothrow) FakeWritesFramebufferVMObject(parent_object, move(new_physical_pages)));
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject::RealWritesFramebufferVMObject>> SharedFramebufferVMObject::RealWritesFramebufferVMObject::try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object)
+{
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(0));
+ return adopt_nonnull_ref_or_enomem(new (nothrow) RealWritesFramebufferVMObject(parent_object, move(new_physical_pages)));
+}
+
+ErrorOr<void> SharedFramebufferVMObject::create_fake_writes_framebuffer_vm_object()
+{
+ m_fake_writes_framebuffer_vmobject = TRY(FakeWritesFramebufferVMObject::try_create({}, *this));
+ return {};
+}
+
+ErrorOr<void> SharedFramebufferVMObject::create_real_writes_framebuffer_vm_object()
+{
+ m_real_writes_framebuffer_vmobject = TRY(RealWritesFramebufferVMObject::try_create({}, *this));
+ return {};
+}
+
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::real_framebuffer_physical_pages()
+{
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::real_framebuffer_physical_pages() const
+{
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::fake_sink_framebuffer_physical_pages()
+{
+ return m_physical_pages.span();
+}
+
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::fake_sink_framebuffer_physical_pages() const
+{
+ return m_physical_pages.span();
+}
+
+void SharedFramebufferVMObject::switch_to_fake_sink_framebuffer_writes(Badge<Kernel::DisplayConnector>)
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ m_writes_are_faked = true;
+ for_each_region([](Region& region) {
+ region.remap();
+ });
+}
+void SharedFramebufferVMObject::switch_to_real_framebuffer_writes(Badge<Kernel::DisplayConnector>)
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ m_writes_are_faked = false;
+ for_each_region([](Region& region) {
+ region.remap();
+ });
+}
+
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::physical_pages() const
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ if (m_writes_are_faked)
+ return VMObject::physical_pages();
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::physical_pages()
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ if (m_writes_are_faked)
+ return VMObject::physical_pages();
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+
+SharedFramebufferVMObject::SharedFramebufferVMObject(FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, CommittedPhysicalPageSet committed_pages, AnonymousVMObject& real_framebuffer_vmobject)
+ : VMObject(move(new_physical_pages))
+ , m_real_framebuffer_vmobject(real_framebuffer_vmobject)
+ , m_committed_pages(move(committed_pages))
+{
+ // Allocate all pages right now. We know we can get all because we committed the amount needed
+ for (size_t i = 0; i < page_count(); ++i)
+ m_physical_pages[i] = m_committed_pages.take_one();
+}
+
+}
diff --git a/Kernel/Memory/SharedFramebufferVMObject.h b/Kernel/Memory/SharedFramebufferVMObject.h
new file mode 100644
index 0000000000..90e195aa34
--- /dev/null
+++ b/Kernel/Memory/SharedFramebufferVMObject.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/Forward.h>
+#include <Kernel/Memory/AllocationStrategy.h>
+#include <Kernel/Memory/AnonymousVMObject.h>
+#include <Kernel/Memory/MemoryManager.h>
+#include <Kernel/Memory/PageFaultResponse.h>
+#include <Kernel/PhysicalAddress.h>
+
+namespace Kernel::Memory {
+
+class SharedFramebufferVMObject final : public VMObject {
+public:
+ class FakeWritesFramebufferVMObject final : public VMObject {
+ public:
+ static ErrorOr<NonnullRefPtr<FakeWritesFramebufferVMObject>> try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object);
+
+ private:
+ FakeWritesFramebufferVMObject(SharedFramebufferVMObject const& parent_object, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages)
+ : VMObject(move(new_physical_pages))
+ , m_parent_object(parent_object)
+ {
+ }
+ virtual StringView class_name() const override { return "FakeWritesFramebufferVMObject"sv; }
+ virtual ErrorOr<NonnullRefPtr<VMObject>> try_clone() override { return Error::from_errno(ENOTIMPL); }
+ virtual Span<RefPtr<PhysicalPage> const> physical_pages() const override { return m_parent_object->fake_sink_framebuffer_physical_pages(); }
+ virtual Span<RefPtr<PhysicalPage>> physical_pages() override { return m_parent_object->fake_sink_framebuffer_physical_pages(); }
+ NonnullRefPtr<SharedFramebufferVMObject> m_parent_object;
+ };
+
+ class RealWritesFramebufferVMObject final : public VMObject {
+ public:
+ static ErrorOr<NonnullRefPtr<RealWritesFramebufferVMObject>> try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object);
+
+ private:
+ RealWritesFramebufferVMObject(SharedFramebufferVMObject const& parent_object, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages)
+ : VMObject(move(new_physical_pages))
+ , m_parent_object(parent_object)
+ {
+ }
+ virtual StringView class_name() const override { return "RealWritesFramebufferVMObject"sv; }
+ virtual ErrorOr<NonnullRefPtr<VMObject>> try_clone() override { return Error::from_errno(ENOTIMPL); }
+ virtual Span<RefPtr<PhysicalPage> const> physical_pages() const override { return m_parent_object->real_framebuffer_physical_pages(); }
+ virtual Span<RefPtr<PhysicalPage>> physical_pages() override { return m_parent_object->real_framebuffer_physical_pages(); }
+ NonnullRefPtr<SharedFramebufferVMObject> m_parent_object;
+ };
+
+ virtual ~SharedFramebufferVMObject() override = default;
+
+ static ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> try_create_for_physical_range(PhysicalAddress paddr, size_t size);
+ static ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> try_create_at_arbitrary_physical_range(size_t size);
+ virtual ErrorOr<NonnullRefPtr<VMObject>> try_clone() override { return Error::from_errno(ENOTIMPL); }
+
+ void switch_to_fake_sink_framebuffer_writes(Badge<Kernel::DisplayConnector>);
+ void switch_to_real_framebuffer_writes(Badge<Kernel::DisplayConnector>);
+
+ virtual Span<RefPtr<PhysicalPage> const> physical_pages() const override;
+ virtual Span<RefPtr<PhysicalPage>> physical_pages() override;
+
+ Span<RefPtr<PhysicalPage>> fake_sink_framebuffer_physical_pages();
+ Span<RefPtr<PhysicalPage> const> fake_sink_framebuffer_physical_pages() const;
+
+ Span<RefPtr<PhysicalPage>> real_framebuffer_physical_pages();
+ Span<RefPtr<PhysicalPage> const> real_framebuffer_physical_pages() const;
+
+ FakeWritesFramebufferVMObject const& fake_writes_framebuffer_vmobject() const { return *m_fake_writes_framebuffer_vmobject; }
+ FakeWritesFramebufferVMObject& fake_writes_framebuffer_vmobject() { return *m_fake_writes_framebuffer_vmobject; }
+
+ RealWritesFramebufferVMObject const& real_writes_framebuffer_vmobject() const { return *m_real_writes_framebuffer_vmobject; }
+ RealWritesFramebufferVMObject& real_writes_framebuffer_vmobject() { return *m_real_writes_framebuffer_vmobject; }
+
+private:
+ SharedFramebufferVMObject(FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, CommittedPhysicalPageSet, AnonymousVMObject& real_framebuffer_vmobject);
+
+ virtual StringView class_name() const override { return "SharedFramebufferVMObject"sv; }
+
+ ErrorOr<void> create_fake_writes_framebuffer_vm_object();
+ ErrorOr<void> create_real_writes_framebuffer_vm_object();
+
+ NonnullRefPtr<AnonymousVMObject> m_real_framebuffer_vmobject;
+ RefPtr<FakeWritesFramebufferVMObject> m_fake_writes_framebuffer_vmobject;
+ RefPtr<RealWritesFramebufferVMObject> m_real_writes_framebuffer_vmobject;
+ bool m_writes_are_faked { false };
+ mutable RecursiveSpinlock m_writes_state_lock;
+ CommittedPhysicalPageSet m_committed_pages;
+};
+
+}
diff --git a/Kernel/Memory/VMObject.h b/Kernel/Memory/VMObject.h
index 24898722a8..7432181ecf 100644
--- a/Kernel/Memory/VMObject.h
+++ b/Kernel/Memory/VMObject.h
@@ -34,8 +34,9 @@ public:
virtual bool is_private_inode() const { return false; }
size_t page_count() const { return m_physical_pages.size(); }
- Span<RefPtr<PhysicalPage> const> physical_pages() const { return m_physical_pages.span(); }
- Span<RefPtr<PhysicalPage>> physical_pages() { return m_physical_pages.span(); }
+
+ virtual Span<RefPtr<PhysicalPage> const> physical_pages() const { return m_physical_pages.span(); }
+ virtual Span<RefPtr<PhysicalPage>> physical_pages() { return m_physical_pages.span(); }
size_t size() const { return m_physical_pages.size() * PAGE_SIZE; }