diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index ad799d8ede..c9fcb9074f 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -28,6 +28,7 @@ set(KERNEL_SOURCES Devices/I8042Controller.cpp Devices/KeyboardDevice.cpp Devices/MBVGADevice.cpp + Devices/MemoryDevice.cpp Devices/NullDevice.cpp Devices/PCSpeaker.cpp Devices/PS2MouseDevice.cpp diff --git a/Kernel/Devices/MemoryDevice.cpp b/Kernel/Devices/MemoryDevice.cpp new file mode 100644 index 0000000000..acbe53ae90 --- /dev/null +++ b/Kernel/Devices/MemoryDevice.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "MemoryDevice.h" +#include +#include +#include +#include +#include + +namespace Kernel { + +MemoryDevice::MemoryDevice() + : CharacterDevice(1, 1) +{ +} + +MemoryDevice::~MemoryDevice() +{ +} + +KResultOr MemoryDevice::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) +{ + TODO(); +} + +void MemoryDevice::did_seek(FileDescription&, off_t) +{ + TODO(); +} + +KResultOr MemoryDevice::mmap(Process& process, FileDescription&, const Range& range, size_t offset, int prot, bool shared) +{ + auto viewed_address = PhysicalAddress(offset); + + dbgln("MemoryDevice: Trying to mmap physical memory at {} for range of {} bytes", viewed_address, range.size()); + if (!MM.is_allowed_to_mmap_to_userspace(viewed_address, range)) { + dbgln("MemoryDevice: Trying to mmap physical memory at {} for range of {} bytes failed due to violation of access", viewed_address, range.size()); + return EINVAL; + } + + auto vmobject = AnonymousVMObject::create_for_physical_range(viewed_address, range.size()); + if (!vmobject) + return ENOMEM; + dbgln("MemoryDevice: Mapped physical memory at {} for range of {} bytes", viewed_address, range.size()); + return process.allocate_region_with_vmobject( + range, + vmobject.release_nonnull(), + 0, + "Mapped Physical Memory", + prot, + shared); +} + +} diff --git a/Kernel/Devices/MemoryDevice.h b/Kernel/Devices/MemoryDevice.h new file mode 100644 index 0000000000..cd14c864d6 --- /dev/null +++ b/Kernel/Devices/MemoryDevice.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include + +namespace Kernel { + +class MemoryDevice final : public CharacterDevice { + AK_MAKE_ETERNAL +public: + MemoryDevice(); + ~MemoryDevice(); + + virtual KResultOr mmap(Process&, FileDescription&, const Range&, size_t offset, int prot, bool shared) override; + + // ^Device + virtual mode_t required_mode() const override { return 0660; } + virtual String device_name() const override { return "mem"; }; + +private: + virtual const char* class_name() const override { return "MemoryDevice"; } + virtual bool can_read(const FileDescription&, size_t) const override { return true; } + virtual bool can_write(const FileDescription&, size_t) const override { return false; } + virtual bool is_seekable() const { return true; } + virtual KResultOr read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; + virtual KResultOr write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return -EINVAL; } + + virtual void did_seek(FileDescription&, off_t) override; + + bool is_allowed_range(PhysicalAddress, const Range&) const; +}; + +} diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 5a7c1687d6..20e5a4d46c 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -121,6 +121,45 @@ void MemoryManager::protect_kernel_image() } } +void MemoryManager::register_reserved_ranges() +{ + ASSERT(!m_physical_memory_ranges.is_empty()); + ContiguousReservedMemoryRange range; + for (auto& current_range : m_physical_memory_ranges) { + if (current_range.type != PhysicalMemoryRangeType::Reserved) { + if (range.start.is_null()) + continue; + m_reserved_memory_ranges.append(ContiguousReservedMemoryRange { range.start, current_range.start.get() - range.start.get() }); + range.start.set((FlatPtr) nullptr); + continue; + } + if (!range.start.is_null()) { + continue; + } + range.start = current_range.start; + } + if (m_physical_memory_ranges.last().type != PhysicalMemoryRangeType::Reserved) + return; + if (range.start.is_null()) + return; + m_reserved_memory_ranges.append(ContiguousReservedMemoryRange { range.start, m_physical_memory_ranges.last().start.get() + m_physical_memory_ranges.last().length - range.start.get() }); +} + +bool MemoryManager::is_allowed_to_mmap_to_userspace(PhysicalAddress start_address, const Range& range) const +{ + ASSERT(!m_reserved_memory_ranges.is_empty()); + for (auto& current_range : m_reserved_memory_ranges) { + if (!(current_range.start <= start_address)) + continue; + if (!(current_range.start.offset(current_range.length) > start_address)) + continue; + if (!(current_range.length >= range.size())) + return false; + return true; + } + return false; +} + void MemoryManager::parse_memory_map() { RefPtr region; @@ -149,6 +188,31 @@ void MemoryManager::parse_memory_map() for (auto* mmap = mmap_begin; mmap < mmap_end; mmap++) { klog() << "MM: Multiboot mmap: address = " << String::format("0x%016llx", mmap->addr) << ", length = " << String::format("0x%016llx", mmap->len) << ", type = 0x" << String::format("%x", mmap->type); + auto start_address = PhysicalAddress(mmap->addr); + size_t length = static_cast(mmap->len); + switch (mmap->type) { + case (MULTIBOOT_MEMORY_AVAILABLE): + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::Usable, start_address, length }); + break; + case (MULTIBOOT_MEMORY_RESERVED): + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::Reserved, start_address, length }); + break; + case (MULTIBOOT_MEMORY_ACPI_RECLAIMABLE): + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::ACPI_Reclaimable, start_address, length }); + break; + case (MULTIBOOT_MEMORY_NVS): + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::ACPI_NVS, start_address, length }); + break; + case (MULTIBOOT_MEMORY_BADRAM): + klog() << "MM: Warning, detected bad memory range!"; + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::BadMemory, start_address, length }); + break; + default: + dbgln("MM: Unknown range!"); + m_physical_memory_ranges.append(PhysicalMemoryRange { PhysicalMemoryRangeType::Unknown, start_address, length }); + break; + } + if (mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue; @@ -216,6 +280,10 @@ void MemoryManager::parse_memory_map() // We start out with no committed pages m_user_physical_pages_uncommitted = m_user_physical_pages.load(); + register_reserved_ranges(); + for (auto& range : m_reserved_memory_ranges) { + dmesgln("MM: Contiguous reserved range from {}, length is {}", range.start, range.length); + } } PageTableEntry* MemoryManager::pte(PageDirectory& page_directory, VirtualAddress vaddr) diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index efe338cee5..b85376c181 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -85,6 +85,26 @@ struct UsedMemoryRange { PhysicalAddress end; }; +struct ContiguousReservedMemoryRange { + PhysicalAddress start; + size_t length; +}; + +enum class PhysicalMemoryRangeType { + Usable = 0, + Reserved, + ACPI_Reclaimable, + ACPI_NVS, + BadMemory, + Unknown +}; + +struct PhysicalMemoryRange { + PhysicalMemoryRangeType type; + PhysicalAddress start; + size_t length; +}; + const LogStream& operator<<(const LogStream& stream, const UsedMemoryRange& value); #define MM Kernel::MemoryManager::the() @@ -187,11 +207,14 @@ public: PageDirectory& kernel_page_directory() { return *m_kernel_page_directory; } const Vector& used_memory_ranges() { return m_used_memory_ranges; } + bool is_allowed_to_mmap_to_userspace(PhysicalAddress, const Range&) const; private: MemoryManager(); ~MemoryManager(); + void register_reserved_ranges(); + enum class AccessSpace { Kernel, User }; enum class AccessType { Read, @@ -245,6 +268,8 @@ private: InlineLinkedList m_user_regions; InlineLinkedList m_kernel_regions; Vector m_used_memory_ranges; + Vector m_physical_memory_ranges; + Vector m_reserved_memory_ranges; InlineLinkedList m_vmobjects; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 5ed49bd014..f6177c17d3 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -262,6 +263,7 @@ void init_stage2(void*) Syscall::initialize(); + new MemoryDevice; new ZeroDevice; new FullDevice; new RandomDevice;