mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 15:27:34 +00:00
Kernel: Move all Graphics-related code into Devices/GPU directory
Like the HID, Audio and Storage subsystem, the Graphics subsystem (which handles GPUs technically) exposes unix device files (typically in /dev). To ensure consistency across the repository, move all related files to a new directory under Kernel/Devices called "GPU". Also remove the redundant "GPU" word from the VirtIO driver directory, and the word "Graphics" from GraphicsManagement.{h,cpp} filenames.
This commit is contained in:
parent
31a7dabf02
commit
9ee098b119
69 changed files with 167 additions and 167 deletions
69
Kernel/Devices/GPU/VMWare/Console.cpp
Normal file
69
Kernel/Devices/GPU/VMWare/Console.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Devices/GPU/VMWare/Console.h>
|
||||
#include <Kernel/Tasks/WorkQueue.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr static AK::Duration refresh_interval = AK::Duration::from_milliseconds(16);
|
||||
|
||||
NonnullLockRefPtr<VMWareFramebufferConsole> VMWareFramebufferConsole::initialize(VMWareDisplayConnector& parent_display_connector)
|
||||
{
|
||||
auto current_resolution = parent_display_connector.current_mode_setting();
|
||||
return adopt_lock_ref(*new (nothrow) VMWareFramebufferConsole(parent_display_connector, current_resolution));
|
||||
}
|
||||
|
||||
VMWareFramebufferConsole::VMWareFramebufferConsole(VMWareDisplayConnector const& parent_display_connector, DisplayConnector::ModeSetting current_resolution)
|
||||
: GenericFramebufferConsole(current_resolution.horizontal_active, current_resolution.vertical_active, current_resolution.horizontal_stride)
|
||||
, m_parent_display_connector(parent_display_connector)
|
||||
{
|
||||
enqueue_refresh_timer();
|
||||
}
|
||||
|
||||
void VMWareFramebufferConsole::set_resolution(size_t width, size_t height, size_t pitch)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_pitch = pitch;
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void VMWareFramebufferConsole::flush(size_t, size_t, size_t, size_t)
|
||||
{
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void VMWareFramebufferConsole::enqueue_refresh_timer()
|
||||
{
|
||||
auto refresh_timer = adopt_nonnull_ref_or_enomem(new (nothrow) Timer()).release_value_but_fixme_should_propagate_errors();
|
||||
refresh_timer->setup(CLOCK_MONOTONIC, refresh_interval, [this]() {
|
||||
if (m_enabled.load() && m_dirty) {
|
||||
MUST(g_io_work->try_queue([this]() {
|
||||
MUST(m_parent_display_connector->flush_first_surface());
|
||||
m_dirty = false;
|
||||
}));
|
||||
}
|
||||
enqueue_refresh_timer();
|
||||
});
|
||||
TimerQueue::the().add_timer(move(refresh_timer));
|
||||
}
|
||||
|
||||
void VMWareFramebufferConsole::enable()
|
||||
{
|
||||
auto current_resolution = m_parent_display_connector->current_mode_setting();
|
||||
GenericFramebufferConsole::enable();
|
||||
m_width = current_resolution.horizontal_active;
|
||||
m_height = current_resolution.vertical_active;
|
||||
m_pitch = current_resolution.horizontal_stride;
|
||||
}
|
||||
|
||||
u8* VMWareFramebufferConsole::framebuffer_data()
|
||||
{
|
||||
return m_parent_display_connector->framebuffer_data();
|
||||
}
|
||||
|
||||
}
|
32
Kernel/Devices/GPU/VMWare/Console.h
Normal file
32
Kernel/Devices/GPU/VMWare/Console.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/DisplayConnector.h>
|
||||
#include <Kernel/Time/TimerQueue.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class VMWareFramebufferConsole final : public Graphics::GenericFramebufferConsole {
|
||||
public:
|
||||
static NonnullLockRefPtr<VMWareFramebufferConsole> initialize(VMWareDisplayConnector& parent_display_connector);
|
||||
|
||||
virtual void set_resolution(size_t width, size_t height, size_t pitch) override;
|
||||
virtual void flush(size_t x, size_t y, size_t width, size_t height) override;
|
||||
virtual void enable() override;
|
||||
|
||||
private:
|
||||
void enqueue_refresh_timer();
|
||||
virtual u8* framebuffer_data() override;
|
||||
|
||||
VMWareFramebufferConsole(VMWareDisplayConnector const& parent_display_connector, DisplayConnector::ModeSetting current_resolution);
|
||||
LockRefPtr<VMWareDisplayConnector> m_parent_display_connector;
|
||||
bool m_dirty { false };
|
||||
};
|
||||
|
||||
}
|
61
Kernel/Devices/GPU/VMWare/Definitions.h
Normal file
61
Kernel/Devices/GPU/VMWare/Definitions.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
static constexpr size_t vmware_svga_version_2_id = (0x900000UL << 8 | (2));
|
||||
|
||||
enum class VMWareDisplayRegistersOffset {
|
||||
ID = 0,
|
||||
ENABLE = 1,
|
||||
WIDTH = 2,
|
||||
HEIGHT = 3,
|
||||
MAX_WIDTH = 4,
|
||||
MAX_HEIGHT = 5,
|
||||
DEPTH = 6,
|
||||
BITS_PER_PIXEL = 7, /* Current bpp in the guest */
|
||||
PSEUDOCOLOR = 8,
|
||||
RED_MASK = 9,
|
||||
GREEN_MASK = 10,
|
||||
BLUE_MASK = 11,
|
||||
BYTES_PER_LINE = 12,
|
||||
FB_OFFSET = 14,
|
||||
VRAM_SIZE = 15,
|
||||
FB_SIZE = 16,
|
||||
|
||||
CAPABILITIES = 17,
|
||||
MEM_SIZE = 19,
|
||||
CONFIG_DONE = 20, /* Set when memory area configured */
|
||||
SYNC = 21, /* See "FIFO Synchronization Registers" */
|
||||
BUSY = 22, /* See "FIFO Synchronization Registers" */
|
||||
SCRATCH_SIZE = 29, /* Number of scratch registers */
|
||||
MEM_REGS = 30, /* Number of FIFO registers */
|
||||
PITCHLOCK = 32, /* Fixed pitch for all modes */
|
||||
IRQMASK = 33, /* Interrupt mask */
|
||||
|
||||
GMR_ID = 41,
|
||||
GMR_DESCRIPTOR = 42,
|
||||
GMR_MAX_IDS = 43,
|
||||
GMR_MAX_DESCRIPTOR_LENGTH = 44,
|
||||
|
||||
TRACES = 45, /* Enable trace-based updates even when FIFO is on */
|
||||
GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
|
||||
MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] VMWareDisplayFIFORegisters {
|
||||
u32 start;
|
||||
u32 size;
|
||||
u32 next_command;
|
||||
u32 stop;
|
||||
u32 commands[];
|
||||
};
|
||||
|
||||
}
|
133
Kernel/Devices/GPU/VMWare/DisplayConnector.cpp
Normal file
133
Kernel/Devices/GPU/VMWare/DisplayConnector.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Devices/GPU/Management.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/Console.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/DisplayConnector.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
NonnullLockRefPtr<VMWareDisplayConnector> VMWareDisplayConnector::must_create(VMWareGraphicsAdapter const& parent_adapter, PhysicalAddress framebuffer_address, size_t framebuffer_resource_size)
|
||||
{
|
||||
auto connector = MUST(DeviceManagement::try_create_device<VMWareDisplayConnector>(parent_adapter, framebuffer_address, framebuffer_resource_size));
|
||||
MUST(connector->create_attached_framebuffer_console());
|
||||
MUST(connector->initialize_edid_for_generic_monitor(Array<u8, 3> { 'V', 'M', 'W' }));
|
||||
return connector;
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::create_attached_framebuffer_console()
|
||||
{
|
||||
m_framebuffer_console = VMWareFramebufferConsole::initialize(*this);
|
||||
GraphicsManagement::the().set_console(*m_framebuffer_console);
|
||||
return {};
|
||||
}
|
||||
|
||||
VMWareDisplayConnector::VMWareDisplayConnector(VMWareGraphicsAdapter const& parent_adapter, PhysicalAddress framebuffer_address, size_t framebuffer_resource_size)
|
||||
: DisplayConnector(framebuffer_address, framebuffer_resource_size, false)
|
||||
, m_parent_adapter(parent_adapter)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::set_safe_mode_setting()
|
||||
{
|
||||
// We assume safe resolution is 1024x768x32
|
||||
DisplayConnector::ModeSetting safe_mode_setting {
|
||||
.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_setting);
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::unblank()
|
||||
{
|
||||
return Error::from_errno(ENOTIMPL);
|
||||
}
|
||||
|
||||
void VMWareDisplayConnector::enable_console()
|
||||
{
|
||||
VERIFY(m_control_lock.is_locked());
|
||||
VERIFY(m_framebuffer_console);
|
||||
m_framebuffer_console->enable();
|
||||
}
|
||||
|
||||
void VMWareDisplayConnector::disable_console()
|
||||
{
|
||||
VERIFY(m_control_lock.is_locked());
|
||||
VERIFY(m_framebuffer_console);
|
||||
m_framebuffer_console->disable();
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::flush_first_surface()
|
||||
{
|
||||
// FIXME: Cache these values but keep them in sync with the parent adapter.
|
||||
auto width = m_parent_adapter->primary_screen_width({});
|
||||
auto height = m_parent_adapter->primary_screen_height({});
|
||||
m_parent_adapter->primary_screen_flush({}, width, height);
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::set_y_offset(size_t)
|
||||
{
|
||||
return Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::flush_rectangle(size_t, FBRect const&)
|
||||
{
|
||||
// FIXME: It costs really nothing to flush the entire screen (at least in QEMU).
|
||||
// Try to implement better partial rectangle flush method instead here.
|
||||
VERIFY(m_flushing_lock.is_locked());
|
||||
// FIXME: Cache these values but keep them in sync with the parent adapter.
|
||||
auto width = m_parent_adapter->primary_screen_width({});
|
||||
auto height = m_parent_adapter->primary_screen_height({});
|
||||
m_parent_adapter->primary_screen_flush({}, width, height);
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareDisplayConnector::set_mode_setting(ModeSetting const& mode_setting)
|
||||
{
|
||||
SpinlockLocker locker(m_modeset_lock);
|
||||
VERIFY(m_framebuffer_console);
|
||||
size_t width = mode_setting.horizontal_active;
|
||||
size_t height = mode_setting.vertical_active;
|
||||
|
||||
if (Checked<size_t>::multiplication_would_overflow(width, height, sizeof(u32)))
|
||||
return EOVERFLOW;
|
||||
|
||||
TRY(m_parent_adapter->modeset_primary_screen_resolution({}, width, height));
|
||||
|
||||
m_framebuffer_console->set_resolution(width, height, width * sizeof(u32));
|
||||
|
||||
auto pitch = m_parent_adapter->primary_screen_pitch({});
|
||||
DisplayConnector::ModeSetting current_mode_setting {
|
||||
.horizontal_stride = pitch,
|
||||
.pixel_clock_in_khz = 0, // Note: There's no pixel clock in paravirtualized hardware
|
||||
.horizontal_active = width,
|
||||
.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 = height,
|
||||
.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,
|
||||
};
|
||||
m_current_mode_setting = current_mode_setting;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
54
Kernel/Devices/GPU/VMWare/DisplayConnector.h
Normal file
54
Kernel/Devices/GPU/VMWare/DisplayConnector.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Try.h>
|
||||
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/DisplayConnector.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/GraphicsAdapter.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
||||
#include <Kernel/Locking/Spinlock.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class VMWareFramebufferConsole;
|
||||
class VMWareDisplayConnector : public DisplayConnector {
|
||||
friend class VMWareGraphicsAdapter;
|
||||
friend class VMWareFramebufferConsole;
|
||||
friend class DeviceManagement;
|
||||
|
||||
public:
|
||||
static NonnullLockRefPtr<VMWareDisplayConnector> must_create(VMWareGraphicsAdapter const& parent_adapter, PhysicalAddress framebuffer_address, size_t framebuffer_resource_size);
|
||||
|
||||
private:
|
||||
VMWareDisplayConnector(VMWareGraphicsAdapter const& parent_adapter, PhysicalAddress framebuffer_address, size_t framebuffer_resource_size);
|
||||
ErrorOr<void> create_attached_framebuffer_console();
|
||||
|
||||
virtual bool mutable_mode_setting_capable() const override { return true; }
|
||||
virtual bool double_framebuffering_capable() const override { return false; }
|
||||
virtual ErrorOr<void> set_mode_setting(ModeSetting const&) override;
|
||||
virtual ErrorOr<void> set_safe_mode_setting() override;
|
||||
virtual ErrorOr<void> set_y_offset(size_t y) override;
|
||||
virtual ErrorOr<void> unblank() override;
|
||||
|
||||
virtual bool partial_flush_support() const override { return true; }
|
||||
virtual bool flush_support() const override { return true; }
|
||||
// Note: Paravirtualized hardware doesn't require a defined refresh rate for modesetting.
|
||||
virtual bool refresh_rate_support() const override { return false; }
|
||||
|
||||
virtual ErrorOr<void> flush_first_surface() override;
|
||||
virtual ErrorOr<void> flush_rectangle(size_t buffer_index, FBRect const& rect) override;
|
||||
|
||||
virtual void enable_console() override;
|
||||
virtual void disable_console() override;
|
||||
|
||||
private:
|
||||
NonnullLockRefPtr<VMWareGraphicsAdapter> m_parent_adapter;
|
||||
LockRefPtr<VMWareFramebufferConsole> m_framebuffer_console;
|
||||
};
|
||||
}
|
193
Kernel/Devices/GPU/VMWare/GraphicsAdapter.cpp
Normal file
193
Kernel/Devices/GPU/VMWare/GraphicsAdapter.cpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Atomic.h>
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/Try.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/IDs.h>
|
||||
#include <Kernel/Devices/GPU/Console/ContiguousFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/Management.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/Definitions.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/DisplayConnector.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/GraphicsAdapter.h>
|
||||
#include <Kernel/Library/IOWindow.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ErrorOr<bool> VMWareGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
|
||||
{
|
||||
PCI::HardwareID id = pci_device_identifier.hardware_id();
|
||||
// Note: We only support VMWare SVGA II adapter
|
||||
return id.vendor_id == PCI::VendorID::VMWare && id.device_id == 0x0405;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> 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;
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT VMWareGraphicsAdapter::VMWareGraphicsAdapter(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr<IOWindow> registers_io_window)
|
||||
: PCI::Device(const_cast<PCI::DeviceIdentifier&>(pci_device_identifier))
|
||||
, m_registers_io_window(move(registers_io_window))
|
||||
{
|
||||
dbgln("VMWare SVGA @ {}, {}", pci_device_identifier.address(), m_registers_io_window);
|
||||
}
|
||||
|
||||
u32 VMWareGraphicsAdapter::read_io_register(VMWareDisplayRegistersOffset register_offset) const
|
||||
{
|
||||
SpinlockLocker locker(m_io_access_lock);
|
||||
m_registers_io_window->write32(0, to_underlying(register_offset));
|
||||
return m_registers_io_window->read32_unaligned(1);
|
||||
}
|
||||
void VMWareGraphicsAdapter::write_io_register(VMWareDisplayRegistersOffset register_offset, u32 value)
|
||||
{
|
||||
SpinlockLocker locker(m_io_access_lock);
|
||||
m_registers_io_window->write32(0, to_underlying(register_offset));
|
||||
m_registers_io_window->write32_unaligned(1, value);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::negotiate_device_version()
|
||||
{
|
||||
write_io_register(VMWareDisplayRegistersOffset::ID, vmware_svga_version_2_id);
|
||||
auto accepted_version = read_io_register(VMWareDisplayRegistersOffset::ID);
|
||||
dbgln("VMWare SVGA @ {}: Accepted version {}", device_identifier().address(), accepted_version);
|
||||
if (read_io_register(VMWareDisplayRegistersOffset::ID) == vmware_svga_version_2_id)
|
||||
return {};
|
||||
return Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::initialize_fifo_registers()
|
||||
{
|
||||
auto framebuffer_size = read_io_register(VMWareDisplayRegistersOffset::FB_SIZE);
|
||||
auto fifo_size = read_io_register(VMWareDisplayRegistersOffset::MEM_SIZE);
|
||||
auto fifo_physical_address = PhysicalAddress(PCI::get_BAR2(device_identifier()) & PCI::bar_address_mask);
|
||||
|
||||
dbgln("VMWare SVGA @ {}: framebuffer size {} bytes, FIFO size {} bytes @ {}", device_identifier().address(), framebuffer_size, fifo_size, fifo_physical_address);
|
||||
if (framebuffer_size < 0x100000 || fifo_size < 0x10000) {
|
||||
dbgln("VMWare SVGA @ {}: invalid framebuffer or fifo size", device_identifier().address());
|
||||
return Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
m_fifo_registers = TRY(Memory::map_typed<VMWareDisplayFIFORegisters volatile>(fifo_physical_address, fifo_size, Memory::Region::Access::ReadWrite));
|
||||
m_fifo_registers->start = 16;
|
||||
m_fifo_registers->size = 16 + (10 * 1024);
|
||||
m_fifo_registers->next_command = 16;
|
||||
m_fifo_registers->stop = 16;
|
||||
return {};
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void VMWareGraphicsAdapter::print_svga_capabilities() const
|
||||
{
|
||||
auto svga_capabilities = read_io_register(VMWareDisplayRegistersOffset::CAPABILITIES);
|
||||
dbgln("VMWare SVGA capabilities (raw {:x}):", svga_capabilities);
|
||||
if (svga_capabilities & (1 << 1))
|
||||
dbgln("\tRect copy");
|
||||
if (svga_capabilities & (1 << 5))
|
||||
dbgln("\tCursor");
|
||||
if (svga_capabilities & (1 << 6))
|
||||
dbgln("\tCursor Bypass");
|
||||
if (svga_capabilities & (1 << 7))
|
||||
dbgln("\tCursor Bypass 2");
|
||||
if (svga_capabilities & (1 << 8))
|
||||
dbgln("\t8 Bit emulation");
|
||||
if (svga_capabilities & (1 << 9))
|
||||
dbgln("\tAlpha Cursor");
|
||||
if (svga_capabilities & (1 << 14))
|
||||
dbgln("\t3D acceleration");
|
||||
if (svga_capabilities & (1 << 15))
|
||||
dbgln("\tExtended FIFO");
|
||||
if (svga_capabilities & (1 << 16))
|
||||
dbgln("\tMulti-monitor (legacy)");
|
||||
if (svga_capabilities & (1 << 17))
|
||||
dbgln("\tPitch lock");
|
||||
if (svga_capabilities & (1 << 18))
|
||||
dbgln("\tIRQ masking");
|
||||
if (svga_capabilities & (1 << 19))
|
||||
dbgln("\tDisplay topology");
|
||||
if (svga_capabilities & (1 << 20))
|
||||
dbgln("\tGMR");
|
||||
if (svga_capabilities & (1 << 21))
|
||||
dbgln("\tTraces");
|
||||
if (svga_capabilities & (1 << 22))
|
||||
dbgln("\tGMR2");
|
||||
if (svga_capabilities & (1 << 23))
|
||||
dbgln("\tScreen object 2");
|
||||
}
|
||||
|
||||
ErrorOr<void> VMWareGraphicsAdapter::modeset_primary_screen_resolution(Badge<VMWareDisplayConnector>, size_t width, size_t height)
|
||||
{
|
||||
auto max_width = read_io_register(VMWareDisplayRegistersOffset::MAX_WIDTH);
|
||||
auto max_height = read_io_register(VMWareDisplayRegistersOffset::MAX_HEIGHT);
|
||||
if (width > max_width || height > max_height)
|
||||
return Error::from_errno(ENOTSUP);
|
||||
modeset_primary_screen_resolution(width, height);
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t VMWareGraphicsAdapter::primary_screen_width(Badge<VMWareDisplayConnector>) const
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
return read_io_register(VMWareDisplayRegistersOffset::WIDTH);
|
||||
}
|
||||
size_t VMWareGraphicsAdapter::primary_screen_height(Badge<VMWareDisplayConnector>) const
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
return read_io_register(VMWareDisplayRegistersOffset::HEIGHT);
|
||||
}
|
||||
size_t VMWareGraphicsAdapter::primary_screen_pitch(Badge<VMWareDisplayConnector>) const
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
return read_io_register(VMWareDisplayRegistersOffset::BYTES_PER_LINE);
|
||||
}
|
||||
|
||||
void VMWareGraphicsAdapter::primary_screen_flush(Badge<VMWareDisplayConnector>, size_t current_width, size_t current_height)
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
m_fifo_registers->start = 16;
|
||||
m_fifo_registers->size = 16 + (10 * 1024);
|
||||
m_fifo_registers->next_command = 16 + 4 * 5;
|
||||
m_fifo_registers->stop = 16;
|
||||
m_fifo_registers->commands[0] = 1;
|
||||
m_fifo_registers->commands[1] = 0;
|
||||
m_fifo_registers->commands[2] = 0;
|
||||
m_fifo_registers->commands[3] = current_width;
|
||||
m_fifo_registers->commands[4] = current_height;
|
||||
write_io_register(VMWareDisplayRegistersOffset::SYNC, 1);
|
||||
}
|
||||
|
||||
void VMWareGraphicsAdapter::modeset_primary_screen_resolution(size_t width, size_t height)
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
write_io_register(VMWareDisplayRegistersOffset::ENABLE, 0);
|
||||
write_io_register(VMWareDisplayRegistersOffset::WIDTH, width);
|
||||
write_io_register(VMWareDisplayRegistersOffset::HEIGHT, height);
|
||||
write_io_register(VMWareDisplayRegistersOffset::BITS_PER_PIXEL, 32);
|
||||
write_io_register(VMWareDisplayRegistersOffset::ENABLE, 1);
|
||||
write_io_register(VMWareDisplayRegistersOffset::CONFIG_DONE, 1);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::initialize_adapter()
|
||||
{
|
||||
TRY(negotiate_device_version());
|
||||
print_svga_capabilities();
|
||||
TRY(initialize_fifo_registers());
|
||||
// Note: enable the device by modesetting the primary screen resolution
|
||||
modeset_primary_screen_resolution(640, 480);
|
||||
|
||||
auto bar1_space_size = PCI::get_BAR_space_size(device_identifier(), PCI::HeaderType0BaseRegister::BAR1);
|
||||
|
||||
m_display_connector = VMWareDisplayConnector::must_create(*this, PhysicalAddress(PCI::get_BAR1(device_identifier()) & PCI::bar_address_mask), bar1_space_size);
|
||||
TRY(m_display_connector->set_safe_mode_setting());
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
61
Kernel/Devices/GPU/VMWare/GraphicsAdapter.h
Normal file
61
Kernel/Devices/GPU/VMWare/GraphicsAdapter.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Bus/PCI/Device.h>
|
||||
#include <Kernel/Devices/GPU/GenericGraphicsAdapter.h>
|
||||
#include <Kernel/Devices/GPU/VMWare/Definitions.h>
|
||||
#include <Kernel/Library/IOWindow.h>
|
||||
#include <Kernel/Locking/Spinlock.h>
|
||||
#include <Kernel/Memory/PhysicalAddress.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class GraphicsManagement;
|
||||
|
||||
class VMWareDisplayConnector;
|
||||
class VMWareGraphicsAdapter final
|
||||
: public GenericGraphicsAdapter
|
||||
, public PCI::Device {
|
||||
friend class GraphicsManagement;
|
||||
|
||||
public:
|
||||
static ErrorOr<bool> probe(PCI::DeviceIdentifier const&);
|
||||
static ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> create(PCI::DeviceIdentifier const&);
|
||||
virtual ~VMWareGraphicsAdapter() = default;
|
||||
|
||||
virtual StringView device_name() const override { return "VMWareGraphicsAdapter"sv; }
|
||||
|
||||
ErrorOr<void> modeset_primary_screen_resolution(Badge<VMWareDisplayConnector>, size_t width, size_t height);
|
||||
size_t primary_screen_width(Badge<VMWareDisplayConnector>) const;
|
||||
size_t primary_screen_height(Badge<VMWareDisplayConnector>) const;
|
||||
size_t primary_screen_pitch(Badge<VMWareDisplayConnector>) const;
|
||||
void primary_screen_flush(Badge<VMWareDisplayConnector>, size_t current_width, size_t current_height);
|
||||
|
||||
private:
|
||||
ErrorOr<void> initialize_adapter();
|
||||
ErrorOr<void> initialize_fifo_registers();
|
||||
ErrorOr<void> negotiate_device_version();
|
||||
|
||||
u32 read_io_register(VMWareDisplayRegistersOffset) const;
|
||||
void write_io_register(VMWareDisplayRegistersOffset, u32 value);
|
||||
|
||||
void print_svga_capabilities() const;
|
||||
void modeset_primary_screen_resolution(size_t width, size_t height);
|
||||
|
||||
VMWareGraphicsAdapter(PCI::DeviceIdentifier const&, NonnullOwnPtr<IOWindow> registers_io_window);
|
||||
|
||||
Memory::TypedMapping<VMWareDisplayFIFORegisters volatile> m_fifo_registers;
|
||||
LockRefPtr<VMWareDisplayConnector> m_display_connector;
|
||||
mutable NonnullOwnPtr<IOWindow> m_registers_io_window;
|
||||
mutable Spinlock<LockRank::None> m_io_access_lock {};
|
||||
mutable RecursiveSpinlock<LockRank::None> m_operation_lock {};
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue