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 5b80bf3..a271f57 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 ba9f58b..cbaa4c9 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 9ebda4e..7d1d2f1 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 60805e4..3408ff1 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 0cb0989..a9aa651 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 7b8bd3a..75e7001 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 bcdcaea..e49221a 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 665ef7a..6949bbd 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 a36d05b..24f0ec3 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 */