]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/panic: Fix 24bit pixel crossing page boundaries
authorJocelyn Falempe <jfalempe@redhat.com>
Thu, 9 Oct 2025 12:24:53 +0000 (14:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Oct 2025 13:10:28 +0000 (14:10 +0100)
[ Upstream commit 23437509a69476d4f896891032d62ac868731668 ]

When using page list framebuffer, and using RGB888 format, some
pixels can cross the page boundaries, and this case was not handled,
leading to writing 1 or 2 bytes on the next virtual address.

Add a check and a specific function to handle this case.

Fixes: c9ff2808790f0 ("drm/panic: Add support to scanout buffer as array of pages")
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://lore.kernel.org/r/20251009122955.562888-7-jfalempe@redhat.com
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/drm_panic.c

index 1bc15c44207b4a5eda2650ddb03910f3e9f9f671..f52752880e1c9bd673d745c06bc74ed2e3f0abd6 100644 (file)
@@ -174,6 +174,33 @@ static void drm_panic_write_pixel24(void *vaddr, unsigned int offset, u32 color)
        *p = color & 0xff;
 }
 
+/*
+ * Special case if the pixel crosses page boundaries
+ */
+static void drm_panic_write_pixel24_xpage(void *vaddr, struct page *next_page,
+                                         unsigned int offset, u32 color)
+{
+       u8 *vaddr2;
+       u8 *p = vaddr + offset;
+
+       vaddr2 = kmap_local_page_try_from_panic(next_page);
+
+       *p++ = color & 0xff;
+       color >>= 8;
+
+       if (offset == PAGE_SIZE - 1)
+               p = vaddr2;
+
+       *p++ = color & 0xff;
+       color >>= 8;
+
+       if (offset == PAGE_SIZE - 2)
+               p = vaddr2;
+
+       *p = color & 0xff;
+       kunmap_local(vaddr2);
+}
+
 static void drm_panic_write_pixel32(void *vaddr, unsigned int offset, u32 color)
 {
        u32 *p = vaddr + offset;
@@ -231,7 +258,14 @@ static void drm_panic_blit_page(struct page **pages, unsigned int dpitch,
                                        page = new_page;
                                        vaddr = kmap_local_page_try_from_panic(pages[page]);
                                }
-                               if (vaddr)
+                               if (!vaddr)
+                                       continue;
+
+                               // Special case for 24bit, as a pixel might cross page boundaries
+                               if (cpp == 3 && offset + 3 > PAGE_SIZE)
+                                       drm_panic_write_pixel24_xpage(vaddr, pages[page + 1],
+                                                                     offset, fg32);
+                               else
                                        drm_panic_write_pixel(vaddr, offset, fg32, cpp);
                        }
                }
@@ -321,7 +355,15 @@ static void drm_panic_fill_page(struct page **pages, unsigned int dpitch,
                                page = new_page;
                                vaddr = kmap_local_page_try_from_panic(pages[page]);
                        }
-                       drm_panic_write_pixel(vaddr, offset, color, cpp);
+                       if (!vaddr)
+                               continue;
+
+                       // Special case for 24bit, as a pixel might cross page boundaries
+                       if (cpp == 3 && offset + 3 > PAGE_SIZE)
+                               drm_panic_write_pixel24_xpage(vaddr, pages[page + 1],
+                                                             offset, color);
+                       else
+                               drm_panic_write_pixel(vaddr, offset, color, cpp);
                }
        }
        if (vaddr)