diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index f443adfdfb..8225254504 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -102,6 +102,8 @@ set(KERNEL_SOURCES Storage/NVMe/NVMeInterruptQueue.cpp Storage/NVMe/NVMePollQueue.cpp Storage/NVMe/NVMeQueue.cpp + Storage/Ramdisk/Controller.cpp + Storage/Ramdisk/Device.cpp Storage/DiskPartition.cpp Storage/StorageController.cpp Storage/StorageDevice.cpp diff --git a/Kernel/Storage/Ramdisk/Controller.cpp b/Kernel/Storage/Ramdisk/Controller.cpp new file mode 100644 index 0000000000..495c070836 --- /dev/null +++ b/Kernel/Storage/Ramdisk/Controller.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel { + +NonnullLockRefPtr RamdiskController::initialize() +{ + return adopt_lock_ref(*new RamdiskController()); +} + +bool RamdiskController::reset() +{ + TODO(); +} + +bool RamdiskController::shutdown() +{ + TODO(); +} + +size_t RamdiskController::devices_count() const +{ + return m_devices.size(); +} + +void RamdiskController::complete_current_request(AsyncDeviceRequest::RequestResult) +{ + VERIFY_NOT_REACHED(); +} + +RamdiskController::RamdiskController() + : StorageController(0) +{ + // Populate ramdisk controllers from Multiboot boot modules, if any. + size_t count = 0; + MM.for_each_used_memory_range([&](auto& used_memory_range) { + if (used_memory_range.type == Memory::UsedMemoryRangeType::BootModule) { + size_t length = Memory::page_round_up(used_memory_range.end.get()).release_value_but_fixme_should_propagate_errors() - used_memory_range.start.get(); + auto region_or_error = MM.allocate_kernel_region(used_memory_range.start, length, "Ramdisk"sv, Memory::Region::Access::ReadWrite); + if (region_or_error.is_error()) { + dmesgln("RamdiskController: Failed to allocate kernel region of size {}", length); + } else { + m_devices.append(RamdiskDevice::create(*this, region_or_error.release_value(), 6, count)); + } + count++; + } + }); +} + +RamdiskController::~RamdiskController() = default; + +LockRefPtr RamdiskController::device(u32 index) const +{ + if (index >= m_devices.size()) + return nullptr; + return m_devices[index]; +} + +} diff --git a/Kernel/Storage/Ramdisk/Controller.h b/Kernel/Storage/Ramdisk/Controller.h new file mode 100644 index 0000000000..56c31a0c03 --- /dev/null +++ b/Kernel/Storage/Ramdisk/Controller.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class AsyncBlockDeviceRequest; + +class RamdiskController final : public StorageController { +public: + static NonnullLockRefPtr initialize(); + virtual ~RamdiskController() override; + + virtual LockRefPtr device(u32 index) const override; + virtual bool reset() override; + virtual bool shutdown() override; + virtual size_t devices_count() const override; + virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override; + +private: + RamdiskController(); + + NonnullLockRefPtrVector m_devices; +}; +} diff --git a/Kernel/Storage/Ramdisk/Device.cpp b/Kernel/Storage/Ramdisk/Device.cpp new file mode 100644 index 0000000000..08033bb0a1 --- /dev/null +++ b/Kernel/Storage/Ramdisk/Device.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +NonnullLockRefPtr RamdiskDevice::create(RamdiskController const& controller, NonnullOwnPtr&& region, int major, int minor) +{ + auto device_or_error = DeviceManagement::try_create_device(controller, move(region), major, minor); + // FIXME: Find a way to propagate errors + VERIFY(!device_or_error.is_error()); + return device_or_error.release_value(); +} + +RamdiskDevice::RamdiskDevice(RamdiskController const& controller, NonnullOwnPtr&& region, int major, int minor) + : StorageDevice({}, LUNAddress { controller.controller_id(), 0, 0 }, 0, major, minor, 512, region->size() / 512) + , m_region(move(region)) +{ + dmesgln("Ramdisk: Device #{} @ {}, Capacity={}", minor, m_region->vaddr(), max_addressable_block() * 512); +} + +RamdiskDevice::~RamdiskDevice() = default; + +StringView RamdiskDevice::class_name() const +{ + return "RamdiskDevice"sv; +} + +void RamdiskDevice::start_request(AsyncBlockDeviceRequest& request) +{ + MutexLocker locker(m_lock); + + u8* base = m_region->vaddr().as_ptr(); + size_t size = m_region->size(); + u8* offset = base + request.block_index() * request.block_size(); + size_t length = request.buffer_size(); + + if ((offset + length > base + size) || (offset + length < base)) { + request.complete(AsyncDeviceRequest::Failure); + } else { + ErrorOr result; + if (request.request_type() == AsyncBlockDeviceRequest::Read) { + result = request.buffer().write(offset, length); + } else { + result = request.buffer().read(offset, length); + } + request.complete(!result.is_error() ? AsyncDeviceRequest::Success : AsyncDeviceRequest::MemoryFault); + } +} + +} diff --git a/Kernel/Storage/Ramdisk/Device.h b/Kernel/Storage/Ramdisk/Device.h new file mode 100644 index 0000000000..28759bbc9a --- /dev/null +++ b/Kernel/Storage/Ramdisk/Device.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel { + +class RamdiskController; + +class RamdiskDevice final : public StorageDevice { + friend class RamdiskController; + friend class DeviceManagement; + +public: + static NonnullLockRefPtr create(RamdiskController const&, NonnullOwnPtr&& region, int major, int minor); + virtual ~RamdiskDevice() override; + + // ^DiskDevice + virtual StringView class_name() const override; + +private: + RamdiskDevice(RamdiskController const&, NonnullOwnPtr&&, int major, int minor); + + // ^BlockDevice + virtual void start_request(AsyncBlockDeviceRequest&) override; + + // ^StorageDevice + virtual CommandSet command_set() const override { return CommandSet::PlainMemory; } + + Mutex m_lock { "RamdiskDevice"sv }; + + NonnullOwnPtr m_region; +}; + +} diff --git a/Kernel/Storage/StorageDevice.cpp b/Kernel/Storage/StorageDevice.cpp index 6a36f8ad3b..091d354602 100644 --- a/Kernel/Storage/StorageDevice.cpp +++ b/Kernel/Storage/StorageDevice.cpp @@ -69,6 +69,8 @@ StringView StorageDevice::class_name() const StringView StorageDevice::command_set_to_string_view() const { switch (command_set()) { + case CommandSet::PlainMemory: + return "memory"sv; case CommandSet::SCSI: return "scsi"sv; case CommandSet::ATA: diff --git a/Kernel/Storage/StorageDevice.h b/Kernel/Storage/StorageDevice.h index 165f8904fe..7497e9637f 100644 --- a/Kernel/Storage/StorageDevice.h +++ b/Kernel/Storage/StorageDevice.h @@ -34,6 +34,7 @@ public: // and ATAPI is the exception to no-distinction rule. If we ever put SCSI support in the kernel, // we can create another enum class to put the distinction. enum class CommandSet { + PlainMemory, SCSI, ATA, NVMe, diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index 55b444f7fd..1689703ef6 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ static constexpr StringView block_device_prefix = "block"sv; static constexpr StringView ata_device_prefix = "ata"sv; static constexpr StringView nvme_device_prefix = "nvme"sv; +static constexpr StringView ramdisk_device_prefix = "ramdisk"sv; static constexpr StringView logical_unit_number_device_prefix = "lun"sv; UNMAP_AFTER_INIT StorageManagement::StorageManagement() @@ -286,6 +288,13 @@ UNMAP_AFTER_INIT void StorageManagement::determine_nvme_boot_device() }); } +UNMAP_AFTER_INIT void StorageManagement::determine_ramdisk_boot_device() +{ + determine_hardware_relative_boot_device(ramdisk_device_prefix, [](StorageDevice const& device) -> bool { + return device.command_set() == StorageDevice::CommandSet::PlainMemory; + }); +} + UNMAP_AFTER_INIT void StorageManagement::determine_block_boot_device() { VERIFY(m_boot_argument.starts_with(block_device_prefix)); @@ -345,6 +354,11 @@ UNMAP_AFTER_INIT void StorageManagement::determine_boot_device() return; } + if (m_boot_argument.starts_with(ramdisk_device_prefix)) { + determine_ramdisk_boot_device(); + return; + } + if (m_boot_argument.starts_with(nvme_device_prefix)) { determine_nvme_boot_device(); return; @@ -428,6 +442,9 @@ UNMAP_AFTER_INIT void StorageManagement::initialize(StringView root_device, bool } else { enumerate_pci_controllers(force_pio, poll); } + // Note: Whether PCI bus is present on the system or not, always try to attach + // a given ramdisk. + m_controllers.append(RamdiskController::initialize()); enumerate_storage_devices(); enumerate_disk_partitions(); diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h index 03fd573f77..46a8b743a4 100644 --- a/Kernel/Storage/StorageManagement.h +++ b/Kernel/Storage/StorageManagement.h @@ -52,6 +52,7 @@ private: void resolve_partition_from_boot_device_parameter(StorageDevice const& chosen_storage_device, StringView boot_device_prefix); void determine_boot_device_with_logical_unit_number(); void determine_block_boot_device(); + void determine_ramdisk_boot_device(); void determine_nvme_boot_device(); void determine_ata_boot_device(); void determine_hardware_relative_boot_device(StringView relative_hardware_prefix, Function filter_device_callback);