diff --git a/Userland/Services/WindowServer/HardwareScreenBackend.cpp b/Userland/Services/WindowServer/HardwareScreenBackend.cpp index dffbc0b7c2..a3d72f4ae0 100644 --- a/Userland/Services/WindowServer/HardwareScreenBackend.cpp +++ b/Userland/Services/WindowServer/HardwareScreenBackend.cpp @@ -51,8 +51,27 @@ HardwareScreenBackend::~HardwareScreenBackend() } } +ErrorOr 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 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 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) { diff --git a/Userland/Services/WindowServer/HardwareScreenBackend.h b/Userland/Services/WindowServer/HardwareScreenBackend.h index 35b2786d17..b58b72e3cc 100644 --- a/Userland/Services/WindowServer/HardwareScreenBackend.h +++ b/Userland/Services/WindowServer/HardwareScreenBackend.h @@ -31,6 +31,8 @@ public: virtual ErrorOr unmap_framebuffer() override; virtual ErrorOr map_framebuffer() override; + virtual ErrorOr set_safe_head_mode_setting() override; + virtual ErrorOr set_head_mode_setting(GraphicsHeadModeSetting) override; virtual ErrorOr get_head_mode_setting() override; diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index abf32be4a0..378811c8db 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/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) diff --git a/Userland/Services/WindowServer/ScreenBackend.h b/Userland/Services/WindowServer/ScreenBackend.h index 14870c1aa3..1523566cc7 100644 --- a/Userland/Services/WindowServer/ScreenBackend.h +++ b/Userland/Services/WindowServer/ScreenBackend.h @@ -35,6 +35,7 @@ public: virtual ErrorOr flush_framebuffer() = 0; virtual ErrorOr set_head_mode_setting(GraphicsHeadModeSetting) = 0; + virtual ErrorOr set_safe_head_mode_setting() = 0; virtual ErrorOr get_head_mode_setting() = 0; bool m_can_device_flush_buffers { true }; diff --git a/Userland/Services/WindowServer/VirtualScreenBackend.cpp b/Userland/Services/WindowServer/VirtualScreenBackend.cpp index 30e644a46e..05769481a7 100644 --- a/Userland/Services/WindowServer/VirtualScreenBackend.cpp +++ b/Userland/Services/WindowServer/VirtualScreenBackend.cpp @@ -31,6 +31,11 @@ void VirtualScreenBackend::set_head_buffer(int index) m_first_buffer_active = index == 0; } +ErrorOr VirtualScreenBackend::set_safe_head_mode_setting() +{ + return {}; +} + ErrorOr VirtualScreenBackend::set_head_mode_setting(GraphicsHeadModeSetting mode_setting) { m_height = mode_setting.vertical_active; diff --git a/Userland/Services/WindowServer/VirtualScreenBackend.h b/Userland/Services/WindowServer/VirtualScreenBackend.h index 808d43259f..a48cec7b8f 100644 --- a/Userland/Services/WindowServer/VirtualScreenBackend.h +++ b/Userland/Services/WindowServer/VirtualScreenBackend.h @@ -35,6 +35,8 @@ private: virtual ErrorOr unmap_framebuffer() override; virtual ErrorOr map_framebuffer() override; + virtual ErrorOr set_safe_head_mode_setting() override; + virtual ErrorOr set_head_mode_setting(GraphicsHeadModeSetting) override; virtual ErrorOr get_head_mode_setting() override;