GraphicsAdapter.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Atomic.h>
  7. #include <AK/Checked.h>
  8. #include <AK/Try.h>
  9. #include <Kernel/Bus/PCI/API.h>
  10. #include <Kernel/Bus/PCI/IDs.h>
  11. #include <Kernel/Graphics/Console/ContiguousFramebufferConsole.h>
  12. #include <Kernel/Graphics/GraphicsManagement.h>
  13. #include <Kernel/Graphics/VMWare/Definitions.h>
  14. #include <Kernel/Graphics/VMWare/DisplayConnector.h>
  15. #include <Kernel/Graphics/VMWare/GraphicsAdapter.h>
  16. #include <Kernel/IOWindow.h>
  17. #include <Kernel/Memory/TypedMapping.h>
  18. #include <Kernel/Sections.h>
  19. namespace Kernel {
  20. ErrorOr<bool> VMWareGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
  21. {
  22. PCI::HardwareID id = pci_device_identifier.hardware_id();
  23. // Note: We only support VMWare SVGA II adapter
  24. return id.vendor_id == PCI::VendorID::VMWare && id.device_id == 0x0405;
  25. }
  26. ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> VMWareGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier)
  27. {
  28. auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0));
  29. auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VMWareGraphicsAdapter(pci_device_identifier, move(registers_io_window))));
  30. TRY(adapter->initialize_adapter());
  31. return adapter;
  32. }
  33. UNMAP_AFTER_INIT VMWareGraphicsAdapter::VMWareGraphicsAdapter(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr<IOWindow> registers_io_window)
  34. : PCI::Device(const_cast<PCI::DeviceIdentifier&>(pci_device_identifier))
  35. , m_registers_io_window(move(registers_io_window))
  36. {
  37. dbgln("VMWare SVGA @ {}, {}", pci_device_identifier.address(), m_registers_io_window);
  38. }
  39. u32 VMWareGraphicsAdapter::read_io_register(VMWareDisplayRegistersOffset register_offset) const
  40. {
  41. SpinlockLocker locker(m_io_access_lock);
  42. m_registers_io_window->write32(0, to_underlying(register_offset));
  43. return m_registers_io_window->read32_unaligned(1);
  44. }
  45. void VMWareGraphicsAdapter::write_io_register(VMWareDisplayRegistersOffset register_offset, u32 value)
  46. {
  47. SpinlockLocker locker(m_io_access_lock);
  48. m_registers_io_window->write32(0, to_underlying(register_offset));
  49. m_registers_io_window->write32_unaligned(1, value);
  50. }
  51. UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::negotiate_device_version()
  52. {
  53. write_io_register(VMWareDisplayRegistersOffset::ID, vmware_svga_version_2_id);
  54. auto accepted_version = read_io_register(VMWareDisplayRegistersOffset::ID);
  55. dbgln("VMWare SVGA @ {}: Accepted version {}", device_identifier().address(), accepted_version);
  56. if (read_io_register(VMWareDisplayRegistersOffset::ID) == vmware_svga_version_2_id)
  57. return {};
  58. return Error::from_errno(ENOTSUP);
  59. }
  60. UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::initialize_fifo_registers()
  61. {
  62. auto framebuffer_size = read_io_register(VMWareDisplayRegistersOffset::FB_SIZE);
  63. auto fifo_size = read_io_register(VMWareDisplayRegistersOffset::MEM_SIZE);
  64. auto fifo_physical_address = PhysicalAddress(PCI::get_BAR2(device_identifier()) & 0xfffffff0);
  65. dbgln("VMWare SVGA @ {}: framebuffer size {} bytes, FIFO size {} bytes @ {}", device_identifier().address(), framebuffer_size, fifo_size, fifo_physical_address);
  66. if (framebuffer_size < 0x100000 || fifo_size < 0x10000) {
  67. dbgln("VMWare SVGA @ {}: invalid framebuffer or fifo size", device_identifier().address());
  68. return Error::from_errno(ENOTSUP);
  69. }
  70. m_fifo_registers = TRY(Memory::map_typed<VMWareDisplayFIFORegisters volatile>(fifo_physical_address, fifo_size, Memory::Region::Access::ReadWrite));
  71. m_fifo_registers->start = 16;
  72. m_fifo_registers->size = 16 + (10 * 1024);
  73. m_fifo_registers->next_command = 16;
  74. m_fifo_registers->stop = 16;
  75. return {};
  76. }
  77. UNMAP_AFTER_INIT void VMWareGraphicsAdapter::print_svga_capabilities() const
  78. {
  79. auto svga_capabilities = read_io_register(VMWareDisplayRegistersOffset::CAPABILITIES);
  80. dbgln("VMWare SVGA capabilities (raw {:x}):", svga_capabilities);
  81. if (svga_capabilities & (1 << 1))
  82. dbgln("\tRect copy");
  83. if (svga_capabilities & (1 << 5))
  84. dbgln("\tCursor");
  85. if (svga_capabilities & (1 << 6))
  86. dbgln("\tCursor Bypass");
  87. if (svga_capabilities & (1 << 7))
  88. dbgln("\tCursor Bypass 2");
  89. if (svga_capabilities & (1 << 8))
  90. dbgln("\t8 Bit emulation");
  91. if (svga_capabilities & (1 << 9))
  92. dbgln("\tAlpha Cursor");
  93. if (svga_capabilities & (1 << 14))
  94. dbgln("\t3D acceleration");
  95. if (svga_capabilities & (1 << 15))
  96. dbgln("\tExtended FIFO");
  97. if (svga_capabilities & (1 << 16))
  98. dbgln("\tMulti-monitor (legacy)");
  99. if (svga_capabilities & (1 << 17))
  100. dbgln("\tPitch lock");
  101. if (svga_capabilities & (1 << 18))
  102. dbgln("\tIRQ masking");
  103. if (svga_capabilities & (1 << 19))
  104. dbgln("\tDisplay topology");
  105. if (svga_capabilities & (1 << 20))
  106. dbgln("\tGMR");
  107. if (svga_capabilities & (1 << 21))
  108. dbgln("\tTraces");
  109. if (svga_capabilities & (1 << 22))
  110. dbgln("\tGMR2");
  111. if (svga_capabilities & (1 << 23))
  112. dbgln("\tScreen object 2");
  113. }
  114. ErrorOr<void> VMWareGraphicsAdapter::modeset_primary_screen_resolution(Badge<VMWareDisplayConnector>, size_t width, size_t height)
  115. {
  116. auto max_width = read_io_register(VMWareDisplayRegistersOffset::MAX_WIDTH);
  117. auto max_height = read_io_register(VMWareDisplayRegistersOffset::MAX_HEIGHT);
  118. if (width > max_width || height > max_height)
  119. return Error::from_errno(ENOTSUP);
  120. modeset_primary_screen_resolution(width, height);
  121. return {};
  122. }
  123. size_t VMWareGraphicsAdapter::primary_screen_width(Badge<VMWareDisplayConnector>) const
  124. {
  125. SpinlockLocker locker(m_operation_lock);
  126. return read_io_register(VMWareDisplayRegistersOffset::WIDTH);
  127. }
  128. size_t VMWareGraphicsAdapter::primary_screen_height(Badge<VMWareDisplayConnector>) const
  129. {
  130. SpinlockLocker locker(m_operation_lock);
  131. return read_io_register(VMWareDisplayRegistersOffset::HEIGHT);
  132. }
  133. size_t VMWareGraphicsAdapter::primary_screen_pitch(Badge<VMWareDisplayConnector>) const
  134. {
  135. SpinlockLocker locker(m_operation_lock);
  136. return read_io_register(VMWareDisplayRegistersOffset::BYTES_PER_LINE);
  137. }
  138. void VMWareGraphicsAdapter::primary_screen_flush(Badge<VMWareDisplayConnector>, size_t current_width, size_t current_height)
  139. {
  140. SpinlockLocker locker(m_operation_lock);
  141. m_fifo_registers->start = 16;
  142. m_fifo_registers->size = 16 + (10 * 1024);
  143. m_fifo_registers->next_command = 16 + 4 * 5;
  144. m_fifo_registers->stop = 16;
  145. m_fifo_registers->commands[0] = 1;
  146. m_fifo_registers->commands[1] = 0;
  147. m_fifo_registers->commands[2] = 0;
  148. m_fifo_registers->commands[3] = current_width;
  149. m_fifo_registers->commands[4] = current_height;
  150. write_io_register(VMWareDisplayRegistersOffset::SYNC, 1);
  151. }
  152. void VMWareGraphicsAdapter::modeset_primary_screen_resolution(size_t width, size_t height)
  153. {
  154. SpinlockLocker locker(m_operation_lock);
  155. write_io_register(VMWareDisplayRegistersOffset::ENABLE, 0);
  156. write_io_register(VMWareDisplayRegistersOffset::WIDTH, width);
  157. write_io_register(VMWareDisplayRegistersOffset::HEIGHT, height);
  158. write_io_register(VMWareDisplayRegistersOffset::BITS_PER_PIXEL, 32);
  159. write_io_register(VMWareDisplayRegistersOffset::ENABLE, 1);
  160. write_io_register(VMWareDisplayRegistersOffset::CONFIG_DONE, 1);
  161. }
  162. UNMAP_AFTER_INIT ErrorOr<void> VMWareGraphicsAdapter::initialize_adapter()
  163. {
  164. TRY(negotiate_device_version());
  165. print_svga_capabilities();
  166. TRY(initialize_fifo_registers());
  167. // Note: enable the device by modesetting the primary screen resolution
  168. modeset_primary_screen_resolution(640, 480);
  169. auto bar1_space_size = PCI::get_BAR_space_size(device_identifier(), PCI::HeaderType0BaseRegister::BAR1);
  170. m_display_connector = VMWareDisplayConnector::must_create(*this, PhysicalAddress(PCI::get_BAR1(device_identifier()) & 0xfffffff0), bar1_space_size);
  171. TRY(m_display_connector->set_safe_mode_setting());
  172. return {};
  173. }
  174. }