From 92c0dab5ab45ff0db8317439ea2f8bc3d96158c4 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 13 Mar 2021 12:01:44 +0200 Subject: [PATCH] Kernel: Introduce the new SysFS The intention is to add dynamic mechanism for notifying the userspace about hotplug events. Currently, the DMI (SMBIOS) blobs and ACPI tables are exposed in the new filesystem. --- Kernel/ACPI/Parser.cpp | 73 ++++++++++++ Kernel/ACPI/Parser.h | 24 +++- Kernel/Arch/PC/BIOS.cpp | 149 ++++++++++++++++++++++++ Kernel/Arch/PC/BIOS.h | 107 ++++++++++++++++++ Kernel/CMakeLists.txt | 3 +- Kernel/DMI.cpp | 111 ------------------ Kernel/DMI.h | 87 -------------- Kernel/FileSystem/SysFS.cpp | 220 ++++++++++++++++++++++++++++++++++++ Kernel/FileSystem/SysFS.h | 121 ++++++++++++++++++++ Kernel/Syscalls/mount.cpp | 3 + Kernel/SystemExposed.cpp | 74 ++++++++++++ Kernel/SystemExposed.h | 62 ++++++++++ Kernel/init.cpp | 7 +- 13 files changed, 839 insertions(+), 202 deletions(-) delete mode 100644 Kernel/DMI.cpp delete mode 100644 Kernel/DMI.h create mode 100644 Kernel/FileSystem/SysFS.cpp create mode 100644 Kernel/FileSystem/SysFS.h create mode 100644 Kernel/SystemExposed.cpp create mode 100644 Kernel/SystemExposed.h diff --git a/Kernel/ACPI/Parser.cpp b/Kernel/ACPI/Parser.cpp index 1706445c7e..e86f27f33a 100644 --- a/Kernel/ACPI/Parser.cpp +++ b/Kernel/ACPI/Parser.cpp @@ -27,6 +27,79 @@ Parser* Parser::the() return s_acpi_parser; } +UNMAP_AFTER_INIT NonnullRefPtr ExposedComponent::create(String name, PhysicalAddress paddr, size_t table_size) +{ + return adopt_ref(*new (nothrow) ExposedComponent(name, paddr, table_size)); +} + +KResultOr ExposedComponent::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const +{ + auto blob = try_to_generate_buffer(); + if (!blob) + return KResult(EFAULT); + + if ((size_t)offset >= blob->size()) + return KSuccess; + + ssize_t nread = min(static_cast(blob->size() - offset), static_cast(count)); + if (!buffer.write(blob->data() + offset, nread)) + return KResult(EFAULT); + return nread; +} + +OwnPtr ExposedComponent::try_to_generate_buffer() const +{ + auto acpi_blob = map_typed((m_paddr), m_length); + return KBuffer::try_create_with_bytes(Span { acpi_blob.ptr(), m_length }); +} + +UNMAP_AFTER_INIT ExposedComponent::ExposedComponent(String name, PhysicalAddress paddr, size_t table_size) + : SystemExposedComponent(name) + , m_paddr(paddr) + , m_length(table_size) +{ +} + +UNMAP_AFTER_INIT void ExposedFolder::initialize() +{ + auto acpi_folder = adopt_ref(*new (nothrow) ExposedFolder()); + SystemRegistrar::the().register_new_component(acpi_folder); +} + +UNMAP_AFTER_INIT ExposedFolder::ExposedFolder() + : SystemExposedFolder("acpi", SystemRegistrar::the().root_folder()) +{ + NonnullRefPtrVector components; + size_t ssdt_count = 0; + ACPI::Parser::the()->enumerate_static_tables([&](const StringView& signature, PhysicalAddress p_table, size_t length) { + if (signature == "SSDT") { + components.append(ExposedComponent::create(String::formatted("{:4s}{}", signature.characters_without_null_termination(), ssdt_count), p_table, length)); + ssdt_count++; + return; + } + components.append(ExposedComponent::create(signature, p_table, length)); + }); + m_components = components; + + auto rsdp = map_typed(ACPI::Parser::the()->rsdp()); + m_components.append(ExposedComponent::create("RSDP", ACPI::Parser::the()->rsdp(), rsdp->base.revision == 0 ? sizeof(Structures::RSDPDescriptor) : rsdp->length)); + + auto main_system_description_table = map_typed(ACPI::Parser::the()->main_system_description_table()); + if (ACPI::Parser::the()->is_xsdt_supported()) { + m_components.append(ExposedComponent::create("XSDT", ACPI::Parser::the()->main_system_description_table(), main_system_description_table->length)); + } else { + m_components.append(ExposedComponent::create("RSDT", ACPI::Parser::the()->main_system_description_table(), main_system_description_table->length)); + } +} + +void Parser::enumerate_static_tables(Function callback) +{ + for (auto& p_table : m_sdt_pointers) { + auto table = map_typed(p_table); + callback({ table->sig, 4 }, p_table, table->length); + } +} + void Parser::set_the(Parser& parser) { VERIFY(!s_acpi_parser); diff --git a/Kernel/ACPI/Parser.h b/Kernel/ACPI/Parser.h index e31e355396..c9fbd5dd2e 100644 --- a/Kernel/ACPI/Parser.h +++ b/Kernel/ACPI/Parser.h @@ -9,14 +9,36 @@ #include #include #include -#include #include +#include #include #include namespace Kernel { namespace ACPI { +class ExposedFolder : public SystemExposedFolder { +public: + static void initialize(); + +private: + ExposedFolder(); +}; + +class ExposedComponent : public SystemExposedComponent { +public: + static NonnullRefPtr create(String name, PhysicalAddress, size_t table_size); + + virtual KResultOr read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const override; + +protected: + OwnPtr try_to_generate_buffer() const; + ExposedComponent(String name, PhysicalAddress, size_t table_size); + + PhysicalAddress m_paddr; + size_t m_length; +}; + class Parser { public: static Parser* the(); diff --git a/Kernel/Arch/PC/BIOS.cpp b/Kernel/Arch/PC/BIOS.cpp index 8dd0b58dad..fc86d756d7 100644 --- a/Kernel/Arch/PC/BIOS.cpp +++ b/Kernel/Arch/PC/BIOS.cpp @@ -1,16 +1,165 @@ /* * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2021, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include +#include +#include +#include #include #include namespace Kernel { +#define SMBIOS_BASE_SEARCH_ADDR 0xf0000 +#define SMBIOS_END_SEARCH_ADDR 0xfffff +#define SMBIOS_SEARCH_AREA_SIZE (SMBIOS_END_SEARCH_ADDR - SMBIOS_BASE_SEARCH_ADDR) + +UNMAP_AFTER_INIT NonnullRefPtr DMIEntryPointExposedBlob::create(PhysicalAddress dmi_entry_point, size_t blob_size) +{ + return adopt_ref(*new (nothrow) DMIEntryPointExposedBlob(dmi_entry_point, blob_size)); +} + +UNMAP_AFTER_INIT BIOSExposedComponent::BIOSExposedComponent(String name) + : SystemExposedComponent(name) +{ +} + +KResultOr BIOSExposedComponent::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const +{ + auto blob = try_to_generate_buffer(); + if (!blob) + return KResult(EFAULT); + + if ((size_t)offset >= blob->size()) + return KSuccess; + + ssize_t nread = min(static_cast(blob->size() - offset), static_cast(count)); + if (!buffer.write(blob->data() + offset, nread)) + return KResult(EFAULT); + return nread; +} + +UNMAP_AFTER_INIT DMIEntryPointExposedBlob::DMIEntryPointExposedBlob(PhysicalAddress dmi_entry_point, size_t blob_size) + : BIOSExposedComponent("smbios_entry_point") + , m_dmi_entry_point(dmi_entry_point) + , m_dmi_entry_point_length(blob_size) +{ +} + +OwnPtr DMIEntryPointExposedBlob::try_to_generate_buffer() const +{ + auto dmi_blob = map_typed((m_dmi_entry_point), m_dmi_entry_point_length); + return KBuffer::try_create_with_bytes(Span { dmi_blob.ptr(), m_dmi_entry_point_length }); +} + +UNMAP_AFTER_INIT NonnullRefPtr SMBIOSExposedTable::create(PhysicalAddress smbios_structure_table, size_t smbios_structure_table_length) +{ + return adopt_ref(*new (nothrow) SMBIOSExposedTable(smbios_structure_table, smbios_structure_table_length)); +} + +UNMAP_AFTER_INIT SMBIOSExposedTable::SMBIOSExposedTable(PhysicalAddress smbios_structure_table, size_t smbios_structure_table_length) + : BIOSExposedComponent("DMI") + , m_smbios_structure_table(smbios_structure_table) + , m_smbios_structure_table_length(smbios_structure_table_length) +{ +} + +OwnPtr SMBIOSExposedTable::try_to_generate_buffer() const +{ + auto dmi_blob = map_typed((m_smbios_structure_table), m_smbios_structure_table_length); + return KBuffer::try_create_with_bytes(Span { dmi_blob.ptr(), m_smbios_structure_table_length }); +} + +UNMAP_AFTER_INIT void BIOSExposedFolder::set_dmi_64_bit_entry_initialization_values() +{ + dbgln("BIOSExposedFolder: SMBIOS 64bit Entry point @ {}", m_dmi_entry_point); + auto smbios_entry = map_typed(m_dmi_entry_point, SMBIOS_SEARCH_AREA_SIZE); + m_smbios_structure_table = PhysicalAddress(smbios_entry.ptr()->table_ptr); + m_dmi_entry_point_length = smbios_entry.ptr()->length; + m_smbios_structure_table_length = smbios_entry.ptr()->table_maximum_size; +} + +UNMAP_AFTER_INIT void BIOSExposedFolder::set_dmi_32_bit_entry_initialization_values() +{ + dbgln("BIOSExposedFolder: SMBIOS 32bit Entry point @ {}", m_dmi_entry_point); + auto smbios_entry = map_typed(m_dmi_entry_point, SMBIOS_SEARCH_AREA_SIZE); + m_smbios_structure_table = PhysicalAddress(smbios_entry.ptr()->legacy_structure.smbios_table_ptr); + m_dmi_entry_point_length = smbios_entry.ptr()->length; + m_smbios_structure_table_length = smbios_entry.ptr()->legacy_structure.smboios_table_length; +} + +UNMAP_AFTER_INIT void BIOSExposedFolder::initialize() +{ + auto bios_folder = adopt_ref(*new (nothrow) BIOSExposedFolder()); + SystemRegistrar::the().register_new_component(bios_folder); + bios_folder->create_components(); +} + +void BIOSExposedFolder::create_components() +{ + auto dmi_entry_point = DMIEntryPointExposedBlob::create(m_dmi_entry_point, m_dmi_entry_point_length); + m_components.append(dmi_entry_point); + auto smbios_table = SMBIOSExposedTable::create(m_smbios_structure_table, m_smbios_structure_table_length); + m_components.append(smbios_table); +} + +size_t BIOSExposedFolder::dmi_entry_point_length() const +{ + return m_dmi_entry_point_length; +} +size_t BIOSExposedFolder::smbios_structure_table_length() const +{ + return m_smbios_structure_table_length; +} + +UNMAP_AFTER_INIT void BIOSExposedFolder::initialize_dmi_exposer() +{ + VERIFY(!(m_dmi_entry_point.is_null())); + if (m_using_64bit_dmi_entry_point) { + set_dmi_64_bit_entry_initialization_values(); + } else { + set_dmi_32_bit_entry_initialization_values(); + } + dbgln("BIOSExposedFolder: Data table @ {}", m_smbios_structure_table); +} + +OwnPtr BIOSExposedFolder::smbios_structure_table() const +{ + auto dmi_blob = map_typed(m_smbios_structure_table, m_smbios_structure_table_length); + return KBuffer::try_create_with_bytes(Span { dmi_blob.ptr(), m_smbios_structure_table_length }); +} + +UNMAP_AFTER_INIT BIOSExposedFolder::BIOSExposedFolder() + : SystemExposedFolder("bios", SystemRegistrar::the().root_folder()) +{ + auto entry_32bit = find_dmi_entry32bit_point(); + m_dmi_entry_point = entry_32bit.value(); + + auto entry_64bit = find_dmi_entry64bit_point(); + if (entry_64bit.has_value()) { + m_dmi_entry_point = entry_64bit.value(); + m_using_64bit_dmi_entry_point = true; + } + if (m_dmi_entry_point.is_null()) + return; + initialize_dmi_exposer(); +} + +UNMAP_AFTER_INIT Optional BIOSExposedFolder::find_dmi_entry64bit_point() +{ + return map_bios().find_chunk_starting_with("_SM3_", 16); +} + +UNMAP_AFTER_INIT Optional BIOSExposedFolder::find_dmi_entry32bit_point() +{ + return map_bios().find_chunk_starting_with("_SM_", 16); +} + MappedROM map_bios() { MappedROM mapping; diff --git a/Kernel/Arch/PC/BIOS.h b/Kernel/Arch/PC/BIOS.h index a3289d47b0..39bc11c73d 100644 --- a/Kernel/Arch/PC/BIOS.h +++ b/Kernel/Arch/PC/BIOS.h @@ -1,16 +1,123 @@ /* * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2021, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include +#include +#include +#include +#include #include +#include +#include + +namespace Kernel::SMBIOS { + +struct [[gnu::packed]] LegacyEntryPoint32bit { + char legacy_sig[5]; + u8 checksum2; + u16 smboios_table_length; + u32 smbios_table_ptr; + u16 smbios_tables_count; + u8 smbios_bcd_revision; +}; + +struct [[gnu::packed]] EntryPoint32bit { + char sig[4]; + u8 checksum; + u8 length; + u8 major_version; + u8 minor_version; + u16 maximum_structure_size; + u8 implementation_revision; + char formatted_area[5]; + LegacyEntryPoint32bit legacy_structure; +}; + +struct [[gnu::packed]] EntryPoint64bit { + char sig[5]; + u8 checksum; + u8 length; + u8 major_version; + u8 minor_version; + u8 document_revision; + u8 revision; + u8 reserved; + u32 table_maximum_size; + u64 table_ptr; +}; +} namespace Kernel { MappedROM map_bios(); MappedROM map_ebda(); +class BIOSExposedComponent : public SystemExposedComponent { +public: + virtual KResultOr read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const override; + +protected: + virtual OwnPtr try_to_generate_buffer() const = 0; + explicit BIOSExposedComponent(String name); +}; + +class DMIEntryPointExposedBlob : public BIOSExposedComponent { +public: + static NonnullRefPtr create(PhysicalAddress dmi_entry_point, size_t blob_size); + virtual size_t size() const override { return m_dmi_entry_point_length; } + +private: + DMIEntryPointExposedBlob(PhysicalAddress dmi_entry_point, size_t blob_size); + virtual OwnPtr try_to_generate_buffer() const override; + PhysicalAddress m_dmi_entry_point; + size_t m_dmi_entry_point_length; +}; + +class SMBIOSExposedTable : public BIOSExposedComponent { +public: + static NonnullRefPtr create(PhysicalAddress, size_t blob_size); + virtual size_t size() const override { return m_smbios_structure_table_length; } + +private: + SMBIOSExposedTable(PhysicalAddress dmi_entry_point, size_t blob_size); + virtual OwnPtr try_to_generate_buffer() const override; + + PhysicalAddress m_smbios_structure_table; + size_t m_smbios_structure_table_length; +}; + +class BIOSExposedFolder : public SystemExposedFolder { +public: + static void initialize(); + + void create_components(); + +private: + OwnPtr dmi_entry_point() const; + OwnPtr smbios_structure_table() const; + size_t dmi_entry_point_length() const; + size_t smbios_structure_table_length() const; + + BIOSExposedFolder(); + + void set_dmi_64_bit_entry_initialization_values(); + void set_dmi_32_bit_entry_initialization_values(); + void initialize_dmi_exposer(); + + Optional find_dmi_entry64bit_point(); + Optional find_dmi_entry32bit_point(); + + PhysicalAddress m_dmi_entry_point; + PhysicalAddress m_smbios_structure_table; + bool m_using_64bit_dmi_entry_point { false }; + size_t m_smbios_structure_table_length { 0 }; + size_t m_dmi_entry_point_length { 0 }; +}; + } diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index d991bac2e9..9652fbace8 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -30,7 +30,6 @@ set(KERNEL_SOURCES CommandLine.cpp ConsoleDevice.cpp CoreDump.cpp - DMI.cpp Devices/AsyncDeviceRequest.cpp Devices/BlockDevice.cpp Devices/CharacterDevice.cpp @@ -107,6 +106,7 @@ set(KERNEL_SOURCES FileSystem/InodeWatcher.cpp FileSystem/Plan9FileSystem.cpp FileSystem/ProcFS.cpp + FileSystem/SysFS.cpp FileSystem/TmpFS.cpp FileSystem/VirtualFileSystem.cpp FutexQueue.cpp @@ -225,6 +225,7 @@ set(KERNEL_SOURCES Syscalls/waitid.cpp Syscalls/inode_watcher.cpp Syscalls/write.cpp + SystemExposed.cpp TTY/ConsoleManagement.cpp TTY/MasterPTY.cpp TTY/PTYMultiplexer.cpp diff --git a/Kernel/DMI.cpp b/Kernel/DMI.cpp deleted file mode 100644 index 8d821c3287..0000000000 --- a/Kernel/DMI.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel { - -#define SMBIOS_BASE_SEARCH_ADDR 0xf0000 -#define SMBIOS_END_SEARCH_ADDR 0xfffff -#define SMBIOS_SEARCH_AREA_SIZE (SMBIOS_END_SEARCH_ADDR - SMBIOS_BASE_SEARCH_ADDR) - -AK::Singleton s_the; - -UNMAP_AFTER_INIT void DMIExpose::set_64_bit_entry_initialization_values() -{ - dbgln("DMIExpose: SMBIOS 64bit Entry point @ {}", m_entry_point); - auto smbios_entry = map_typed(m_entry_point, SMBIOS_SEARCH_AREA_SIZE); - m_structure_table = PhysicalAddress(smbios_entry.ptr()->table_ptr); - m_entry_point_length = smbios_entry.ptr()->length; - m_structure_table_length = smbios_entry.ptr()->table_maximum_size; -} - -UNMAP_AFTER_INIT void DMIExpose::set_32_bit_entry_initialization_values() -{ - dbgln("DMIExpose: SMBIOS 32bit Entry point @ {}", m_entry_point); - auto smbios_entry = map_typed(m_entry_point, SMBIOS_SEARCH_AREA_SIZE); - m_structure_table = PhysicalAddress(smbios_entry.ptr()->legacy_structure.smbios_table_ptr); - m_entry_point_length = smbios_entry.ptr()->length; - m_structure_table_length = smbios_entry.ptr()->legacy_structure.smboios_table_length; -} - -UNMAP_AFTER_INIT void DMIExpose::initialize() -{ - s_the.ensure_instance(); -} - -DMIExpose& DMIExpose::the() -{ - return *s_the; -} - -size_t DMIExpose::entry_point_length() const -{ - return m_entry_point_length; -} -size_t DMIExpose::structure_table_length() const -{ - return m_structure_table_length; -} - -UNMAP_AFTER_INIT void DMIExpose::initialize_exposer() -{ - VERIFY(!(m_entry_point.is_null())); - if (m_using_64bit_entry_point) { - set_64_bit_entry_initialization_values(); - } else { - set_32_bit_entry_initialization_values(); - } - dbgln("DMIExpose: Data table @ {}", m_structure_table); -} - -OwnPtr DMIExpose::entry_point() const -{ - auto dmi_blob = map_typed((m_entry_point), m_entry_point_length); - return KBuffer::try_create_with_bytes(Span { dmi_blob.ptr(), m_entry_point_length }); -} -OwnPtr DMIExpose::structure_table() const -{ - auto dmi_blob = map_typed(m_structure_table, m_structure_table_length); - return KBuffer::try_create_with_bytes(Span { dmi_blob.ptr(), m_structure_table_length }); -} - -UNMAP_AFTER_INIT DMIExpose::DMIExpose() -{ - auto entry_32bit = find_entry32bit_point(); - m_entry_point = entry_32bit.value(); - - auto entry_64bit = find_entry64bit_point(); - if (entry_64bit.has_value()) { - m_entry_point = entry_64bit.value(); - m_using_64bit_entry_point = true; - } - if (m_entry_point.is_null()) - return; - m_available = true; - initialize_exposer(); -} - -UNMAP_AFTER_INIT Optional DMIExpose::find_entry64bit_point() -{ - return map_bios().find_chunk_starting_with("_SM3_", 16); -} - -UNMAP_AFTER_INIT Optional DMIExpose::find_entry32bit_point() -{ - return map_bios().find_chunk_starting_with("_SM_", 16); -} - -} diff --git a/Kernel/DMI.h b/Kernel/DMI.h deleted file mode 100644 index 90c0cee305..0000000000 --- a/Kernel/DMI.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel::SMBIOS { - -struct [[gnu::packed]] LegacyEntryPoint32bit { - char legacy_sig[5]; - u8 checksum2; - u16 smboios_table_length; - u32 smbios_table_ptr; - u16 smbios_tables_count; - u8 smbios_bcd_revision; -}; - -struct [[gnu::packed]] EntryPoint32bit { - char sig[4]; - u8 checksum; - u8 length; - u8 major_version; - u8 minor_version; - u16 maximum_structure_size; - u8 implementation_revision; - char formatted_area[5]; - LegacyEntryPoint32bit legacy_structure; -}; - -struct [[gnu::packed]] EntryPoint64bit { - char sig[5]; - u8 checksum; - u8 length; - u8 major_version; - u8 minor_version; - u8 document_revision; - u8 revision; - u8 reserved; - u32 table_maximum_size; - u64 table_ptr; -}; -} - -namespace Kernel { - -class DMIExpose { - -public: - static void initialize(); - - DMIExpose(); - - static DMIExpose& the(); - - bool is_available() const { return m_available; } - OwnPtr entry_point() const; - OwnPtr structure_table() const; - size_t entry_point_length() const; - size_t structure_table_length() const; - -private: - void set_64_bit_entry_initialization_values(); - void set_32_bit_entry_initialization_values(); - void initialize_exposer(); - - Optional find_entry64bit_point(); - Optional find_entry32bit_point(); - - PhysicalAddress m_entry_point; - PhysicalAddress m_structure_table; - bool m_using_64bit_entry_point { false }; - bool m_available { false }; - size_t m_structure_table_length { 0 }; - size_t m_entry_point_length { 0 }; -}; - -} diff --git a/Kernel/FileSystem/SysFS.cpp b/Kernel/FileSystem/SysFS.cpp new file mode 100644 index 0000000000..09cb9ec78d --- /dev/null +++ b/Kernel/FileSystem/SysFS.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +static InodeIndex s_next_inode_index; +static AK::Singleton s_the; + +SystemRegistrar& SystemRegistrar::the() +{ + return *s_the; +} + +UNMAP_AFTER_INIT void SystemRegistrar::initialize() +{ + VERIFY(!s_the.is_initialized()); + s_next_inode_index = 0; + s_the.ensure_instance(); +} + +UNMAP_AFTER_INIT SystemRegistrar::SystemRegistrar() + : m_root_folder(SysFSRootFolder::create()) +{ +} + +UNMAP_AFTER_INIT void SystemRegistrar::register_new_component(SystemExposedComponent& component) +{ + Locker locker(m_lock); + m_root_folder->m_components.append(component); +} + +NonnullRefPtr SysFSRootFolder::create() +{ + return adopt_ref(*new (nothrow) SysFSRootFolder); +} + +KResult SysFSRootFolder::traverse_as_directory(unsigned fsid, Function callback) const +{ + Locker locker(SystemRegistrar::the().m_lock); + callback({ ".", { fsid, component_index() }, 0 }); + callback({ "..", { fsid, 0 }, 0 }); + + for (auto& component : m_components) { + InodeIdentifier identifier = { fsid, component.component_index() }; + callback({ component.name(), identifier, 0 }); + } + return KSuccess; +} + +SysFSRootFolder::SysFSRootFolder() + : SystemExposedFolder(".") +{ +} + +NonnullRefPtr SysFS::create() +{ + return adopt_ref(*new (nothrow) SysFS); +} + +SysFS::SysFS() + : m_root_inode(SystemRegistrar::the().m_root_folder->to_inode(*this)) +{ + Locker locker(m_lock); +} + +SysFS::~SysFS() +{ +} + +bool SysFS::initialize() +{ + return true; +} + +NonnullRefPtr SysFS::root_inode() const +{ + return *m_root_inode; +} + +NonnullRefPtr SysFSInode::create(const SysFS& fs, const SystemExposedComponent& component) +{ + return adopt_ref(*new (nothrow) SysFSInode(fs, component)); +} + +SysFSInode::SysFSInode(const SysFS& fs, const SystemExposedComponent& component) + : Inode(const_cast(fs), component.component_index()) + , m_associated_component(component) +{ +} + +KResultOr SysFSInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* fd) const +{ + return m_associated_component->read_bytes(offset, count, buffer, fd); +} + +KResult SysFSInode::traverse_as_directory(Function) const +{ + VERIFY_NOT_REACHED(); +} + +RefPtr SysFSInode::lookup(StringView) +{ + VERIFY_NOT_REACHED(); +} + +InodeMetadata SysFSInode::metadata() const +{ + Locker locker(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), m_associated_component->component_index() }; + metadata.mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = m_associated_component->size(); + metadata.mtime = mepoch; + return metadata; +} + +void SysFSInode::flush_metadata() +{ +} + +KResultOr SysFSInode::write_bytes(off_t offset, size_t count, const UserOrKernelBuffer& buffer, FileDescription* fd) +{ + return m_associated_component->write_bytes(offset, count, buffer, fd); +} + +KResultOr> SysFSInode::create_child(const String&, mode_t, dev_t, uid_t, gid_t) +{ + return EROFS; +} + +KResult SysFSInode::add_child(Inode&, const StringView&, mode_t) +{ + return EROFS; +} + +KResult SysFSInode::remove_child(const StringView&) +{ + return EROFS; +} + +KResultOr SysFSInode::directory_entry_count() const +{ + VERIFY_NOT_REACHED(); +} + +KResult SysFSInode::chmod(mode_t) +{ + return EPERM; +} + +KResult SysFSInode::chown(uid_t, gid_t) +{ + return EPERM; +} + +KResult SysFSInode::truncate(u64) +{ + return EPERM; +} + +NonnullRefPtr SysFSDirectoryInode::create(const SysFS& sysfs, const SystemExposedComponent& component) +{ + return adopt_ref(*new (nothrow) SysFSDirectoryInode(sysfs, component)); +} + +SysFSDirectoryInode::SysFSDirectoryInode(const SysFS& fs, const SystemExposedComponent& component) + : SysFSInode(fs, component) + , m_parent_fs(const_cast(fs)) +{ +} + +SysFSDirectoryInode::~SysFSDirectoryInode() +{ +} +InodeMetadata SysFSDirectoryInode::metadata() const +{ + Locker locker(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), m_associated_component->component_index() }; + metadata.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXOTH; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = 0; + metadata.mtime = mepoch; + return metadata; +} +KResult SysFSDirectoryInode::traverse_as_directory(Function callback) const +{ + Locker locker(m_parent_fs.m_lock); + return m_associated_component->traverse_as_directory(m_parent_fs.fsid(), move(callback)); +} + +RefPtr SysFSDirectoryInode::lookup(StringView name) +{ + Locker locker(m_parent_fs.m_lock); + auto component = m_associated_component->lookup(name); + if (!component) + return {}; + return component->to_inode(m_parent_fs); +} + +KResultOr SysFSDirectoryInode::directory_entry_count() const +{ + Locker locker(m_lock); + return m_associated_component->entries_count(); +} + +} diff --git a/Kernel/FileSystem/SysFS.h b/Kernel/FileSystem/SysFS.h new file mode 100644 index 0000000000..97269d624a --- /dev/null +++ b/Kernel/FileSystem/SysFS.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class SysFS; +class SysFSInode; +class SysFSDirectoryInode; + +class SysFSRootFolder final : public SystemExposedFolder { + friend class SystemRegistrar; + +public: + static NonnullRefPtr create(); + virtual KResult traverse_as_directory(unsigned, Function) const override; + +private: + SysFSRootFolder(); +}; + +class SystemRegistrar { + friend class SysFS; + friend class SystemExposedComponent; + friend class SystemExposedFolder; + friend class SysFSRootFolder; + +public: + static SystemRegistrar& the(); + + static void initialize(); + + SystemRegistrar(); + void register_new_component(SystemExposedComponent&); + + NonnullRefPtr root_folder() { return m_root_folder; } + +private: + Lock m_lock; + NonnullRefPtr m_root_folder; +}; + +class SysFS final : public FS { + friend class SysFSInode; + friend class SysFSDirectoryInode; + +public: + virtual ~SysFS() override; + static NonnullRefPtr create(); + + virtual bool initialize() override; + virtual const char* class_name() const override { return "SysFS"; } + + virtual NonnullRefPtr root_inode() const override; + +private: + SysFS(); + + NonnullRefPtr m_root_inode; +}; + +class SysFSInode : public Inode { + friend class SysFS; + friend class SysFSDirectoryInode; + +public: + static NonnullRefPtr create(const SysFS&, const SystemExposedComponent&); + StringView name() const { return m_associated_component->name(); } + +protected: + SysFSInode(const SysFS&, const SystemExposedComponent&); + virtual KResultOr read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override; + virtual KResult traverse_as_directory(Function) const override; + virtual RefPtr lookup(StringView name) override; + virtual void flush_metadata() override; + virtual InodeMetadata metadata() const override; + virtual KResultOr write_bytes(off_t, size_t, const UserOrKernelBuffer& buffer, FileDescription*) override; + virtual KResultOr> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; + virtual KResult add_child(Inode&, const StringView& name, mode_t) override; + virtual KResult remove_child(const StringView& name) override; + virtual KResultOr directory_entry_count() const override; + virtual KResult chmod(mode_t) override; + virtual KResult chown(uid_t, gid_t) override; + virtual KResult truncate(u64) override; + + NonnullRefPtr m_associated_component; +}; + +class SysFSDirectoryInode : public SysFSInode { + friend class SysFS; + friend class SysFSRootDirectoryInode; + +public: + static NonnullRefPtr create(const SysFS&, const SystemExposedComponent&); + virtual ~SysFSDirectoryInode() override; + +protected: + SysFSDirectoryInode(const SysFS&, const SystemExposedComponent&); + // ^Inode + virtual InodeMetadata metadata() const override; + virtual KResult traverse_as_directory(Function) const override; + virtual RefPtr lookup(StringView name) override; + virtual KResultOr directory_entry_count() const override; + + SysFS& m_parent_fs; +}; + +} diff --git a/Kernel/Syscalls/mount.cpp b/Kernel/Syscalls/mount.cpp index c6b9f7c5b8..f42c1bb213 100644 --- a/Kernel/Syscalls/mount.cpp +++ b/Kernel/Syscalls/mount.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,8 @@ KResultOr Process::sys$mount(Userspace fs = DevPtsFS::create(); } else if (fs_type == "dev" || fs_type == "DevFS") { fs = DevFS::create(); + } else if (fs_type == "sys" || fs_type == "SysFS") { + fs = SysFS::create(); } else if (fs_type == "tmp" || fs_type == "TmpFS") { fs = TmpFS::create(); } else { diff --git a/Kernel/SystemExposed.cpp b/Kernel/SystemExposed.cpp new file mode 100644 index 0000000000..12598dad7d --- /dev/null +++ b/Kernel/SystemExposed.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Kernel { + +static SpinLock s_index_lock; +static InodeIndex s_next_inode_index { 0 }; + +static size_t allocate_inode_index() +{ + ScopedSpinLock lock(s_index_lock); + s_next_inode_index = s_next_inode_index.value() + 1; + VERIFY(s_next_inode_index > 0); + return s_next_inode_index.value(); +} + +SystemExposedComponent::SystemExposedComponent(StringView name) + : m_name(KString::try_create(name).release_nonnull()) + , m_component_index(allocate_inode_index()) +{ +} + +KResult SystemExposedFolder::traverse_as_directory(unsigned fsid, Function callback) const +{ + Locker locker(SystemRegistrar::the().m_lock); + VERIFY(m_parent_folder); + callback({ ".", { fsid, component_index() }, 0 }); + callback({ "..", { fsid, m_parent_folder->component_index() }, 0 }); + + for (auto& component : m_components) { + InodeIdentifier identifier = { fsid, component.component_index() }; + callback({ component.name(), identifier, 0 }); + } + return KSuccess; +} + +RefPtr SystemExposedFolder::lookup(StringView name) +{ + for (auto& component : m_components) { + if (component.name() == name) { + return component; + } + } + return {}; +} + +SystemExposedFolder::SystemExposedFolder(String name) + : SystemExposedComponent(name) +{ +} + +SystemExposedFolder::SystemExposedFolder(String name, const SystemExposedFolder& parent_folder) + : SystemExposedComponent(name) + , m_parent_folder(parent_folder) +{ +} + +NonnullRefPtr SystemExposedFolder::to_inode(const SysFS& sysfs_instance) const +{ + return SysFSDirectoryInode::create(sysfs_instance, *this); +} + +NonnullRefPtr SystemExposedComponent::to_inode(const SysFS& sysfs_instance) const +{ + return SysFSInode::create(sysfs_instance, *this); +} + +} diff --git a/Kernel/SystemExposed.h b/Kernel/SystemExposed.h new file mode 100644 index 0000000000..6ef0f29305 --- /dev/null +++ b/Kernel/SystemExposed.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class SysFS; +class SystemExposedComponent : public RefCounted { +public: + virtual KResultOr entries_count() const { VERIFY_NOT_REACHED(); }; + virtual StringView name() const { return m_name->view(); } + virtual KResultOr read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const { VERIFY_NOT_REACHED(); } + virtual KResult traverse_as_directory(unsigned, Function) const { VERIFY_NOT_REACHED(); } + virtual RefPtr lookup(StringView) { VERIFY_NOT_REACHED(); }; + virtual KResultOr write_bytes(off_t, size_t, const UserOrKernelBuffer&, FileDescription*) { return -EROFS; } + virtual size_t size() const { return 0; } + + virtual NonnullRefPtr to_inode(const SysFS& sysfs_instance) const; + + size_t component_index() const { return m_component_index; }; + + virtual ~SystemExposedComponent() = default; + +protected: + explicit SystemExposedComponent(StringView name); + +private: + NonnullOwnPtr m_name; + size_t m_component_index; +}; + +class SystemExposedFolder : public SystemExposedComponent { +public: + virtual KResultOr entries_count() const override { return m_components.size(); }; + virtual KResult traverse_as_directory(unsigned, Function) const override; + virtual RefPtr lookup(StringView name) override; + void add_component(const SystemExposedComponent&); + + virtual NonnullRefPtr to_inode(const SysFS& sysfs_instance) const override final; + +protected: + explicit SystemExposedFolder(String name); + SystemExposedFolder(String name, const SystemExposedFolder& parent_folder); + NonnullRefPtrVector m_components; + RefPtr m_parent_folder; +}; + +} diff --git a/Kernel/init.cpp b/Kernel/init.cpp index f67bb8bd86..10e4e8b1eb 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -146,6 +147,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init() ACPI::initialize(); // Initialize the PCI Bus as early as possible, for early boot (PCI based) serial logging + SystemRegistrar::initialize(); PCI::initialize(); PCISerialDevice::detect(); @@ -237,7 +239,8 @@ void init_stage2(void*) USB::UHCIController::detect(); - DMIExpose::initialize(); + BIOSExposedFolder::initialize(); + ACPI::ExposedFolder::initialize(); VirtIO::detect();