From fb488e2b2707063224a58e88d89796d7647ab93e Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 16 Jun 2021 19:35:11 -0600 Subject: [PATCH] Kernel: Allow VGA-capable graphics adapters to exist with legacy VGA If we have a VGA-capable graphics adapter that we support, we should prefer it over any legacy VGA because we wouldn't use it in legacy VGA mode in this case. This solves the problem where we would only use the legacy VGA card when both a legacy VGA card as well as a VGA-mode capable adapter is present. --- Kernel/Graphics/BochsGraphicsAdapter.cpp | 3 +- Kernel/Graphics/GraphicsDevice.h | 8 +- Kernel/Graphics/GraphicsManagement.cpp | 104 +++++++++++++++-------- Kernel/Graphics/GraphicsManagement.h | 2 - Kernel/Graphics/VGACompatibleAdapter.cpp | 6 +- Kernel/PCI/Definitions.h | 12 ++- 6 files changed, 92 insertions(+), 43 deletions(-) diff --git a/Kernel/Graphics/BochsGraphicsAdapter.cpp b/Kernel/Graphics/BochsGraphicsAdapter.cpp index 5b815b1bad..6e947113f5 100644 --- a/Kernel/Graphics/BochsGraphicsAdapter.cpp +++ b/Kernel/Graphics/BochsGraphicsAdapter.cpp @@ -49,7 +49,8 @@ UNMAP_AFTER_INIT NonnullRefPtr BochsGraphicsAdapter::initi } UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::Address pci_address) - : PCI::DeviceController(pci_address) + : GraphicsDevice(pci_address) + , PCI::DeviceController(pci_address) , m_mmio_registers(PCI::get_BAR2(pci_address) & 0xfffffff0) { // We assume safe resolutio is 1024x768x32 diff --git a/Kernel/Graphics/GraphicsDevice.h b/Kernel/Graphics/GraphicsDevice.h index acc6b9ac0f..ed409188dc 100644 --- a/Kernel/Graphics/GraphicsDevice.h +++ b/Kernel/Graphics/GraphicsDevice.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Kernel { @@ -23,6 +24,7 @@ public: virtual ~GraphicsDevice() = default; virtual void initialize_framebuffer_devices() = 0; virtual Type type() const = 0; + PCI::Address device_pci_address() const { return m_pci_address; } virtual void enable_consoles() = 0; virtual void disable_consoles() = 0; bool consoles_enabled() const { return m_consoles_enabled; } @@ -35,8 +37,12 @@ public: virtual bool set_y_offset(size_t output_port_index, size_t y) = 0; protected: - GraphicsDevice() = default; + GraphicsDevice(PCI::Address pci_address) + : m_pci_address(pci_address) + { + } + const PCI::Address m_pci_address; bool m_consoles_enabled { false }; }; diff --git a/Kernel/Graphics/GraphicsManagement.cpp b/Kernel/Graphics/GraphicsManagement.cpp index 67e6d92c1c..6fde82ee5c 100644 --- a/Kernel/Graphics/GraphicsManagement.cpp +++ b/Kernel/Graphics/GraphicsManagement.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -52,28 +53,9 @@ void GraphicsManagement::activate_graphical_mode() } } -UNMAP_AFTER_INIT RefPtr GraphicsManagement::determine_graphics_device(PCI::Address address, PCI::ID id) const +static inline bool is_vga_compatible_pci_device(PCI::Address address) { - if ((id.vendor_id == 0x1234 && id.device_id == 0x1111) || (id.vendor_id == 0x80ee && id.device_id == 0xbeef)) { - return BochsGraphicsAdapter::initialize(address); - } - if (PCI::get_class(address) == 0x3 && PCI::get_subclass(address) == 0x0) { - if (id.vendor_id == 0x8086) { - auto adapter = IntelNativeGraphicsAdapter::initialize(address); - if (!adapter.is_null()) - return adapter; - } - if (multiboot_info_ptr->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB) { - dmesgln("Graphics: Using a preset resolution from the bootloader"); - return VGACompatibleAdapter::initialize_with_preset_resolution(address, - PhysicalAddress((u32)(multiboot_info_ptr->framebuffer_addr)), - multiboot_info_ptr->framebuffer_width, - multiboot_info_ptr->framebuffer_height, - multiboot_info_ptr->framebuffer_pitch); - } - return VGACompatibleAdapter::initialize(address); - } - return {}; + return PCI::get_class(address) == 0x3 && PCI::get_subclass(address) == 0x0; } UNMAP_AFTER_INIT bool GraphicsManagement::initialize() @@ -119,28 +101,78 @@ UNMAP_AFTER_INIT bool GraphicsManagement::initialize() dbgln("Forcing no initialization of framebuffer devices"); } - PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { - // Note: Each graphics controller will try to set its native screen resolution - // upon creation. Later on, if we don't want to have framebuffer devices, a - // framebuffer console will take the control instead. - auto adapter = determine_graphics_device(address, id); - if (!adapter) - return; - - // If IO space is enabled, this VGA adapter is operating in VGA mode. - if (adapter->type() == GraphicsDevice::Type::VGACompatible && PCI::is_io_space_enabled(address)) { - VERIFY(m_vga_adapter.is_null()); - dbgln("Graphics adapter @ {} is operating in VGA mode", address); - m_vga_adapter = adapter; - } - auto display_adapter = adapter.release_nonnull(); + auto add_and_initialize_adapter = [&](NonnullRefPtr display_adapter) { m_graphics_devices.append(display_adapter); if (!m_framebuffer_devices_allowed) { display_adapter->enable_consoles(); return; } display_adapter->initialize_framebuffer_devices(); + }; + auto have_adapter_for_address = [&](const PCI::Address& address) { + for (auto& adapter : m_graphics_devices) { + if (adapter.device_pci_address() == address) + return true; + } + return false; + }; + + Vector uninitialized_vga_pci_addresses; + PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { + // Note: Each graphics controller will try to set its native screen resolution + // upon creation. Later on, if we don't want to have framebuffer devices, a + // framebuffer console will take the control instead. + RefPtr adapter; + bool is_vga_compatible = is_vga_compatible_pci_device(address); + if ((id.vendor_id == 0x1234 && id.device_id == 0x1111) || (id.vendor_id == 0x80ee && id.device_id == 0xbeef)) { + adapter = BochsGraphicsAdapter::initialize(address); + } else if (is_vga_compatible) { + if (id.vendor_id == 0x8086) { + adapter = IntelNativeGraphicsAdapter::initialize(address); + } + } + if (adapter) + add_and_initialize_adapter(adapter.release_nonnull()); + else if (is_vga_compatible) + uninitialized_vga_pci_addresses.append(address); }); + + if (!uninitialized_vga_pci_addresses.is_empty()) { + for (auto& address : uninitialized_vga_pci_addresses) { + VERIFY(is_vga_compatible_pci_device(address)); + VERIFY(!have_adapter_for_address(address)); + + if (multiboot_info_ptr->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB) { + dmesgln("Graphics: Using a preset resolution from the bootloader"); + auto vga_adapter = VGACompatibleAdapter::initialize_with_preset_resolution(address, + PhysicalAddress((u32)(multiboot_info_ptr->framebuffer_addr)), + multiboot_info_ptr->framebuffer_width, + multiboot_info_ptr->framebuffer_height, + multiboot_info_ptr->framebuffer_pitch); + m_vga_adapter = vga_adapter; + add_and_initialize_adapter(move(vga_adapter)); + } else { + dmesgln("Graphics: Using a VGA compatible generic adapter"); + auto vga_adapter = VGACompatibleAdapter::initialize(address); + m_vga_adapter = vga_adapter; + add_and_initialize_adapter(move(vga_adapter)); + } + break; // We can only have one vga adapter + } + + // If we still don't have a VGA compatible adapter, check if any of the ones + // we support explicitly happens to be able to operate in VGA mode + if (!m_vga_adapter) { + for (auto& adapter : m_graphics_devices) { + // If IO space is enabled, this VGA adapter is operating in VGA mode. + if (adapter.type() == GraphicsDevice::Type::VGACompatible && !m_vga_adapter && PCI::is_io_space_enabled(adapter.device_pci_address())) { + dbgln("Graphics adapter @ {} is operating in VGA mode", adapter.device_pci_address()); + m_vga_adapter = adapter; + break; + } + } + } + } if (m_graphics_devices.is_empty()) { dbgln("No graphics adapter was initialized."); return false; diff --git a/Kernel/Graphics/GraphicsManagement.h b/Kernel/Graphics/GraphicsManagement.h index 144f480db9..0549d97b95 100644 --- a/Kernel/Graphics/GraphicsManagement.h +++ b/Kernel/Graphics/GraphicsManagement.h @@ -45,8 +45,6 @@ public: void activate_graphical_mode(); private: - RefPtr determine_graphics_device(PCI::Address address, PCI::ID id) const; - NonnullRefPtrVector m_graphics_devices; NonnullOwnPtr m_vga_font_region; RefPtr m_console; diff --git a/Kernel/Graphics/VGACompatibleAdapter.cpp b/Kernel/Graphics/VGACompatibleAdapter.cpp index f2bf1cc232..19ece12e59 100644 --- a/Kernel/Graphics/VGACompatibleAdapter.cpp +++ b/Kernel/Graphics/VGACompatibleAdapter.cpp @@ -36,7 +36,8 @@ UNMAP_AFTER_INIT void VGACompatibleAdapter::initialize_framebuffer_devices() } UNMAP_AFTER_INIT VGACompatibleAdapter::VGACompatibleAdapter(PCI::Address address) - : PCI::DeviceController(address) + : GraphicsDevice(address) + , PCI::DeviceController(address) { m_framebuffer_console = Graphics::TextModeConsole::initialize(*this); // FIXME: This is a very wrong way to do this... @@ -44,7 +45,8 @@ UNMAP_AFTER_INIT VGACompatibleAdapter::VGACompatibleAdapter(PCI::Address address } UNMAP_AFTER_INIT VGACompatibleAdapter::VGACompatibleAdapter(PCI::Address address, PhysicalAddress framebuffer_address, size_t framebuffer_width, size_t framebuffer_height, size_t framebuffer_pitch) - : PCI::DeviceController(address) + : GraphicsDevice(address) + , PCI::DeviceController(address) , m_framebuffer_address(framebuffer_address) , m_framebuffer_width(framebuffer_width) , m_framebuffer_height(framebuffer_height) diff --git a/Kernel/PCI/Definitions.h b/Kernel/PCI/Definitions.h index 66fba2934e..08edcf6cc9 100644 --- a/Kernel/PCI/Definitions.h +++ b/Kernel/PCI/Definitions.h @@ -99,12 +99,22 @@ public: operator bool() const { return !is_null(); } // Disable default implementations that would use surprising integer promotion. - bool operator==(const Address&) const = delete; bool operator<=(const Address&) const = delete; bool operator>=(const Address&) const = delete; bool operator<(const Address&) const = delete; bool operator>(const Address&) const = delete; + bool operator==(const Address& other) const + { + if (this == &other) + return true; + return m_seg == other.m_seg && m_bus == other.m_bus && m_device == other.m_device && m_function == other.m_function; + } + bool operator!=(const Address& other) const + { + return !(*this == other); + } + u16 seg() const { return m_seg; } u8 bus() const { return m_bus; } u8 device() const { return m_device; }