Serenity Operating System
at master 328 lines 9.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StringBuilder.h> 8#include <Kernel/CommandLine.h> 9#include <Kernel/Panic.h> 10#include <Kernel/Sections.h> 11#include <Kernel/StdLib.h> 12 13namespace Kernel { 14 15static char s_cmd_line[1024]; 16static constexpr StringView s_embedded_cmd_line = ""sv; 17static CommandLine* s_the; 18 19UNMAP_AFTER_INIT void CommandLine::early_initialize(char const* cmd_line) 20{ 21 if (!cmd_line) 22 return; 23 size_t length = strlen(cmd_line); 24 if (length >= sizeof(s_cmd_line)) 25 length = sizeof(s_cmd_line) - 1; 26 memcpy(s_cmd_line, cmd_line, length); 27 s_cmd_line[length] = '\0'; 28} 29 30bool CommandLine::was_initialized() 31{ 32 return s_the != nullptr; 33} 34 35CommandLine const& kernel_command_line() 36{ 37 VERIFY(s_the); 38 return *s_the; 39} 40 41UNMAP_AFTER_INIT void CommandLine::initialize() 42{ 43 VERIFY(!s_the); 44 s_the = new CommandLine({ s_cmd_line, strlen(s_cmd_line) }); 45 dmesgln("Kernel Commandline: {}", kernel_command_line().string()); 46 // Validate the modes the user passed in. 47 (void)s_the->panic_mode(Validate::Yes); 48} 49 50UNMAP_AFTER_INIT NonnullOwnPtr<KString> CommandLine::build_commandline(StringView cmdline_from_bootloader) 51{ 52 StringBuilder builder; 53 builder.append(cmdline_from_bootloader); 54 if constexpr (!s_embedded_cmd_line.is_empty()) { 55 builder.append(' '); 56 builder.append(s_embedded_cmd_line); 57 } 58 return KString::must_create(builder.string_view()); 59} 60 61UNMAP_AFTER_INIT void CommandLine::add_arguments(Vector<StringView> const& args) 62{ 63 for (auto&& str : args) { 64 if (str == ""sv) { 65 continue; 66 } 67 68 auto pair = str.split_view('='); 69 VERIFY(pair.size() == 2 || pair.size() == 1); 70 71 if (pair.size() == 1) { 72 m_params.set(pair[0], ""sv); 73 } else { 74 m_params.set(pair[0], pair[1]); 75 } 76 } 77} 78 79UNMAP_AFTER_INIT CommandLine::CommandLine(StringView cmdline_from_bootloader) 80 : m_string(build_commandline(cmdline_from_bootloader)) 81{ 82 s_the = this; 83 auto const& args = m_string->view().split_view(' '); 84 MUST(m_params.try_ensure_capacity(args.size())); 85 add_arguments(args); 86} 87 88Optional<StringView> CommandLine::lookup(StringView key) const 89{ 90 return m_params.get(key); 91} 92 93bool CommandLine::contains(StringView key) const 94{ 95 return m_params.contains(key); 96} 97 98UNMAP_AFTER_INIT bool CommandLine::is_boot_profiling_enabled() const 99{ 100 return contains("boot_prof"sv); 101} 102 103UNMAP_AFTER_INIT bool CommandLine::is_ide_enabled() const 104{ 105 return !contains("disable_ide"sv); 106} 107 108UNMAP_AFTER_INIT bool CommandLine::is_smp_enabled() const 109{ 110 // Note: We can't enable SMP mode without enabling the IOAPIC. 111 if (!is_ioapic_enabled()) 112 return false; 113 return lookup("smp"sv).value_or("off"sv) == "on"sv; 114} 115 116UNMAP_AFTER_INIT bool CommandLine::is_smp_enabled_without_ioapic_enabled() const 117{ 118 auto smp_enabled = lookup("smp"sv).value_or("off"sv) == "on"sv; 119 return smp_enabled && !is_ioapic_enabled(); 120} 121 122UNMAP_AFTER_INIT bool CommandLine::is_ioapic_enabled() const 123{ 124 auto value = lookup("enable_ioapic"sv).value_or("on"sv); 125 if (value == "on"sv) 126 return true; 127 if (value == "off"sv) 128 return false; 129 PANIC("Unknown enable_ioapic setting: {}", value); 130} 131 132UNMAP_AFTER_INIT bool CommandLine::is_early_boot_console_disabled() const 133{ 134 auto value = lookup("early_boot_console"sv).value_or("on"sv); 135 if (value == "on"sv) 136 return false; 137 if (value == "off"sv) 138 return true; 139 PANIC("Unknown early_boot_console setting: {}", value); 140} 141 142UNMAP_AFTER_INIT I8042PresenceMode CommandLine::i8042_presence_mode() const 143{ 144 auto value = lookup("i8042_presence_mode"sv).value_or("auto"sv); 145 if (value == "auto"sv) 146 return I8042PresenceMode::Automatic; 147 if (value == "none"sv) 148 return I8042PresenceMode::None; 149 if (value == "force"sv) 150 return I8042PresenceMode::Force; 151 if (value == "aggressive-test"sv) 152 return I8042PresenceMode::AggressiveTest; 153 PANIC("Unknown i8042_presence_mode setting: {}", value); 154} 155 156UNMAP_AFTER_INIT bool CommandLine::is_vmmouse_enabled() const 157{ 158 return lookup("vmmouse"sv).value_or("on"sv) == "on"sv; 159} 160 161UNMAP_AFTER_INIT PCIAccessLevel CommandLine::pci_access_level() const 162{ 163 auto value = lookup("pci"sv).value_or("ecam"sv); 164 if (value == "ecam"sv) 165 return PCIAccessLevel::MemoryAddressing; 166#if ARCH(X86_64) 167 if (value == "io"sv) 168 return PCIAccessLevel::IOAddressing; 169#endif 170 if (value == "none"sv) 171 return PCIAccessLevel::None; 172 PANIC("Unknown PCI ECAM setting: {}", value); 173} 174 175UNMAP_AFTER_INIT bool CommandLine::is_pci_disabled() const 176{ 177 return lookup("pci"sv).value_or("ecam"sv) == "none"sv; 178} 179 180UNMAP_AFTER_INIT bool CommandLine::is_legacy_time_enabled() const 181{ 182 return lookup("time"sv).value_or("modern"sv) == "legacy"sv; 183} 184 185bool CommandLine::is_pc_speaker_enabled() const 186{ 187 auto value = lookup("pcspeaker"sv).value_or("off"sv); 188 if (value == "on"sv) 189 return true; 190 if (value == "off"sv) 191 return false; 192 PANIC("Unknown pcspeaker setting: {}", value); 193} 194 195UNMAP_AFTER_INIT bool CommandLine::is_force_pio() const 196{ 197 return contains("force_pio"sv); 198} 199 200UNMAP_AFTER_INIT StringView CommandLine::root_device() const 201{ 202 return lookup("root"sv).value_or("lun0:0:0"sv); 203} 204 205bool CommandLine::is_nvme_polling_enabled() const 206{ 207 return contains("nvme_poll"sv); 208} 209 210UNMAP_AFTER_INIT AcpiFeatureLevel CommandLine::acpi_feature_level() const 211{ 212 auto value = kernel_command_line().lookup("acpi"sv).value_or("limited"sv); 213 if (value == "limited"sv) 214 return AcpiFeatureLevel::Limited; 215 if (value == "off"sv) 216 return AcpiFeatureLevel::Disabled; 217 if (value == "on"sv) 218 return AcpiFeatureLevel::Enabled; 219 PANIC("Unknown ACPI feature level: {}", value); 220} 221 222UNMAP_AFTER_INIT HPETMode CommandLine::hpet_mode() const 223{ 224 auto hpet_mode = lookup("hpet"sv).value_or("periodic"sv); 225 if (hpet_mode == "periodic"sv) 226 return HPETMode::Periodic; 227 if (hpet_mode == "nonperiodic"sv) 228 return HPETMode::NonPeriodic; 229 PANIC("Unknown HPETMode: {}", hpet_mode); 230} 231 232UNMAP_AFTER_INIT bool CommandLine::is_physical_networking_disabled() const 233{ 234 return contains("disable_physical_networking"sv); 235} 236 237UNMAP_AFTER_INIT bool CommandLine::disable_physical_storage() const 238{ 239 return contains("disable_physical_storage"sv); 240} 241 242UNMAP_AFTER_INIT bool CommandLine::disable_uhci_controller() const 243{ 244 return contains("disable_uhci_controller"sv); 245} 246 247UNMAP_AFTER_INIT bool CommandLine::disable_usb() const 248{ 249 return contains("disable_usb"sv); 250} 251 252UNMAP_AFTER_INIT bool CommandLine::disable_virtio() const 253{ 254 return contains("disable_virtio"sv); 255} 256 257UNMAP_AFTER_INIT AHCIResetMode CommandLine::ahci_reset_mode() const 258{ 259 auto const ahci_reset_mode = lookup("ahci_reset_mode"sv).value_or("controllers"sv); 260 if (ahci_reset_mode == "controllers"sv) { 261 return AHCIResetMode::ControllerOnly; 262 } 263 if (ahci_reset_mode == "aggressive"sv) { 264 return AHCIResetMode::Aggressive; 265 } 266 PANIC("Unknown AHCIResetMode: {}", ahci_reset_mode); 267} 268 269StringView CommandLine::system_mode() const 270{ 271 return lookup("system_mode"sv).value_or("graphical"sv); 272} 273 274PanicMode CommandLine::panic_mode(Validate should_validate) const 275{ 276 auto const panic_mode = lookup("panic"sv).value_or("halt"sv); 277 if (panic_mode == "halt"sv) { 278 return PanicMode::Halt; 279 } 280 if (panic_mode == "shutdown"sv) { 281 return PanicMode::Shutdown; 282 } 283 284 if (should_validate == Validate::Yes) 285 PANIC("Unknown PanicMode: {}", panic_mode); 286 287 return PanicMode::Halt; 288} 289 290UNMAP_AFTER_INIT CommandLine::GraphicsSubsystemMode CommandLine::graphics_subsystem_mode() const 291{ 292 auto const graphics_subsystem_mode_value = lookup("graphics_subsystem_mode"sv).value_or("on"sv); 293 if (graphics_subsystem_mode_value == "on"sv) 294 return GraphicsSubsystemMode::Enabled; 295 if (graphics_subsystem_mode_value == "limited"sv) 296 return GraphicsSubsystemMode::Limited; 297 if (graphics_subsystem_mode_value == "off"sv) 298 return GraphicsSubsystemMode::Disabled; 299 PANIC("Invalid graphics_subsystem_mode value: {}", graphics_subsystem_mode_value); 300} 301 302StringView CommandLine::userspace_init() const 303{ 304 return lookup("init"sv).value_or("/bin/SystemServer"sv); 305} 306 307Vector<NonnullOwnPtr<KString>> CommandLine::userspace_init_args() const 308{ 309 Vector<NonnullOwnPtr<KString>> args; 310 311 auto init_args = lookup("init_args"sv).value_or(""sv).split_view(';'); 312 if (!init_args.is_empty()) 313 MUST(args.try_prepend(MUST(KString::try_create(userspace_init())))); 314 for (auto& init_arg : init_args) 315 args.append(MUST(KString::try_create(init_arg))); 316 return args; 317} 318 319UNMAP_AFTER_INIT size_t CommandLine::switch_to_tty() const 320{ 321 auto const default_tty = lookup("switch_to_tty"sv).value_or("1"sv); 322 auto switch_tty_number = default_tty.to_uint(); 323 if (switch_tty_number.has_value() && switch_tty_number.value() >= 1) { 324 return switch_tty_number.value() - 1; 325 } 326 PANIC("Invalid default tty value: {}", default_tty); 327} 328}