From 84a399de5d977009b07652bf2dfefaff163693f8 Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Wed, 3 Mar 2021 00:51:55 -0800 Subject: [PATCH] Kernel: Move Kernel CommandLine parsing to strongly typed API. Previously all of the CommandLine parsing was spread out around the Kernel. Instead move it all into the Kernel CommandLine class, and expose a strongly typed API for querying the state of options. --- Kernel/ACPI/Initialize.cpp | 22 +----- Kernel/CommandLine.cpp | 89 +++++++++++++++++++++++ Kernel/CommandLine.h | 36 ++++++++- Kernel/Devices/VMWareBackdoor.cpp | 2 +- Kernel/Interrupts/InterruptManagement.cpp | 2 +- Kernel/PCI/Initializer.cpp | 2 +- Kernel/Storage/StorageManagement.cpp | 2 +- Kernel/Time/TimeManagement.cpp | 12 +-- Kernel/init.cpp | 21 ++---- 9 files changed, 143 insertions(+), 45 deletions(-) diff --git a/Kernel/ACPI/Initialize.cpp b/Kernel/ACPI/Initialize.cpp index 8249549170..539b5992ee 100644 --- a/Kernel/ACPI/Initialize.cpp +++ b/Kernel/ACPI/Initialize.cpp @@ -31,33 +31,17 @@ namespace Kernel { namespace ACPI { -enum class FeatureLevel { - Enabled, - Limited, - Disabled, -}; - -UNMAP_AFTER_INIT static FeatureLevel determine_feature_level() -{ - auto value = kernel_command_line().lookup("acpi").value_or("on"); - if (value == "limited") - return FeatureLevel::Limited; - if (value == "off") - return FeatureLevel::Disabled; - return FeatureLevel::Enabled; -} - UNMAP_AFTER_INIT void initialize() { - auto feature_level = determine_feature_level(); - if (feature_level == FeatureLevel::Disabled) + auto feature_level = kernel_command_line().acpi_feature_level(); + if (feature_level == AcpiFeatureLevel::Disabled) return; auto rsdp = StaticParsing::find_rsdp(); if (!rsdp.has_value()) return; - if (feature_level == FeatureLevel::Enabled) + if (feature_level == AcpiFeatureLevel::Enabled) Parser::initialize(rsdp.value()); else Parser::initialize(rsdp.value()); diff --git a/Kernel/CommandLine.cpp b/Kernel/CommandLine.cpp index 2bc0679646..005cd6080f 100644 --- a/Kernel/CommandLine.cpp +++ b/Kernel/CommandLine.cpp @@ -25,6 +25,7 @@ */ #include +#include #include namespace Kernel { @@ -87,4 +88,92 @@ bool CommandLine::contains(const String& key) const return m_params.contains(key); } +UNMAP_AFTER_INIT bool CommandLine::is_ide_enabled() const +{ + return !contains("disable_ide"); +} + +UNMAP_AFTER_INIT bool CommandLine::is_smp_enabled() const +{ + return lookup("smp").value_or("off") == "on"; +} + +UNMAP_AFTER_INIT bool CommandLine::is_vmmouse_enabled() const +{ + return lookup("vmmouse").value_or("on") == "on"; +} + +UNMAP_AFTER_INIT bool CommandLine::is_mmio_enabled() const +{ + return lookup("pci_mmio").value_or("off") == "on"; +} + +UNMAP_AFTER_INIT bool CommandLine::is_legacy_time_enabled() const +{ + return lookup("time").value_or("modern") == "legacy"; +} + +UNMAP_AFTER_INIT bool CommandLine::is_force_pio() const +{ + return contains("force_pio"); +} + +UNMAP_AFTER_INIT String CommandLine::root_device() const +{ + return lookup("root").value_or("/dev/hda"); +} + +UNMAP_AFTER_INIT AcpiFeatureLevel CommandLine::acpi_feature_level() const +{ + auto value = kernel_command_line().lookup("acpi").value_or("on"); + if (value == "limited") + return AcpiFeatureLevel::Limited; + if (value == "off") + return AcpiFeatureLevel::Disabled; + return AcpiFeatureLevel::Enabled; +} + +UNMAP_AFTER_INIT HPETMode CommandLine::hpet_mode() const +{ + auto hpet_mode = lookup("hpet").value_or("periodic"); + if (hpet_mode == "periodic") + return HPETMode::Periodic; + if (hpet_mode == "nonperiodic") + return HPETMode::NonPeriodic; + PANIC("Unknown HPETMode: {}", hpet_mode); +} + +UNMAP_AFTER_INIT BootMode CommandLine::boot_mode() const +{ + const auto boot_mode = lookup("boot_mode").value_or("graphical"); + if (boot_mode == "text") { + return BootMode::Text; + } else if (boot_mode == "self-test") { + return BootMode::SelfTest; + } else if (boot_mode == "graphical") { + return BootMode::Graphical; + } + PANIC("Unknown BootMode: {}", boot_mode); +} + +UNMAP_AFTER_INIT bool CommandLine::is_text_mode() const +{ + const auto mode = boot_mode(); + return mode == BootMode::Text || mode == BootMode::SelfTest; +} + +String CommandLine::userspace_init() const +{ + return lookup("init").value_or("/bin/SystemServer"); +} + +Vector CommandLine::userspace_init_args() const +{ + auto init_args = lookup("init_args").value_or("").split(','); + if (!init_args.is_empty()) + init_args.prepend(userspace_init()); + + return init_args; +} + } diff --git a/Kernel/CommandLine.h b/Kernel/CommandLine.h index 0d68f024bc..0e15bb70a8 100644 --- a/Kernel/CommandLine.h +++ b/Kernel/CommandLine.h @@ -29,9 +29,27 @@ #include #include #include +#include namespace Kernel { +enum class BootMode { + Text, + SelfTest, + Graphical +}; + +enum class HPETMode { + Periodic, + NonPeriodic +}; + +enum class AcpiFeatureLevel { + Enabled, + Limited, + Disabled, +}; + class CommandLine { AK_MAKE_ETERNAL; @@ -39,9 +57,23 @@ public: static void early_initialize(const char* cmd_line); static void initialize(); - const String& string() const { return m_string; } + [[nodiscard]] const String& string() const { return m_string; } Optional lookup(const String& key) const; - bool contains(const String& key) const; + [[nodiscard]] bool contains(const String& key) const; + + [[nodiscard]] bool is_ide_enabled() const; + [[nodiscard]] bool is_smp_enabled() const; + [[nodiscard]] bool is_vmmouse_enabled() const; + [[nodiscard]] bool is_mmio_enabled() const; + [[nodiscard]] bool is_legacy_time_enabled() const; + [[nodiscard]] bool is_text_mode() const; + [[nodiscard]] bool is_force_pio() const; + [[nodiscard]] AcpiFeatureLevel acpi_feature_level() const; + [[nodiscard]] BootMode boot_mode() const; + [[nodiscard]] HPETMode hpet_mode() const; + [[nodiscard]] String userspace_init() const; + [[nodiscard]] Vector userspace_init_args() const; + [[nodiscard]] String root_device() const; private: CommandLine(const String&); diff --git a/Kernel/Devices/VMWareBackdoor.cpp b/Kernel/Devices/VMWareBackdoor.cpp index 87311ceb26..5ba1b993a1 100644 --- a/Kernel/Devices/VMWareBackdoor.cpp +++ b/Kernel/Devices/VMWareBackdoor.cpp @@ -118,7 +118,7 @@ VMWareBackdoor* VMWareBackdoor::the() UNMAP_AFTER_INIT VMWareBackdoor::VMWareBackdoor() { - if (kernel_command_line().lookup("vmmouse").value_or("on") == "on") + if (kernel_command_line().is_vmmouse_enabled()) enable_absolute_vmmouse(); } diff --git a/Kernel/Interrupts/InterruptManagement.cpp b/Kernel/Interrupts/InterruptManagement.cpp index 3a4b97f647..5f9da12acb 100644 --- a/Kernel/Interrupts/InterruptManagement.cpp +++ b/Kernel/Interrupts/InterruptManagement.cpp @@ -61,7 +61,7 @@ UNMAP_AFTER_INIT void InterruptManagement::initialize() VERIFY(!InterruptManagement::initialized()); s_interrupt_management = new InterruptManagement(); - if (kernel_command_line().lookup("smp").value_or("off") == "on") + if (kernel_command_line().is_smp_enabled()) InterruptManagement::the().switch_to_ioapic_mode(); else InterruptManagement::the().switch_to_pic_mode(); diff --git a/Kernel/PCI/Initializer.cpp b/Kernel/PCI/Initializer.cpp index 5df4ca2cec..ac33d6161a 100644 --- a/Kernel/PCI/Initializer.cpp +++ b/Kernel/PCI/Initializer.cpp @@ -50,7 +50,7 @@ UNMAP_AFTER_INIT static Access::Type detect_optimal_access_type(bool mmio_allowe UNMAP_AFTER_INIT void initialize() { - bool mmio_allowed = kernel_command_line().lookup("pci_mmio").value_or("off") == "on"; + bool mmio_allowed = kernel_command_line().is_mmio_enabled(); if (detect_optimal_access_type(mmio_allowed) == Access::Type::MMIO) MMIOAccess::initialize(ACPI::Parser::the()->find_table("MCFG")); diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index 9211ce97f5..8090270d2e 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -62,7 +62,7 @@ bool StorageManagement::boot_argument_contains_partition_uuid() NonnullRefPtrVector StorageManagement::enumerate_controllers(bool force_pio) const { NonnullRefPtrVector controllers; - if (!kernel_command_line().contains("disable_ide")) { + if (kernel_command_line().is_ide_enabled()) { 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)); diff --git a/Kernel/Time/TimeManagement.cpp b/Kernel/Time/TimeManagement.cpp index 01efc7c371..4267de7487 100644 --- a/Kernel/Time/TimeManagement.cpp +++ b/Kernel/Time/TimeManagement.cpp @@ -192,7 +192,7 @@ time_t TimeManagement::boot_time() const UNMAP_AFTER_INIT TimeManagement::TimeManagement() { - bool probe_non_legacy_hardware_timers = !(kernel_command_line().lookup("time").value_or("modern") == "legacy"); + bool probe_non_legacy_hardware_timers = !(kernel_command_line().is_legacy_time_enabled()); if (ACPI::is_enabled()) { if (!ACPI::Parser::the()->x86_specific_flags().cmos_rtc_not_present) { RTC::initialize(); @@ -247,12 +247,14 @@ Vector TimeManagement::scan_for_non_periodic_timers() bool TimeManagement::is_hpet_periodic_mode_allowed() { - auto hpet_mode = kernel_command_line().lookup("hpet").value_or("periodic"); - if (hpet_mode == "periodic") + switch (kernel_command_line().hpet_mode()) { + case HPETMode::Periodic: return true; - if (hpet_mode == "nonperiodic") + case HPETMode::NonPeriodic: return false; - VERIFY_NOT_REACHED(); + default: + VERIFY_NOT_REACHED(); + } } UNMAP_AFTER_INIT bool TimeManagement::probe_and_set_non_legacy_hardware_timers() diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 18923f48da..5c13864361 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -247,11 +247,8 @@ void init_stage2(void*) PCI::initialize(); - auto boot_mode = kernel_command_line().lookup("boot_mode").value_or("graphical"); - // FIXME: Richer boot mode options would be nice instead of adding more strcmp here - bool text_mode = boot_mode == "text" || boot_mode == "self-test"; - - if (text_mode) { + auto is_text_mode = kernel_command_line().is_text_mode(); + if (is_text_mode) { dbgln("Text mode enabled"); } else { bool bxvga_found = false; @@ -294,11 +291,7 @@ void init_stage2(void*) SB16::detect(); VMWareBackdoor::the(); // don't wait until first mouse packet - bool force_pio = kernel_command_line().contains("force_pio"); - - auto root = kernel_command_line().lookup("root").value_or("/dev/hda"); - - StorageManagement::initialize(root, force_pio); + StorageManagement::initialize(kernel_command_line().root_device(), kernel_command_line().is_force_pio()); if (!VFS::the().mount_root(StorageManagement::the().root_filesystem())) { PANIC("VFS::mount_root failed"); } @@ -316,12 +309,10 @@ void init_stage2(void*) int error; // FIXME: It would be nicer to set the mode from userspace. - tty0->set_graphical(!text_mode); + tty0->set_graphical(!is_text_mode); RefPtr thread; - auto userspace_init = kernel_command_line().lookup("init").value_or("/bin/SystemServer"); - auto init_args = kernel_command_line().lookup("init_args").value_or("").split(','); - if (!init_args.is_empty()) - init_args.prepend(userspace_init); + auto userspace_init = kernel_command_line().userspace_init(); + auto init_args = kernel_command_line().userspace_init_args(); Process::create_user_process(thread, userspace_init, (uid_t)0, (gid_t)0, ProcessID(0), error, move(init_args), {}, tty0); if (error != 0) { PANIC("init_stage2: Error spawning SystemServer: {}", error);