Pārlūkot izejas kodu

WindowServer: Fallback to safe mode-setting in case of mapping overflow

In case of possible framebuffer mapping overflow, just fallback to the
safe mode-setting of the DisplayConnector, because in that state we know
for sure that we can map a usable framebuffer (otherwise it is a bug in
the Kernel, and not WindowServer).
Liav A 2 gadi atpakaļ
vecāks
revīzija
13e9947b4b

+ 22 - 0
Userland/Services/WindowServer/HardwareScreenBackend.cpp

@@ -51,8 +51,27 @@ HardwareScreenBackend::~HardwareScreenBackend()
     }
 }
 
+ErrorOr<void> HardwareScreenBackend::set_safe_head_mode_setting()
+{
+    auto rc = graphics_connector_set_safe_head_mode_setting(m_display_connector_fd);
+    if (rc != 0) {
+        dbgln("Failed to set backend safe mode setting: aborting");
+        return Error::from_syscall("graphics_connector_set_safe_head_mode_setting"sv, rc);
+    }
+    return {};
+}
+
 ErrorOr<void> HardwareScreenBackend::set_head_mode_setting(GraphicsHeadModeSetting mode_setting)
 {
+    size_t size_in_bytes = 0;
+    if (m_can_set_head_buffer) {
+        size_in_bytes = mode_setting.horizontal_stride * mode_setting.vertical_active * 2;
+    } else {
+        size_in_bytes = mode_setting.horizontal_stride * mode_setting.vertical_active;
+    }
+    VERIFY(size_in_bytes != 0);
+    if (m_max_size_in_bytes < size_in_bytes)
+        return Error::from_errno(EOVERFLOW);
 
     GraphicsHeadModeSetting requested_mode_setting = mode_setting;
     auto rc = graphics_connector_set_head_mode_setting(m_display_connector_fd, &requested_mode_setting);
@@ -91,6 +110,9 @@ ErrorOr<void> HardwareScreenBackend::map_framebuffer()
     } else {
         m_size_in_bytes = mode_setting.horizontal_stride * mode_setting.vertical_active;
     }
+
+    if (m_max_size_in_bytes < m_size_in_bytes)
+        return Error::from_errno(EOVERFLOW);
     m_framebuffer = (Gfx::ARGB32*)TRY(Core::System::mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_display_connector_fd, 0));
 
     if (m_can_set_head_buffer) {

+ 2 - 0
Userland/Services/WindowServer/HardwareScreenBackend.h

@@ -31,6 +31,8 @@ public:
     virtual ErrorOr<void> unmap_framebuffer() override;
     virtual ErrorOr<void> map_framebuffer() override;
 
+    virtual ErrorOr<void> set_safe_head_mode_setting() override;
+
     virtual ErrorOr<void> set_head_mode_setting(GraphicsHeadModeSetting) override;
     virtual ErrorOr<GraphicsHeadModeSetting> get_head_mode_setting() override;
 

+ 5 - 2
Userland/Services/WindowServer/Screen.cpp

@@ -370,12 +370,15 @@ bool Screen::set_resolution(bool initial)
         if (!return_value.is_error())
             return true;
     }
-    if (return_value.is_error()) {
+    if (return_value.is_error() && return_value.error() != Error::from_errno(EOVERFLOW)) {
         dbgln("Screen #{}: Failed to set resolution {}: {}", index(), info.resolution, return_value.error());
         MUST(on_change_resolution());
         return false;
     }
-    VERIFY_NOT_REACHED();
+    dbgln("Screen #{}: Failed to set resolution {}: {}, falling back to safe resolution", index(), info.resolution, return_value.error());
+    MUST(m_backend->set_safe_head_mode_setting());
+    MUST(on_change_resolution());
+    return false;
 }
 
 void Screen::set_buffer(int index)

+ 1 - 0
Userland/Services/WindowServer/ScreenBackend.h

@@ -35,6 +35,7 @@ public:
     virtual ErrorOr<void> flush_framebuffer() = 0;
 
     virtual ErrorOr<void> set_head_mode_setting(GraphicsHeadModeSetting) = 0;
+    virtual ErrorOr<void> set_safe_head_mode_setting() = 0;
     virtual ErrorOr<GraphicsHeadModeSetting> get_head_mode_setting() = 0;
 
     bool m_can_device_flush_buffers { true };

+ 5 - 0
Userland/Services/WindowServer/VirtualScreenBackend.cpp

@@ -31,6 +31,11 @@ void VirtualScreenBackend::set_head_buffer(int index)
     m_first_buffer_active = index == 0;
 }
 
+ErrorOr<void> VirtualScreenBackend::set_safe_head_mode_setting()
+{
+    return {};
+}
+
 ErrorOr<void> VirtualScreenBackend::set_head_mode_setting(GraphicsHeadModeSetting mode_setting)
 {
     m_height = mode_setting.vertical_active;

+ 2 - 0
Userland/Services/WindowServer/VirtualScreenBackend.h

@@ -35,6 +35,8 @@ private:
     virtual ErrorOr<void> unmap_framebuffer() override;
     virtual ErrorOr<void> map_framebuffer() override;
 
+    virtual ErrorOr<void> set_safe_head_mode_setting() override;
+
     virtual ErrorOr<void> set_head_mode_setting(GraphicsHeadModeSetting) override;
     virtual ErrorOr<GraphicsHeadModeSetting> get_head_mode_setting() override;