@@ -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
@@ -226,6 +226,25 @@ static int __init vesafb_setup(char *options)
return 0;
}
+static bool aperture_already_claimed(void)
+{
+ struct apertures_struct *ap;
+ bool ret;
+
+ ap = alloc_apertures(1);
+ if (!ap)
+ return true;
+
+ ap->ranges[0].base = screen_info.lfb_base;
+ ap->ranges[0].size = size_total;
+
+ ret = has_conflicting_framebuffer(ap, true);
+
+ kfree(ap);
+
+ return ret;
+}
+
static int __init vesafb_probe(struct platform_device *dev)
{
struct fb_info *info;
@@ -237,6 +256,9 @@ static int __init vesafb_probe(struct platform_device *dev)
if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
return -ENODEV;
+ if (aperture_already_claimed())
+ return -ENODEV;
+
vga_compat = (screen_info.capabilities & 2) ? 0 : 1;
vesafb_fix.smem_start = screen_info.lfb_base;
vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
@@ -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);
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 <chris@chris-wilson.co.uk> --- drivers/video/fbmem.c | 31 +++++++++++++++++++++++++++++++ drivers/video/vesafb.c | 22 ++++++++++++++++++++++ include/linux/fb.h | 2 ++ 3 files changed, 55 insertions(+)