diff --git a/Base/usr/share/man/man7/boot_parameters.md b/Base/usr/share/man/man7/boot_parameters.md index f38a06038d..f184b4fe7f 100644 --- a/Base/usr/share/man/man7/boot_parameters.md +++ b/Base/usr/share/man/man7/boot_parameters.md @@ -41,7 +41,7 @@ List of options: but only if **`acpi`** is set to **`limited`** or **`on`**, and a `MADT` (APIC) table is available. Otherwise, the kernel will fallback to use the i8259 PICs. -* **`fbdev`** - This parameter expects **`on`** or **`off`**. +* **`fbdev`** - This parameter expects one of the following values. **`on`**- Boot into the graphical environment (default). **`off`** - Boot into text mode. **`bootloader`** - Boot into the graphical environment, but only use the frame buffer set up by the bootloader and do not initialize any other graphics cards. * **`force_pio`** - If present on the command line, the IDE controllers will be force into PIO mode when initialized IDE Channels on boot. diff --git a/Kernel/CommandLine.cpp b/Kernel/CommandLine.cpp index d71cad65cf..abc79850e4 100644 --- a/Kernel/CommandLine.cpp +++ b/Kernel/CommandLine.cpp @@ -245,9 +245,14 @@ PanicMode CommandLine::panic_mode(Validate should_validate) const return PanicMode::Halt; } -UNMAP_AFTER_INIT bool CommandLine::are_framebuffer_devices_enabled() const +UNMAP_AFTER_INIT auto CommandLine::are_framebuffer_devices_enabled() const -> FrameBufferDevices { - return lookup("fbdev"sv).value_or("on"sv) == "on"sv; + const auto fbdev_value = lookup("fbdev"sv).value_or("on"sv); + if (fbdev_value == "on"sv) + return FrameBufferDevices::Enabled; + if (fbdev_value == "bootloader"sv) + return FrameBufferDevices::BootloaderOnly; + return FrameBufferDevices::ConsoleOnly; } StringView CommandLine::userspace_init() const diff --git a/Kernel/CommandLine.h b/Kernel/CommandLine.h index fe373d519a..a7f9b85840 100644 --- a/Kernel/CommandLine.h +++ b/Kernel/CommandLine.h @@ -52,6 +52,12 @@ public: No, }; + enum class FrameBufferDevices { + Enabled, + ConsoleOnly, + BootloaderOnly + }; + [[nodiscard]] const String& string() const { return m_string; } Optional lookup(StringView key) const; [[nodiscard]] bool contains(StringView key) const; @@ -65,7 +71,7 @@ public: [[nodiscard]] bool is_vmmouse_enabled() const; [[nodiscard]] PCIAccessLevel pci_access_level() const; [[nodiscard]] bool is_legacy_time_enabled() const; - [[nodiscard]] bool are_framebuffer_devices_enabled() const; + [[nodiscard]] FrameBufferDevices are_framebuffer_devices_enabled() const; [[nodiscard]] bool is_force_pio() const; [[nodiscard]] AcpiFeatureLevel acpi_feature_level() const; [[nodiscard]] StringView system_mode() const; diff --git a/Kernel/Graphics/GraphicsManagement.cpp b/Kernel/Graphics/GraphicsManagement.cpp index d1b27ef2dc..883cb50b7e 100644 --- a/Kernel/Graphics/GraphicsManagement.cpp +++ b/Kernel/Graphics/GraphicsManagement.cpp @@ -36,9 +36,14 @@ UNMAP_AFTER_INIT GraphicsManagement::GraphicsManagement() { } -bool GraphicsManagement::framebuffer_devices_allowed() const +bool GraphicsManagement::framebuffer_devices_use_bootloader_framebuffer() const { - return kernel_command_line().are_framebuffer_devices_enabled(); + return kernel_command_line().are_framebuffer_devices_enabled() == CommandLine::FrameBufferDevices::BootloaderOnly; +} + +bool GraphicsManagement::framebuffer_devices_console_only() const +{ + return kernel_command_line().are_framebuffer_devices_enabled() == CommandLine::FrameBufferDevices::ConsoleOnly; } void GraphicsManagement::deactivate_graphical_mode() @@ -73,7 +78,7 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi VERIFY(is_vga_compatible_pci_device(device_identifier) || is_display_controller_pci_device(device_identifier)); auto add_and_configure_adapter = [&](GenericGraphicsAdapter& graphics_device) { m_graphics_devices.append(graphics_device); - if (!framebuffer_devices_allowed()) { + if (framebuffer_devices_console_only()) { graphics_device.enable_consoles(); return; } @@ -81,52 +86,63 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi }; RefPtr adapter; - switch (device_identifier.hardware_id().vendor_id) { - case PCI::VendorID::QEMUOld: - if (device_identifier.hardware_id().device_id == 0x1111) - adapter = BochsGraphicsAdapter::initialize(device_identifier); - break; - case PCI::VendorID::VirtualBox: - if (device_identifier.hardware_id().device_id == 0xbeef) - adapter = BochsGraphicsAdapter::initialize(device_identifier); - break; - case PCI::VendorID::Intel: - adapter = IntelNativeGraphicsAdapter::initialize(device_identifier); - break; - case PCI::VendorID::VirtIO: - dmesgln("Graphics: Using VirtIO console"); - adapter = Graphics::VirtIOGPU::GraphicsAdapter::initialize(device_identifier); - break; - default: - if (!is_vga_compatible_pci_device(device_identifier)) - break; - // Note: Although technically possible that a system has a - // non-compatible VGA graphics device that was initialized by the - // Multiboot bootloader to provide a framebuffer, in practice we - // probably want to support these devices natively instead of - // initializing them as some sort of a generic GenericGraphicsAdapter. For now, - // the only known example of this sort of device is qxl in QEMU. For VGA - // compatible devices we don't have a special driver for (e.g. ati-vga, - // qxl-vga, cirrus-vga, vmware-svga in QEMU), it's much more likely that - // these devices will be supported by the Multiboot loader that will - // utilize VESA BIOS extensions (that we don't currently) of these cards - // support, so we want to utilize the provided framebuffer of these - // devices, if possible. - if (!m_vga_adapter && PCI::is_io_space_enabled(device_identifier.address())) { - if (multiboot_framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB) { - dmesgln("Graphics: Using a preset resolution from the bootloader"); - adapter = VGACompatibleAdapter::initialize_with_preset_resolution(device_identifier, - multiboot_framebuffer_addr, - multiboot_framebuffer_width, - multiboot_framebuffer_height, - multiboot_framebuffer_pitch); - } - } else { - dmesgln("Graphics: Using a VGA compatible generic adapter"); - adapter = VGACompatibleAdapter::initialize(device_identifier); + + auto create_bootloader_framebuffer_device = [&]() { + if (multiboot_framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB) { + dmesgln("Graphics: Using a preset resolution from the bootloader"); + adapter = VGACompatibleAdapter::initialize_with_preset_resolution(device_identifier, + multiboot_framebuffer_addr, + multiboot_framebuffer_width, + multiboot_framebuffer_height, + multiboot_framebuffer_pitch); + } + }; + + if (framebuffer_devices_use_bootloader_framebuffer()) + create_bootloader_framebuffer_device(); + + if (!adapter) { + switch (device_identifier.hardware_id().vendor_id) { + case PCI::VendorID::QEMUOld: + if (device_identifier.hardware_id().device_id == 0x1111) + adapter = BochsGraphicsAdapter::initialize(device_identifier); + break; + case PCI::VendorID::VirtualBox: + if (device_identifier.hardware_id().device_id == 0xbeef) + adapter = BochsGraphicsAdapter::initialize(device_identifier); + break; + case PCI::VendorID::Intel: + adapter = IntelNativeGraphicsAdapter::initialize(device_identifier); + break; + case PCI::VendorID::VirtIO: + dmesgln("Graphics: Using VirtIO console"); + adapter = Graphics::VirtIOGPU::GraphicsAdapter::initialize(device_identifier); + break; + default: + if (!is_vga_compatible_pci_device(device_identifier)) + break; + // Note: Although technically possible that a system has a + // non-compatible VGA graphics device that was initialized by the + // Multiboot bootloader to provide a framebuffer, in practice we + // probably want to support these devices natively instead of + // initializing them as some sort of a generic GenericGraphicsAdapter. For now, + // the only known example of this sort of device is qxl in QEMU. For VGA + // compatible devices we don't have a special driver for (e.g. ati-vga, + // qxl-vga, cirrus-vga, vmware-svga in QEMU), it's much more likely that + // these devices will be supported by the Multiboot loader that will + // utilize VESA BIOS extensions (that we don't currently) of these cards + // support, so we want to utilize the provided framebuffer of these + // devices, if possible. + if (!m_vga_adapter && PCI::is_io_space_enabled(device_identifier.address())) { + create_bootloader_framebuffer_device(); + } else { + dmesgln("Graphics: Using a VGA compatible generic adapter"); + adapter = VGACompatibleAdapter::initialize(device_identifier); + } + break; } - break; } + if (!adapter) return false; add_and_configure_adapter(*adapter); @@ -179,8 +195,10 @@ UNMAP_AFTER_INIT bool GraphicsManagement::initialize() * be created, so SystemServer will not try to initialize WindowServer. */ - if (!framebuffer_devices_allowed()) - dbgln("Forcing non-initialization of framebuffer devices"); + if (framebuffer_devices_console_only()) + dbgln("Forcing non-initialization of framebuffer devices (console only)"); + else if (framebuffer_devices_use_bootloader_framebuffer()) + dbgln("Forcing use of framebuffer set up by the bootloader"); PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) { // Note: Each graphics controller will try to set its native screen resolution diff --git a/Kernel/Graphics/GraphicsManagement.h b/Kernel/Graphics/GraphicsManagement.h index a89166c56e..43f964c0f5 100644 --- a/Kernel/Graphics/GraphicsManagement.h +++ b/Kernel/Graphics/GraphicsManagement.h @@ -36,7 +36,8 @@ public: unsigned allocate_minor_device_number() { return m_current_minor_number++; }; GraphicsManagement(); - bool framebuffer_devices_allowed() const; + bool framebuffer_devices_console_only() const; + bool framebuffer_devices_use_bootloader_framebuffer() const; bool framebuffer_devices_exist() const; Spinlock& main_vga_lock() { return m_main_vga_lock; }