From 469f20d4eed659ecd382b93644f25757e09431c7 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 19 Dec 2020 15:25:06 +0200 Subject: [PATCH] Kernel: Introduce the StorageManagement class The StorageManagement class has 2 roles: 1. During boot, it should find all storage controllers in the machine, and then determine what is the boot device. 2. Later on boot, it is a registrar of all storage controllers and storage devices. Thus, it could be used to show information about these devices when implemented. This change allows the user to specify a boot driver other than /dev/hda and if it's connected in the machine - it will boot. --- Kernel/CMakeLists.txt | 1 + Kernel/Storage/StorageManagement.cpp | 120 +++++++++++++++++++++++++++ Kernel/Storage/StorageManagement.h | 58 +++++++++++++ Kernel/init.cpp | 19 +---- 4 files changed, 182 insertions(+), 16 deletions(-) create mode 100644 Kernel/Storage/StorageManagement.cpp create mode 100644 Kernel/Storage/StorageManagement.h diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index cae5f5dec26ea2..c5497e7303d2da 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -43,6 +43,7 @@ set(KERNEL_SOURCES Storage/IDEController.cpp Storage/IDEChannel.cpp Storage/PATADiskDevice.cpp + Storage/StorageManagement.cpp DoubleBuffer.cpp FileSystem/BlockBasedFileSystem.cpp FileSystem/Custody.cpp diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp new file mode 100644 index 00000000000000..78ae8974d0b677 --- /dev/null +++ b/Kernel/Storage/StorageManagement.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, 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 +#include +#include +#include + +namespace Kernel { + +static StorageManagement* s_the; + +StorageManagement::StorageManagement(String root_device, bool force_pio) + : m_controllers(enumerate_controllers(force_pio)) + , m_boot_device(determine_boot_device(root_device)) +{ +} + +NonnullRefPtr StorageManagement::determine_boot_device(String root_device) const +{ + ASSERT(!m_controllers.is_empty()); + if (!root_device.starts_with("/dev/hd")) { + klog() << "init_stage2: root filesystem must be on an hard drive"; + Processor::halt(); + } + auto drive_letter = root_device.substring(strlen("/dev/hd"), root_device.length() - strlen("/dev/hd"))[0]; + + if (drive_letter < 'a' || drive_letter > 'z') { + klog() << "init_stage2: root filesystem must be on an hard drive name"; + Processor::halt(); + } + + size_t drive_index = (u8)drive_letter - (u8)'a'; + auto devices = storage_devices(); + if (drive_index >= devices.size()) { + klog() << "init_stage2: invalid selection of hard drive."; + Processor::halt(); + } + return devices[drive_index]; +} + +NonnullRefPtrVector StorageManagement::enumerate_controllers(bool force_pio) const +{ + NonnullRefPtrVector controllers; + PCI::enumerate([&](const PCI::Address& address, PCI::ID) { + if (PCI::get_class(address) == 0x1 && PCI::get_subclass(address) == 0x1) { + controllers.append(IDEController::initialize(address, force_pio)); + } + }); + return controllers; +} + +NonnullRefPtrVector StorageManagement::storage_devices() const +{ + NonnullRefPtrVector devices; + for (auto& controller : m_controllers) { + for (size_t index = 0; index < controller.devices_count(); index++) { + auto device = controller.device(index); + if (device.is_null()) + continue; + devices.append(device.release_nonnull()); + } + } + return devices; +} + +bool StorageManagement::initialized() +{ + return (s_the != nullptr); +} + +void StorageManagement::initialize(String root_device, bool force_pio) +{ + ASSERT(!StorageManagement::initialized()); + s_the = new StorageManagement(root_device, force_pio); +} + +StorageManagement& StorageManagement::the() +{ + return *s_the; +} + +NonnullRefPtr StorageManagement::boot_device() const +{ + return m_boot_device; +} +NonnullRefPtrVector StorageManagement::ide_controllers() const +{ + NonnullRefPtrVector ide_controllers; + for (auto& controller : m_controllers) { + if (controller.type() == StorageController::Type::IDE) + ide_controllers.append(controller); + } + return ide_controllers; +} + +} diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h new file mode 100644 index 00000000000000..c20b2fc698cece --- /dev/null +++ b/Kernel/Storage/StorageManagement.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, 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 +#include + +namespace Kernel { + +class StorageManagement { + AK_MAKE_ETERNAL; + +public: + StorageManagement(String root_device, bool force_pio); + static bool initialized(); + static void initialize(String root_device, bool force_pio); + static StorageManagement& the(); + + NonnullRefPtr boot_device() const; + NonnullRefPtrVector ide_controllers() const; + NonnullRefPtrVector storage_devices() const; + +private: + NonnullRefPtrVector enumerate_controllers(bool force_pio) const; + NonnullRefPtr determine_boot_device(String root_device) const; + + NonnullRefPtrVector m_controllers; + NonnullRefPtr m_boot_device; +}; + +} diff --git a/Kernel/init.cpp b/Kernel/init.cpp index fa119c8e876868..9beeb587618232 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -65,8 +65,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -271,20 +270,8 @@ void init_stage2(void*) auto root = kernel_command_line().lookup("root").value_or("/dev/hda"); - if (!root.starts_with("/dev/hda")) { - klog() << "init_stage2: root filesystem must be on the first IDE hard drive (/dev/hda)"; - Processor::halt(); - } - - RefPtr checked_root_dev; - PCI::enumerate([&](const PCI::Address& address, PCI::ID) { - if (PCI::get_class(address) == 0x1 && PCI::get_subclass(address) == 0x1) { - auto pata0 = IDEController::initialize(address, force_pio); - checked_root_dev = *pata0->device(0); - } - }); - ASSERT(!checked_root_dev.is_null()); - NonnullRefPtr root_dev = checked_root_dev.release_nonnull(); + StorageManagement::initialize(root, force_pio); + NonnullRefPtr root_dev = StorageManagement::the().boot_device(); root = root.substring(strlen("/dev/hda"), root.length() - strlen("/dev/hda"));