From 1e70a3a46c064c4dd93c9c56763e32ebf9eb24bf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 18 Mar 2013 15:13:16 +0000 Subject: [PATCH] vesa: Prevent loading if we conflict with a previously loaded driver vesa is presumed to be the generic hardware agnostic fallback framebuffer driver for standard VGA that conflicts with the real drivers. Those drivers already check and remove vesafb if it is previously loaded, but in the reverse case where vesafb is loaded afterwards, the VESA driver will proceed to clobber hardware state and corrupt the displays. References: https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1156077 Signed-off-by: Chris Wilson --- drivers/video/fbmem.c | 31 +++++++++++++++++++++++++++++++ drivers/video/vesafb.c | 22 ++++++++++++++++++++++ include/linux/fb.h | 2 ++ 3 files changed, 55 insertions(+) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 7c25408..786cec8 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1722,6 +1722,37 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, } EXPORT_SYMBOL(remove_conflicting_framebuffers); +bool has_conflicting_framebuffer(struct apertures_struct *a, bool primary) +{ + bool ret = false; + int i; + + mutex_lock(®istration_lock); + + for (i = 0 ; i < FB_MAX; i++) { + struct apertures_struct *gen_aper; + + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + gen_aper = registered_fb[i]->apertures; + if (fb_do_apertures_overlap(gen_aper, a) || + (primary && gen_aper && gen_aper->count && + gen_aper->ranges[0].base == VGA_FB_PHYS)) { + ret = true; + break; + } + } + + mutex_unlock(®istration_lock); + + return ret; +} +EXPORT_SYMBOL(has_conflicting_framebuffer); + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 501b340..58dc3d7 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -226,6 +226,25 @@ static int __init vesafb_setup(char *options) return 0; } +static bool aperture_already_claimed(unsigned long base, unsigned long size) +{ + struct apertures_struct *ap; + bool ret; + + ap = alloc_apertures(1); + if (!ap) + return true; + + ap->ranges[0].base = base; + ap->ranges[0].size = size; + + ret = has_conflicting_framebuffer(ap, true); + + kfree(ap); + + return ret; +} + static int __init vesafb_probe(struct platform_device *dev) { struct fb_info *info; @@ -279,6 +298,9 @@ static int __init vesafb_probe(struct platform_device *dev) screen_info.vesapm_seg = 0; #endif + if (aperture_already_claimed(vesafb_fix.smem_start, size_total)) + return -ENODEV; + if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { printk(KERN_WARNING "vesafb: cannot reserve video memory at 0x%lx\n", diff --git a/include/linux/fb.h b/include/linux/fb.h index 58b9860..7dfd964 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -611,6 +611,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info); extern int unlink_framebuffer(struct fb_info *fb_info); +extern bool has_conflicting_framebuffer(struct apertures_struct *a, + bool primary); extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); -- 1.7.10.4