From 72b144e9e92605d48c83d6ad568add588ab0d32e Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 17 Dec 2022 21:15:31 +0200 Subject: [PATCH] Kernel/Graphics: Introduce a new mechanism to initialize a PCI device Instead of using a clunky switch-case paradigm, we now have all drivers being declaring two methods for their adapter class - create and probe. These methods are linked in each PCIGraphicsDriverInitializer structure, in a new s_initializers static list of them. Then, when we probe for a PCI device, we use each probe method and if there's a match, then the corresponding create method is called. As a result of this change, it's much more easy to add more drivers and the initialization code is more readable. --- Kernel/Graphics/Bochs/GraphicsAdapter.cpp | 18 ++++-- Kernel/Graphics/Bochs/GraphicsAdapter.h | 5 +- Kernel/Graphics/GraphicsManagement.cpp | 58 +++++++++---------- Kernel/Graphics/GraphicsManagement.h | 2 +- .../Graphics/Intel/NativeDisplayConnector.cpp | 14 ++--- .../Graphics/Intel/NativeDisplayConnector.h | 2 +- .../Graphics/Intel/NativeGraphicsAdapter.cpp | 16 ++--- Kernel/Graphics/Intel/NativeGraphicsAdapter.h | 3 +- Kernel/Graphics/VMWare/GraphicsAdapter.cpp | 16 ++--- Kernel/Graphics/VMWare/GraphicsAdapter.h | 3 +- Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp | 16 +++-- Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h | 3 +- 12 files changed, 85 insertions(+), 71 deletions(-) diff --git a/Kernel/Graphics/Bochs/GraphicsAdapter.cpp b/Kernel/Graphics/Bochs/GraphicsAdapter.cpp index 09a23f42f4..2494c6f448 100644 --- a/Kernel/Graphics/Bochs/GraphicsAdapter.cpp +++ b/Kernel/Graphics/Bochs/GraphicsAdapter.cpp @@ -22,17 +22,25 @@ namespace Kernel { -UNMAP_AFTER_INIT NonnullLockRefPtr BochsGraphicsAdapter::initialize(PCI::DeviceIdentifier const& pci_device_identifier) +UNMAP_AFTER_INIT ErrorOr BochsGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier) { PCI::HardwareID id = pci_device_identifier.hardware_id(); - VERIFY((id.vendor_id == PCI::VendorID::QEMUOld && id.device_id == 0x1111) || (id.vendor_id == PCI::VendorID::VirtualBox && id.device_id == 0xbeef)); - auto adapter = adopt_lock_ref(*new BochsGraphicsAdapter(pci_device_identifier)); + if (id.vendor_id == PCI::VendorID::QEMUOld && id.device_id == 0x1111) + return true; + if (id.vendor_id == PCI::VendorID::VirtualBox && id.device_id == 0xbeef) + return true; + return false; +} + +UNMAP_AFTER_INIT ErrorOr> BochsGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier) +{ + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) BochsGraphicsAdapter(pci_device_identifier.address()))); MUST(adapter->initialize_adapter(pci_device_identifier)); return adapter; } -UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::DeviceIdentifier const& pci_device_identifier) - : PCI::Device(pci_device_identifier.address()) +UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::Address const& address) + : PCI::Device(address) { } diff --git a/Kernel/Graphics/Bochs/GraphicsAdapter.h b/Kernel/Graphics/Bochs/GraphicsAdapter.h index 5fca7601a1..b865c40553 100644 --- a/Kernel/Graphics/Bochs/GraphicsAdapter.h +++ b/Kernel/Graphics/Bochs/GraphicsAdapter.h @@ -24,14 +24,15 @@ class BochsGraphicsAdapter final : public GenericGraphicsAdapter friend class GraphicsManagement; public: - static NonnullLockRefPtr initialize(PCI::DeviceIdentifier const&); + static ErrorOr probe(PCI::DeviceIdentifier const&); + static ErrorOr> create(PCI::DeviceIdentifier const&); virtual ~BochsGraphicsAdapter() = default; virtual StringView device_name() const override { return "BochsGraphicsAdapter"sv; } private: ErrorOr initialize_adapter(PCI::DeviceIdentifier const&); - explicit BochsGraphicsAdapter(PCI::DeviceIdentifier const&); + explicit BochsGraphicsAdapter(PCI::Address const&); LockRefPtr m_display_connector; }; diff --git a/Kernel/Graphics/GraphicsManagement.cpp b/Kernel/Graphics/GraphicsManagement.cpp index a65e69d58f..3fc595d4e2 100644 --- a/Kernel/Graphics/GraphicsManagement.cpp +++ b/Kernel/Graphics/GraphicsManagement.cpp @@ -120,40 +120,35 @@ static inline bool is_display_controller_pci_device(PCI::DeviceIdentifier const& return device_identifier.class_code().value() == 0x3; } -UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_device(PCI::DeviceIdentifier const& device_identifier) +struct PCIGraphicsDriverInitializer { + ErrorOr (*probe)(PCI::DeviceIdentifier const&) = nullptr; + ErrorOr> (*create)(PCI::DeviceIdentifier const&) = nullptr; +}; + +static constexpr PCIGraphicsDriverInitializer s_initializers[] = { + { IntelNativeGraphicsAdapter::probe, IntelNativeGraphicsAdapter::create }, + { BochsGraphicsAdapter::probe, BochsGraphicsAdapter::create }, + { VirtIOGraphicsAdapter::probe, VirtIOGraphicsAdapter::create }, + { VMWareGraphicsAdapter::probe, VMWareGraphicsAdapter::create }, +}; + +UNMAP_AFTER_INIT ErrorOr GraphicsManagement::determine_and_initialize_graphics_device(PCI::DeviceIdentifier const& device_identifier) { VERIFY(is_vga_compatible_pci_device(device_identifier) || is_display_controller_pci_device(device_identifier)); - LockRefPtr adapter; - - 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 = VirtIOGraphicsAdapter::initialize(device_identifier); - break; - case PCI::VendorID::VMWare: - adapter = VMWareGraphicsAdapter::try_initialize(device_identifier); - break; - default: - break; + for (auto& initializer : s_initializers) { + auto initializer_probe_found_driver_match_or_error = initializer.probe(device_identifier); + if (initializer_probe_found_driver_match_or_error.is_error()) { + dmesgln("Graphics: Failed to probe device {}, due to {}", device_identifier.address(), initializer_probe_found_driver_match_or_error.error()); + continue; + } + auto initializer_probe_found_driver_match = initializer_probe_found_driver_match_or_error.release_value(); + if (initializer_probe_found_driver_match) { + auto adapter = TRY(initializer.create(device_identifier)); + TRY(m_graphics_devices.try_append(*adapter)); + return {}; } } - - if (!adapter) - return false; - m_graphics_devices.append(*adapter); - return true; + return {}; } UNMAP_AFTER_INIT void GraphicsManagement::initialize_preset_resolution_generic_display_connector() @@ -239,7 +234,8 @@ UNMAP_AFTER_INIT bool GraphicsManagement::initialize() // framebuffer console will take the control instead. if (!is_vga_compatible_pci_device(device_identifier) && !is_display_controller_pci_device(device_identifier)) return; - determine_and_initialize_graphics_device(device_identifier); + if (auto result = determine_and_initialize_graphics_device(device_identifier); result.is_error()) + dbgln("Failed to initialize device {}, due to {}", device_identifier.address(), result.error()); })); // Note: If we failed to find any graphics device to be used natively, but the diff --git a/Kernel/Graphics/GraphicsManagement.h b/Kernel/Graphics/GraphicsManagement.h index ec771c6528..ee30adf3ce 100644 --- a/Kernel/Graphics/GraphicsManagement.h +++ b/Kernel/Graphics/GraphicsManagement.h @@ -50,7 +50,7 @@ public: private: void enable_vga_text_mode_console_cursor(); - bool determine_and_initialize_graphics_device(PCI::DeviceIdentifier const&); + ErrorOr determine_and_initialize_graphics_device(PCI::DeviceIdentifier const&); void initialize_preset_resolution_generic_display_connector(); diff --git a/Kernel/Graphics/Intel/NativeDisplayConnector.cpp b/Kernel/Graphics/Intel/NativeDisplayConnector.cpp index 4ce94adf0c..260839d436 100644 --- a/Kernel/Graphics/Intel/NativeDisplayConnector.cpp +++ b/Kernel/Graphics/Intel/NativeDisplayConnector.cpp @@ -175,20 +175,18 @@ Optional IntelNativeDisplayConnector::create_pll_set return {}; } -NonnullLockRefPtr IntelNativeDisplayConnector::must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, PhysicalAddress registers_region_address, size_t registers_region_length) +ErrorOr> IntelNativeDisplayConnector::try_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, PhysicalAddress registers_region_address, size_t registers_region_length) { - auto registers_region = MUST(MM.allocate_kernel_region(PhysicalAddress(registers_region_address), registers_region_length, "Intel Native Graphics Registers"sv, Memory::Region::Access::ReadWrite)); - auto device_or_error = DeviceManagement::try_create_device(framebuffer_address, framebuffer_resource_size, move(registers_region)); - VERIFY(!device_or_error.is_error()); - auto connector = device_or_error.release_value(); - MUST(connector->initialize_gmbus_settings_and_read_edid()); + auto registers_region = TRY(MM.allocate_kernel_region(PhysicalAddress(registers_region_address), registers_region_length, "Intel Native Graphics Registers"sv, Memory::Region::Access::ReadWrite)); + auto connector = TRY(DeviceManagement::try_create_device(framebuffer_address, framebuffer_resource_size, move(registers_region))); + TRY(connector->initialize_gmbus_settings_and_read_edid()); // Note: This is very important to set the resolution to something safe so we // can create a framebuffer console with valid resolution. { SpinlockLocker control_lock(connector->m_control_lock); - MUST(connector->set_safe_mode_setting()); + TRY(connector->set_safe_mode_setting()); } - MUST(connector->create_attached_framebuffer_console()); + TRY(connector->create_attached_framebuffer_console()); return connector; } diff --git a/Kernel/Graphics/Intel/NativeDisplayConnector.h b/Kernel/Graphics/Intel/NativeDisplayConnector.h index 0cd60a4358..d8649d08f6 100644 --- a/Kernel/Graphics/Intel/NativeDisplayConnector.h +++ b/Kernel/Graphics/Intel/NativeDisplayConnector.h @@ -81,7 +81,7 @@ class IntelNativeDisplayConnector final friend class DeviceManagement; public: - static NonnullLockRefPtr must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, PhysicalAddress registers_region_address, size_t registers_region_length); + static ErrorOr> try_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, PhysicalAddress registers_region_address, size_t registers_region_length); private: // ^DisplayConnector diff --git a/Kernel/Graphics/Intel/NativeGraphicsAdapter.cpp b/Kernel/Graphics/Intel/NativeGraphicsAdapter.cpp index f410fceb75..6e583a0d58 100644 --- a/Kernel/Graphics/Intel/NativeGraphicsAdapter.cpp +++ b/Kernel/Graphics/Intel/NativeGraphicsAdapter.cpp @@ -26,13 +26,15 @@ static bool is_supported_model(u16 device_id) return false; } -LockRefPtr IntelNativeGraphicsAdapter::initialize(PCI::DeviceIdentifier const& pci_device_identifier) +ErrorOr IntelNativeGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier) { - VERIFY(pci_device_identifier.hardware_id().vendor_id == 0x8086); - if (!is_supported_model(pci_device_identifier.hardware_id().device_id)) - return {}; - auto adapter = adopt_lock_ref(*new IntelNativeGraphicsAdapter(pci_device_identifier.address())); - MUST(adapter->initialize_adapter()); + return is_supported_model(pci_device_identifier.hardware_id().device_id); +} + +ErrorOr> IntelNativeGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier) +{ + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) IntelNativeGraphicsAdapter(pci_device_identifier.address()))); + TRY(adapter->initialize_adapter()); return adapter; } @@ -47,7 +49,7 @@ ErrorOr IntelNativeGraphicsAdapter::initialize_adapter() dmesgln_pci(*this, "framebuffer @ {}", PhysicalAddress(PCI::get_BAR2(address))); PCI::enable_bus_mastering(address); - m_display_connector = IntelNativeDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR2(address) & 0xfffffff0), bar2_space_size, PhysicalAddress(PCI::get_BAR0(address) & 0xfffffff0), bar0_space_size); + m_display_connector = TRY(IntelNativeDisplayConnector::try_create(PhysicalAddress(PCI::get_BAR2(address) & 0xfffffff0), bar2_space_size, PhysicalAddress(PCI::get_BAR0(address) & 0xfffffff0), bar0_space_size)); return {}; } diff --git a/Kernel/Graphics/Intel/NativeGraphicsAdapter.h b/Kernel/Graphics/Intel/NativeGraphicsAdapter.h index b7c58dea8a..3cdb170bbc 100644 --- a/Kernel/Graphics/Intel/NativeGraphicsAdapter.h +++ b/Kernel/Graphics/Intel/NativeGraphicsAdapter.h @@ -20,7 +20,8 @@ class IntelNativeGraphicsAdapter final , public PCI::Device { public: - static LockRefPtr initialize(PCI::DeviceIdentifier const&); + static ErrorOr probe(PCI::DeviceIdentifier const&); + static ErrorOr> create(PCI::DeviceIdentifier const&); virtual ~IntelNativeGraphicsAdapter() = default; diff --git a/Kernel/Graphics/VMWare/GraphicsAdapter.cpp b/Kernel/Graphics/VMWare/GraphicsAdapter.cpp index 839fe23df5..43f00f3222 100644 --- a/Kernel/Graphics/VMWare/GraphicsAdapter.cpp +++ b/Kernel/Graphics/VMWare/GraphicsAdapter.cpp @@ -20,16 +20,18 @@ namespace Kernel { -UNMAP_AFTER_INIT LockRefPtr VMWareGraphicsAdapter::try_initialize(PCI::DeviceIdentifier const& pci_device_identifier) +ErrorOr VMWareGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier) { PCI::HardwareID id = pci_device_identifier.hardware_id(); - VERIFY(id.vendor_id == PCI::VendorID::VMWare); // Note: We only support VMWare SVGA II adapter - if (id.device_id != 0x0405) - return {}; - auto registers_io_window = MUST(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); - auto adapter = MUST(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VMWareGraphicsAdapter(pci_device_identifier, move(registers_io_window)))); - MUST(adapter->initialize_adapter()); + return id.vendor_id == PCI::VendorID::VMWare && id.device_id == 0x0405; +} + +ErrorOr> VMWareGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier) +{ + auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VMWareGraphicsAdapter(pci_device_identifier, move(registers_io_window)))); + TRY(adapter->initialize_adapter()); return adapter; } diff --git a/Kernel/Graphics/VMWare/GraphicsAdapter.h b/Kernel/Graphics/VMWare/GraphicsAdapter.h index fd159fb9fa..06c35efaa5 100644 --- a/Kernel/Graphics/VMWare/GraphicsAdapter.h +++ b/Kernel/Graphics/VMWare/GraphicsAdapter.h @@ -26,7 +26,8 @@ class VMWareGraphicsAdapter final friend class GraphicsManagement; public: - static LockRefPtr try_initialize(PCI::DeviceIdentifier const&); + static ErrorOr probe(PCI::DeviceIdentifier const&); + static ErrorOr> create(PCI::DeviceIdentifier const&); virtual ~VMWareGraphicsAdapter() = default; virtual StringView device_name() const override { return "VMWareGraphicsAdapter"sv; } diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp index 5e8872011f..040db751d8 100644 --- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp +++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp @@ -22,19 +22,23 @@ namespace Kernel { #define DEVICE_EVENTS_CLEAR 0x4 #define DEVICE_NUM_SCANOUTS 0x8 -NonnullLockRefPtr VirtIOGraphicsAdapter::initialize(PCI::DeviceIdentifier const& device_identifier) +ErrorOr VirtIOGraphicsAdapter::probe(PCI::DeviceIdentifier const& device_identifier) +{ + return device_identifier.hardware_id().vendor_id == PCI::VendorID::VirtIO; +} + +ErrorOr> VirtIOGraphicsAdapter::create(PCI::DeviceIdentifier const& device_identifier) { - VERIFY(device_identifier.hardware_id().vendor_id == PCI::VendorID::VirtIO); // Setup memory transfer region - auto scratch_space_region = MUST(MM.allocate_contiguous_kernel_region( + auto scratch_space_region = TRY(MM.allocate_contiguous_kernel_region( 32 * PAGE_SIZE, "VirtGPU Scratch Space"sv, Memory::Region::Access::ReadWrite)); - auto active_context_ids = MUST(Bitmap::create(VREND_MAX_CTX, false)); - auto adapter = adopt_lock_ref(*new (nothrow) VirtIOGraphicsAdapter(device_identifier, move(active_context_ids), move(scratch_space_region))); + auto active_context_ids = TRY(Bitmap::create(VREND_MAX_CTX, false)); + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VirtIOGraphicsAdapter(device_identifier, move(active_context_ids), move(scratch_space_region)))); adapter->initialize(); - MUST(adapter->initialize_adapter()); + TRY(adapter->initialize_adapter()); return adapter; } diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h index bc6bf22b5e..ec01de1e76 100644 --- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h +++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h @@ -37,7 +37,8 @@ class VirtIOGraphicsAdapter final friend class VirtIOGPU3DDevice; public: - static NonnullLockRefPtr initialize(PCI::DeviceIdentifier const&); + static ErrorOr probe(PCI::DeviceIdentifier const&); + static ErrorOr> create(PCI::DeviceIdentifier const&); virtual void initialize() override;