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; }