GraphicsAdapter.cpp 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. #if ARCH(X86_64)
  10. # include <Kernel/Arch/x86_64/Hypervisor/BochsDisplayConnector.h>
  11. #endif
  12. #include <Kernel/Bus/PCI/API.h>
  13. #include <Kernel/Bus/PCI/IDs.h>
  14. #include <Kernel/Graphics/Bochs/Definitions.h>
  15. #include <Kernel/Graphics/Bochs/GraphicsAdapter.h>
  16. #include <Kernel/Graphics/Bochs/QEMUDisplayConnector.h>
  17. #include <Kernel/Graphics/Console/ContiguousFramebufferConsole.h>
  18. #include <Kernel/Graphics/GraphicsManagement.h>
  19. #include <Kernel/Memory/TypedMapping.h>
  20. #include <Kernel/Sections.h>
  21. namespace Kernel {
  22. UNMAP_AFTER_INIT ErrorOr<bool> BochsGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
  23. {
  24. PCI::HardwareID id = pci_device_identifier.hardware_id();
  25. if (id.vendor_id == PCI::VendorID::QEMUOld && id.device_id == 0x1111)
  26. return true;
  27. if (id.vendor_id == PCI::VendorID::VirtualBox && id.device_id == 0xbeef)
  28. return true;
  29. return false;
  30. }
  31. UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> BochsGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier)
  32. {
  33. auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) BochsGraphicsAdapter(pci_device_identifier)));
  34. MUST(adapter->initialize_adapter(pci_device_identifier));
  35. return adapter;
  36. }
  37. UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::DeviceIdentifier const& device_identifier)
  38. : PCI::Device(const_cast<PCI::DeviceIdentifier&>(device_identifier))
  39. {
  40. }
  41. UNMAP_AFTER_INIT ErrorOr<void> BochsGraphicsAdapter::initialize_adapter(PCI::DeviceIdentifier const& pci_device_identifier)
  42. {
  43. // Note: If we use VirtualBox graphics adapter (which is based on Bochs one), we need to use IO ports
  44. // Note: Bochs (the real bochs graphics adapter in the Bochs emulator) uses revision ID of 0x0
  45. // and doesn't support memory-mapped IO registers.
  46. // Note: In non x86-builds, we should never encounter VirtualBox hardware nor Pure Bochs VBE graphics,
  47. // so just assume we can use the QEMU BochsVBE-compatible graphics adapter only.
  48. auto bar0_space_size = PCI::get_BAR_space_size(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0);
  49. #if ARCH(X86_64)
  50. bool virtual_box_hardware = (pci_device_identifier.hardware_id().vendor_id == 0x80ee && pci_device_identifier.hardware_id().device_id == 0xbeef);
  51. if (pci_device_identifier.revision_id().value() == 0x0 || virtual_box_hardware) {
  52. m_display_connector = BochsDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR0(pci_device_identifier) & 0xfffffff0), bar0_space_size, virtual_box_hardware);
  53. } else {
  54. auto registers_mapping = TRY(Memory::map_typed_writable<BochsDisplayMMIORegisters volatile>(PhysicalAddress(PCI::get_BAR2(pci_device_identifier) & 0xfffffff0)));
  55. VERIFY(registers_mapping.region);
  56. m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR0(pci_device_identifier) & 0xfffffff0), bar0_space_size, move(registers_mapping));
  57. }
  58. #else
  59. auto registers_mapping = TRY(Memory::map_typed_writable<BochsDisplayMMIORegisters volatile>(PhysicalAddress(PCI::get_BAR2(pci_device_identifier.address()) & 0xfffffff0)));
  60. VERIFY(registers_mapping.region);
  61. m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(PCI::get_BAR0(pci_device_identifier) & 0xfffffff0), bar0_space_size, move(registers_mapping));
  62. #endif
  63. // Note: According to Gerd Hoffmann - "The linux driver simply does
  64. // the unblank unconditionally. With bochs-display this is not needed but
  65. // it also has no bad side effect".
  66. // FIXME: If the error is ENOTIMPL, ignore it for now until we implement
  67. // unblank support for VBoxDisplayConnector class too.
  68. auto result = m_display_connector->unblank();
  69. if (result.is_error() && result.error().code() != ENOTIMPL)
  70. return result;
  71. TRY(m_display_connector->set_safe_mode_setting());
  72. return {};
  73. }
  74. }