diff --git a/Kernel/Graphics/Bochs/DisplayConnector.cpp b/Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.cpp similarity index 98% rename from Kernel/Graphics/Bochs/DisplayConnector.cpp rename to Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.cpp index 62e9b99ed5..4f52ed358d 100644 --- a/Kernel/Graphics/Bochs/DisplayConnector.cpp +++ b/Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.cpp @@ -4,11 +4,12 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include #include #include -#include #include #include diff --git a/Kernel/Graphics/Bochs/DisplayConnector.h b/Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.h similarity index 97% rename from Kernel/Graphics/Bochs/DisplayConnector.h rename to Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.h index 4359b4aecf..b13976d8b4 100644 --- a/Kernel/Graphics/Bochs/DisplayConnector.h +++ b/Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.h @@ -26,9 +26,9 @@ public: static NonnullLockRefPtr must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, bool virtual_box_hardware); - virtual IndexID index_id() const; +private: + IndexID index_id() const; -protected: ErrorOr create_attached_framebuffer_console(); BochsDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size); diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index ebb2ce04cb..2e3f230918 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -66,7 +66,6 @@ set(KERNEL_SOURCES Devices/HID/KeyboardDevice.cpp Devices/HID/MouseDevice.cpp GlobalProcessExposed.cpp - Graphics/Bochs/DisplayConnector.cpp Graphics/Bochs/GraphicsAdapter.cpp Graphics/Bochs/QEMUDisplayConnector.cpp Graphics/Console/BootFramebufferConsole.cpp @@ -333,6 +332,7 @@ if ("${SERENITY_ARCH}" STREQUAL "i686" OR "${SERENITY_ARCH}" STREQUAL "x86_64") Arch/x86/common/SmapDisabler.cpp Arch/x86/common/Shutdown.cpp + Arch/x86/Hypervisor/BochsDisplayConnector.cpp Arch/x86/Hypervisor/VMWareBackdoor.cpp Arch/x86/ISABus/HID/PS2KeyboardDevice.cpp diff --git a/Kernel/Graphics/Bochs/GraphicsAdapter.cpp b/Kernel/Graphics/Bochs/GraphicsAdapter.cpp index 7a41ff9217..33d1a5e13b 100644 --- a/Kernel/Graphics/Bochs/GraphicsAdapter.cpp +++ b/Kernel/Graphics/Bochs/GraphicsAdapter.cpp @@ -7,11 +7,13 @@ #include #include #include +#if ARCH(I386) || ARCH(X86_64) +# include +#endif #include #include #include #include -#include #include #include #include @@ -40,6 +42,10 @@ UNMAP_AFTER_INIT ErrorOr BochsGraphicsAdapter::initialize_adapter(PCI::Dev // Note: If we use VirtualBox graphics adapter (which is based on Bochs one), we need to use IO ports // Note: Bochs (the real bochs graphics adapter in the Bochs emulator) uses revision ID of 0x0 // and doesn't support memory-mapped IO registers. + + // Note: In non x86-builds, we should never encounter VirtualBox hardware nor Pure Bochs VBE graphics, + // so just assume we can use the QEMU BochsVBE-compatible graphics adapter only. +#if ARCH(I386) || ARCH(X86_64) bool virtual_box_hardware = (pci_device_identifier.hardware_id().vendor_id == 0x80ee && pci_device_identifier.hardware_id().device_id == 0xbeef); auto bar0_space_size = PCI::get_BAR_space_size(pci_device_identifier.address(), PCI::HeaderType0BaseRegister::BAR0); if (pci_device_identifier.revision_id().value() == 0x0 || virtual_box_hardware) { @@ -49,6 +55,11 @@ UNMAP_AFTER_INIT ErrorOr BochsGraphicsAdapter::initialize_adapter(PCI::Dev VERIFY(registers_mapping.region); m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR0(pci_device_identifier.address()) & 0xfffffff0), bar0_space_size, move(registers_mapping)); } +#else + auto registers_mapping = TRY(Memory::map_typed_writable(PhysicalAddress(PCI::get_BAR2(pci_device_identifier.address()) & 0xfffffff0))); + VERIFY(registers_mapping.region); + m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR0(pci_device_identifier.address()) & 0xfffffff0), bar0_space_size, move(registers_mapping)); +#endif // Note: According to Gerd Hoffmann - "The linux driver simply does // the unblank unconditionally. With bochs-display this is not needed but diff --git a/Kernel/Graphics/Bochs/GraphicsAdapter.h b/Kernel/Graphics/Bochs/GraphicsAdapter.h index d5ba3910f8..bb298a3a5f 100644 --- a/Kernel/Graphics/Bochs/GraphicsAdapter.h +++ b/Kernel/Graphics/Bochs/GraphicsAdapter.h @@ -19,7 +19,6 @@ namespace Kernel { class GraphicsManagement; struct BochsDisplayMMIORegisters; -class BochsDisplayConnector; class BochsGraphicsAdapter final : public GenericGraphicsAdapter , public PCI::Device { friend class GraphicsManagement; @@ -33,6 +32,6 @@ private: explicit BochsGraphicsAdapter(PCI::DeviceIdentifier const&); - LockRefPtr m_display_connector; + LockRefPtr m_display_connector; }; } diff --git a/Kernel/Graphics/Bochs/QEMUDisplayConnector.cpp b/Kernel/Graphics/Bochs/QEMUDisplayConnector.cpp index d74f788ef8..69d1a5bc58 100644 --- a/Kernel/Graphics/Bochs/QEMUDisplayConnector.cpp +++ b/Kernel/Graphics/Bochs/QEMUDisplayConnector.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -31,8 +32,54 @@ ErrorOr QEMUDisplayConnector::fetch_and_initialize_edid() return {}; } +ErrorOr QEMUDisplayConnector::create_attached_framebuffer_console() +{ + // We assume safe resolution is 1024x768x32 + m_framebuffer_console = Graphics::ContiguousFramebufferConsole::initialize(m_framebuffer_address.value(), 1024, 768, 1024 * sizeof(u32)); + GraphicsManagement::the().set_console(*m_framebuffer_console); + return {}; +} + +void QEMUDisplayConnector::enable_console() +{ + VERIFY(m_control_lock.is_locked()); + VERIFY(m_framebuffer_console); + m_framebuffer_console->enable(); +} + +void QEMUDisplayConnector::disable_console() +{ + VERIFY(m_control_lock.is_locked()); + VERIFY(m_framebuffer_console); + m_framebuffer_console->disable(); +} + +ErrorOr QEMUDisplayConnector::flush_first_surface() +{ + return Error::from_errno(ENOTSUP); +} + +ErrorOr QEMUDisplayConnector::set_safe_mode_setting() +{ + DisplayConnector::ModeSetting safe_mode_set { + .horizontal_stride = 1024 * sizeof(u32), + .pixel_clock_in_khz = 0, // Note: There's no pixel clock in paravirtualized hardware + .horizontal_active = 1024, + .horizontal_front_porch_pixels = 0, // Note: There's no horizontal_front_porch_pixels in paravirtualized hardware + .horizontal_sync_time_pixels = 0, // Note: There's no horizontal_sync_time_pixels in paravirtualized hardware + .horizontal_blank_pixels = 0, // Note: There's no horizontal_blank_pixels in paravirtualized hardware + .vertical_active = 768, + .vertical_front_porch_lines = 0, // Note: There's no vertical_front_porch_lines in paravirtualized hardware + .vertical_sync_time_lines = 0, // Note: There's no vertical_sync_time_lines in paravirtualized hardware + .vertical_blank_lines = 0, // Note: There's no vertical_blank_lines in paravirtualized hardware + .horizontal_offset = 0, + .vertical_offset = 0, + }; + return set_mode_setting(safe_mode_set); +} + QEMUDisplayConnector::QEMUDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping registers_mapping) - : BochsDisplayConnector(framebuffer_address, framebuffer_resource_size) + : DisplayConnector(framebuffer_address, framebuffer_resource_size, false) , m_registers(move(registers_mapping)) { } diff --git a/Kernel/Graphics/Bochs/QEMUDisplayConnector.h b/Kernel/Graphics/Bochs/QEMUDisplayConnector.h index b08cc1b47b..4fa68d3e8d 100644 --- a/Kernel/Graphics/Bochs/QEMUDisplayConnector.h +++ b/Kernel/Graphics/Bochs/QEMUDisplayConnector.h @@ -7,8 +7,9 @@ #pragma once #include -#include +#include #include +#include #include #include #include @@ -17,28 +18,42 @@ namespace Kernel { struct BochsDisplayMMIORegisters; class QEMUDisplayConnector final - : public BochsDisplayConnector { + : public DisplayConnector { friend class BochsGraphicsAdapter; friend class DeviceManagement; public: + AK_TYPEDEF_DISTINCT_ORDERED_ID(u16, IndexID); + static NonnullLockRefPtr must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping); - virtual IndexID index_id() const override; - private: + IndexID index_id() const; + ErrorOr fetch_and_initialize_edid(); + ErrorOr create_attached_framebuffer_console(); QEMUDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping); + virtual bool mutable_mode_setting_capable() const override final { return true; } virtual bool double_framebuffering_capable() const override { return true; } virtual ErrorOr set_mode_setting(ModeSetting const&) override; virtual ErrorOr set_y_offset(size_t y) override; + virtual ErrorOr set_safe_mode_setting() override final; virtual ErrorOr unblank() override; + virtual bool partial_flush_support() const override final { return false; } + virtual bool flush_support() const override final { return false; } + // Note: Paravirtualized hardware doesn't require a defined refresh rate for modesetting. + virtual bool refresh_rate_support() const override final { return false; } + virtual ErrorOr flush_first_surface() override final; void set_framebuffer_to_big_endian_format(); void set_framebuffer_to_little_endian_format(); -private: + virtual void enable_console() override final; + virtual void disable_console() override final; + + LockRefPtr m_framebuffer_console; + Memory::TypedMapping m_registers; }; }