mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 21:17:42 +00:00
Kernel: Introduce the MemoryDevice
This is a character device that is being used by the dmidecode utility. We only allow to map the BIOS ROM area to userspace with this device.
This commit is contained in:
parent
df59b80e23
commit
5ab1864497
6 changed files with 235 additions and 0 deletions
|
@ -28,6 +28,7 @@ set(KERNEL_SOURCES
|
||||||
Devices/I8042Controller.cpp
|
Devices/I8042Controller.cpp
|
||||||
Devices/KeyboardDevice.cpp
|
Devices/KeyboardDevice.cpp
|
||||||
Devices/MBVGADevice.cpp
|
Devices/MBVGADevice.cpp
|
||||||
|
Devices/MemoryDevice.cpp
|
||||||
Devices/NullDevice.cpp
|
Devices/NullDevice.cpp
|
||||||
Devices/PCSpeaker.cpp
|
Devices/PCSpeaker.cpp
|
||||||
Devices/PS2MouseDevice.cpp
|
Devices/PS2MouseDevice.cpp
|
||||||
|
|
78
Kernel/Devices/MemoryDevice.cpp
Normal file
78
Kernel/Devices/MemoryDevice.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
* 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 <AK/Memory.h>
|
||||||
|
#include <AK/StdLibExtras.h>
|
||||||
|
#include <Kernel/Arch/PC/BIOS.h>
|
||||||
|
#include <Kernel/VM/AnonymousVMObject.h>
|
||||||
|
#include <Kernel/VM/TypedMapping.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
MemoryDevice::MemoryDevice()
|
||||||
|
: CharacterDevice(1, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryDevice::~MemoryDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
KResultOr<size_t> MemoryDevice::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t)
|
||||||
|
{
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryDevice::did_seek(FileDescription&, off_t)
|
||||||
|
{
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
KResultOr<Region*> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
Kernel/Devices/MemoryDevice.h
Normal file
61
Kernel/Devices/MemoryDevice.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
* 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 <AK/String.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
#include <Kernel/Devices/CharacterDevice.h>
|
||||||
|
#include <Kernel/PhysicalAddress.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class MemoryDevice final : public CharacterDevice {
|
||||||
|
AK_MAKE_ETERNAL
|
||||||
|
public:
|
||||||
|
MemoryDevice();
|
||||||
|
~MemoryDevice();
|
||||||
|
|
||||||
|
virtual KResultOr<Region*> 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<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
|
||||||
|
virtual KResultOr<size_t> 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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()
|
void MemoryManager::parse_memory_map()
|
||||||
{
|
{
|
||||||
RefPtr<PhysicalRegion> region;
|
RefPtr<PhysicalRegion> region;
|
||||||
|
@ -149,6 +188,31 @@ void MemoryManager::parse_memory_map()
|
||||||
for (auto* mmap = mmap_begin; mmap < mmap_end; mmap++) {
|
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);
|
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<size_t>(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)
|
if (mmap->type != MULTIBOOT_MEMORY_AVAILABLE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -216,6 +280,10 @@ void MemoryManager::parse_memory_map()
|
||||||
|
|
||||||
// We start out with no committed pages
|
// We start out with no committed pages
|
||||||
m_user_physical_pages_uncommitted = m_user_physical_pages.load();
|
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)
|
PageTableEntry* MemoryManager::pte(PageDirectory& page_directory, VirtualAddress vaddr)
|
||||||
|
|
|
@ -85,6 +85,26 @@ struct UsedMemoryRange {
|
||||||
PhysicalAddress end;
|
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);
|
const LogStream& operator<<(const LogStream& stream, const UsedMemoryRange& value);
|
||||||
|
|
||||||
#define MM Kernel::MemoryManager::the()
|
#define MM Kernel::MemoryManager::the()
|
||||||
|
@ -187,11 +207,14 @@ public:
|
||||||
PageDirectory& kernel_page_directory() { return *m_kernel_page_directory; }
|
PageDirectory& kernel_page_directory() { return *m_kernel_page_directory; }
|
||||||
|
|
||||||
const Vector<UsedMemoryRange>& used_memory_ranges() { return m_used_memory_ranges; }
|
const Vector<UsedMemoryRange>& used_memory_ranges() { return m_used_memory_ranges; }
|
||||||
|
bool is_allowed_to_mmap_to_userspace(PhysicalAddress, const Range&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryManager();
|
MemoryManager();
|
||||||
~MemoryManager();
|
~MemoryManager();
|
||||||
|
|
||||||
|
void register_reserved_ranges();
|
||||||
|
|
||||||
enum class AccessSpace { Kernel,
|
enum class AccessSpace { Kernel,
|
||||||
User };
|
User };
|
||||||
enum class AccessType { Read,
|
enum class AccessType { Read,
|
||||||
|
@ -245,6 +268,8 @@ private:
|
||||||
InlineLinkedList<Region> m_user_regions;
|
InlineLinkedList<Region> m_user_regions;
|
||||||
InlineLinkedList<Region> m_kernel_regions;
|
InlineLinkedList<Region> m_kernel_regions;
|
||||||
Vector<UsedMemoryRange> m_used_memory_ranges;
|
Vector<UsedMemoryRange> m_used_memory_ranges;
|
||||||
|
Vector<PhysicalMemoryRange> m_physical_memory_ranges;
|
||||||
|
Vector<ContiguousReservedMemoryRange> m_reserved_memory_ranges;
|
||||||
|
|
||||||
InlineLinkedList<VMObject> m_vmobjects;
|
InlineLinkedList<VMObject> m_vmobjects;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <Kernel/Devices/FullDevice.h>
|
#include <Kernel/Devices/FullDevice.h>
|
||||||
#include <Kernel/Devices/I8042Controller.h>
|
#include <Kernel/Devices/I8042Controller.h>
|
||||||
#include <Kernel/Devices/MBVGADevice.h>
|
#include <Kernel/Devices/MBVGADevice.h>
|
||||||
|
#include <Kernel/Devices/MemoryDevice.h>
|
||||||
#include <Kernel/Devices/NullDevice.h>
|
#include <Kernel/Devices/NullDevice.h>
|
||||||
#include <Kernel/Devices/RandomDevice.h>
|
#include <Kernel/Devices/RandomDevice.h>
|
||||||
#include <Kernel/Devices/SB16.h>
|
#include <Kernel/Devices/SB16.h>
|
||||||
|
@ -262,6 +263,7 @@ void init_stage2(void*)
|
||||||
|
|
||||||
Syscall::initialize();
|
Syscall::initialize();
|
||||||
|
|
||||||
|
new MemoryDevice;
|
||||||
new ZeroDevice;
|
new ZeroDevice;
|
||||||
new FullDevice;
|
new FullDevice;
|
||||||
new RandomDevice;
|
new RandomDevice;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue