GraphicsManagement.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Checked.h>
  7. #include <AK/Singleton.h>
  8. #include <Kernel/CommandLine.h>
  9. #include <Kernel/Debug.h>
  10. #include <Kernel/Graphics/BochsGraphicsAdapter.h>
  11. #include <Kernel/Graphics/Console/FramebufferConsole.h>
  12. #include <Kernel/Graphics/Console/TextModeConsole.h>
  13. #include <Kernel/Graphics/GraphicsManagement.h>
  14. #include <Kernel/Graphics/IntelNativeGraphicsAdapter.h>
  15. #include <Kernel/Graphics/VGACompatibleAdapter.h>
  16. #include <Kernel/IO.h>
  17. #include <Kernel/Multiboot.h>
  18. #include <Kernel/VM/AnonymousVMObject.h>
  19. namespace Kernel {
  20. static AK::Singleton<GraphicsManagement> s_the;
  21. GraphicsManagement& GraphicsManagement::the()
  22. {
  23. return *s_the;
  24. }
  25. bool GraphicsManagement::is_initialized()
  26. {
  27. return s_the.is_initialized();
  28. }
  29. UNMAP_AFTER_INIT GraphicsManagement::GraphicsManagement()
  30. : m_vga_font_region(MM.allocate_kernel_region(PAGE_SIZE, "VGA font", Region::Access::Read | Region::Access::Write, AllocationStrategy::AllocateNow).release_nonnull())
  31. , m_framebuffer_devices_allowed(!kernel_command_line().is_no_framebuffer_devices_mode())
  32. {
  33. }
  34. void GraphicsManagement::deactivate_graphical_mode()
  35. {
  36. for (auto& graphics_device : m_graphics_devices) {
  37. graphics_device.enable_consoles();
  38. }
  39. }
  40. void GraphicsManagement::activate_graphical_mode()
  41. {
  42. for (auto& graphics_device : m_graphics_devices) {
  43. graphics_device.disable_consoles();
  44. }
  45. }
  46. UNMAP_AFTER_INIT RefPtr<GraphicsDevice> GraphicsManagement::determine_graphics_device(PCI::Address address, PCI::ID id) const
  47. {
  48. if ((id.vendor_id == 0x1234 && id.device_id == 0x1111) || (id.vendor_id == 0x80ee && id.device_id == 0xbeef)) {
  49. return BochsGraphicsAdapter::initialize(address);
  50. }
  51. if (PCI::get_class(address) == 0x3 && PCI::get_subclass(address) == 0x0) {
  52. if (id.vendor_id == 0x8086) {
  53. auto adapter = IntelNativeGraphicsAdapter::initialize(address);
  54. if (!adapter.is_null())
  55. return adapter;
  56. }
  57. if (multiboot_info_ptr->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB) {
  58. dmesgln("Graphics: Using a preset resolution from the bootloader");
  59. return VGACompatibleAdapter::initialize_with_preset_resolution(address,
  60. PhysicalAddress((u32)(multiboot_info_ptr->framebuffer_addr)),
  61. multiboot_info_ptr->framebuffer_width,
  62. multiboot_info_ptr->framebuffer_height,
  63. multiboot_info_ptr->framebuffer_pitch);
  64. }
  65. return VGACompatibleAdapter::initialize(address);
  66. }
  67. return {};
  68. }
  69. UNMAP_AFTER_INIT bool GraphicsManagement::initialize()
  70. {
  71. /* Explanation on the flow when not requesting to force not creating any
  72. * framebuffer devices:
  73. * If the user wants to use a Console instead of the graphical environment,
  74. * they doesn't need to request text mode.
  75. * Graphical mode might not be accessible on bare-metal hardware because
  76. * the bootloader didn't set a framebuffer and we don't have a native driver
  77. * to set a framebuffer for it. We don't have VBE modesetting capabilities
  78. * in the kernel yet, so what will happen is one of the following situations:
  79. * 1. The bootloader didn't specify settings of a pre-set framebuffer. The
  80. * kernel has a native driver for a detected display adapter, therefore
  81. * the kernel can still set a framebuffer.
  82. * 2. The bootloader specified settings of a pre-set framebuffer, and the
  83. * kernel has a native driver for a detected display adapter, therefore
  84. * the kernel can still set a framebuffer and change the settings of it.
  85. * In that situation, the kernel will simply ignore the Multiboot pre-set
  86. * framebuffer.
  87. * 2. The bootloader specified settings of a pre-set framebuffer, and the
  88. * kernel does not have a native driver for a detected display adapter,
  89. * therefore the kernel will use the pre-set framebuffer. Modesetting is not
  90. * availabe in this situation.
  91. * 3. The bootloader didn't specify settings of a pre-set framebuffer, and
  92. * the kernel does not have a native driver for a detected display adapter,
  93. * therefore the kernel will try to initialize a VGA text mode console.
  94. * In that situation, the kernel will assume that VGA text mode was already
  95. * initialized, but will still try to modeset it. No switching to graphical
  96. * enviroment is allowed in this case.
  97. *
  98. * By default, the kernel assumes that no framebuffer was created until it
  99. * was proven that there's an existing framebuffer or we can modeset the
  100. * screen resolution to create a framebuffer.
  101. *
  102. * If the user requests to force no initialization of framebuffer devices
  103. * the same flow above will happen, except that no framebuffer device will
  104. * be created, so SystemServer will not try to initialize WindowServer.
  105. */
  106. if (kernel_command_line().is_no_framebuffer_devices_mode()) {
  107. dbgln("Forcing no initialization of framebuffer devices");
  108. }
  109. PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
  110. // Note: Each graphics controller will try to set its native screen resolution
  111. // upon creation. Later on, if we don't want to have framebuffer devices, a
  112. // framebuffer console will take the control instead.
  113. auto adapter = determine_graphics_device(address, id);
  114. if (!adapter)
  115. return;
  116. // If IO space is enabled, this VGA adapter is operating in VGA mode.
  117. if (adapter->type() == GraphicsDevice::Type::VGACompatible && PCI::is_io_space_enabled(address)) {
  118. VERIFY(m_vga_adapter.is_null());
  119. dbgln("Graphics adapter @ {} is operating in VGA mode", address);
  120. m_vga_adapter = adapter;
  121. }
  122. auto display_adapter = adapter.release_nonnull();
  123. m_graphics_devices.append(display_adapter);
  124. if (!m_framebuffer_devices_allowed) {
  125. display_adapter->enable_consoles();
  126. return;
  127. }
  128. display_adapter->initialize_framebuffer_devices();
  129. });
  130. return true;
  131. }
  132. bool GraphicsManagement::framebuffer_devices_exist() const
  133. {
  134. for (auto& graphics_device : m_graphics_devices) {
  135. if (graphics_device.framebuffer_devices_initialized())
  136. return true;
  137. }
  138. return false;
  139. }
  140. }