fbdev: Warn on incorrect framebuffer access
authorThomas Zimmermann <tzimmermann@suse.de>
Mon, 27 Nov 2023 13:16:00 +0000 (14:16 +0100)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 29 Nov 2023 11:20:50 +0000 (12:20 +0100)
Test in framebuffer read, write and drawing helpers if FBINFO_VIRTFB
has been set correctly. Framebuffers in I/O memory should only be
accessed with the architecture's respective helpers. Framebuffers
in system memory should be accessed with the regular load and
store operations. Presumably not all drivers get this right, so we
now warn about it.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231127131655.4020-32-tzimmermann@suse.de
drivers/video/fbdev/core/cfbcopyarea.c
drivers/video/fbdev/core/cfbfillrect.c
drivers/video/fbdev/core/cfbimgblt.c
drivers/video/fbdev/core/fb_io_fops.c
drivers/video/fbdev/core/fb_sys_fops.c
drivers/video/fbdev/core/syscopyarea.c
drivers/video/fbdev/core/sysfillrect.c
drivers/video/fbdev/core/sysimgblt.c
include/linux/fb.h

index 5b80bf3dae504850d9ebc12de3ac1df32341ccee..a271f57d9c6c12ba5ac9a4df0290a158f8e6254f 100644 (file)
@@ -391,6 +391,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (p->flags & FBINFO_VIRTFB)
+               fb_warn_once(p, "Framebuffer is not in I/O address space.");
+
        /* if the beginning of the target area might overlap with the end of
        the source area, be have to copy the area reverse. */
        if ((dy == sy && dx > sx) || (dy > sy)) {
index ba9f58b2a5e86e65a29aa3cabc67d45087b933b9..cbaa4c9e2355a9c3a65d289c2c0a821a30bc0a11 100644 (file)
@@ -287,6 +287,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (p->flags & FBINFO_VIRTFB)
+               fb_warn_once(p, "Framebuffer is not in I/O address space.");
+
        if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
            p->fix.visual == FB_VISUAL_DIRECTCOLOR )
                fg = ((u32 *) (p->pseudo_palette))[rect->color];
index 9ebda4e0dc7abc13187e01c99230f0ee9fe78777..7d1d2f1a627dcb36178973f697ef2b09ed4e6617 100644 (file)
@@ -326,6 +326,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (p->flags & FBINFO_VIRTFB)
+               fb_warn_once(p, "Framebuffer is not in I/O address space.");
+
        bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
        start_index = bitstart & (32 - 1);
        pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
index 60805e43914e52ecc3590870be2875e9f1f8e593..3408ff1b2b7a0a69757ec11111e74ceeac84be50 100644 (file)
@@ -12,6 +12,9 @@ ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t
        int c, cnt = 0, err = 0;
        unsigned long total_size, trailing;
 
+       if (info->flags & FBINFO_VIRTFB)
+               fb_warn_once(info, "Framebuffer is not in I/O address space.");
+
        if (!info->screen_base)
                return -ENODEV;
 
@@ -73,6 +76,9 @@ ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count,
        int c, cnt = 0, err = 0;
        unsigned long total_size, trailing;
 
+       if (info->flags & FBINFO_VIRTFB)
+               fb_warn_once(info, "Framebuffer is not in I/O address space.");
+
        if (!info->screen_base)
                return -ENODEV;
 
@@ -138,6 +144,9 @@ int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
        u32 len = info->fix.smem_len;
        unsigned long mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
 
+       if (info->flags & FBINFO_VIRTFB)
+               fb_warn_once(info, "Framebuffer is not in I/O address space.");
+
        /*
         * This can be either the framebuffer mapping, or if pgoff points
         * past it, the mmio mapping.
index 0cb0989abda61c5f4e3d0cb32b105bf6848a419c..a9aa6519a5b30be5e5d07de5ad6f96dad95b94cf 100644 (file)
@@ -22,6 +22,9 @@ ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
        unsigned long total_size, c;
        ssize_t ret;
 
+       if (!(info->flags & FBINFO_VIRTFB))
+               fb_warn_once(info, "Framebuffer is not in virtual address space.");
+
        if (!info->screen_buffer)
                return -ENODEV;
 
@@ -64,6 +67,9 @@ ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
        unsigned long total_size, c;
        size_t ret;
 
+       if (!(info->flags & FBINFO_VIRTFB))
+               fb_warn_once(info, "Framebuffer is not in virtual address space.");
+
        if (!info->screen_buffer)
                return -ENODEV;
 
index 7b8bd3a2bedc50c5ca23cb180f52dd99229d9cfc..75e7001e8450faa306ff55388174373daf223d88 100644 (file)
@@ -324,6 +324,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (!(p->flags & FBINFO_VIRTFB))
+               fb_warn_once(p, "Framebuffer is not in virtual address space.");
+
        /* if the beginning of the target area might overlap with the end of
        the source area, be have to copy the area reverse. */
        if ((dy == sy && dx > sx) || (dy > sy)) {
index bcdcaeae6538c328cc2de4b2c48bbb6b5307959b..e49221a88ccc727fa1b2fbe3684ba0bb2e0b73ad 100644 (file)
@@ -242,6 +242,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (!(p->flags & FBINFO_VIRTFB))
+               fb_warn_once(p, "Framebuffer is not in virtual address space.");
+
        if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
            p->fix.visual == FB_VISUAL_DIRECTCOLOR )
                fg = ((u32 *) (p->pseudo_palette))[rect->color];
index 665ef7a0a2495bde34d6306d268cdb41353f9061..6949bbd51d9209b7ced72903438361300870606b 100644 (file)
@@ -296,6 +296,9 @@ void sys_imageblit(struct fb_info *p, const struct fb_image *image)
        if (p->state != FBINFO_STATE_RUNNING)
                return;
 
+       if (!(p->flags & FBINFO_VIRTFB))
+               fb_warn_once(p, "Framebuffer is not in virtual address space.");
+
        bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
        start_index = bitstart & (32 - 1);
        pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
index a36d05b576b0ccd7a97051ff3ed8bea8a644b99a..24f0ec36623528fc16d4af1eee325b22600ae87b 100644 (file)
@@ -849,7 +849,10 @@ static inline bool fb_modesetting_disabled(const char *drvname)
 }
 #endif
 
-/* Convenience logging macros */
+/*
+ * Convenience logging macros
+ */
+
 #define fb_err(fb_info, fmt, ...)                                      \
        pr_err("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__)
 #define fb_notice(info, fmt, ...)                                      \
@@ -861,4 +864,7 @@ static inline bool fb_modesetting_disabled(const char *drvname)
 #define fb_dbg(fb_info, fmt, ...)                                      \
        pr_debug("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__)
 
+#define fb_warn_once(fb_info, fmt, ...)                                        \
+       pr_warn_once("fb%d: " fmt, (fb_info)->node, ##__VA_ARGS__)
+
 #endif /* _LINUX_FB_H */