Commit 85a00d9b authored by Peter Jones's avatar Peter Jones Committed by Linus Torvalds

efifb: check that the base address is plausible on pci systems

Some Apple machines have identical DMI data but different memory
configurations for the video.  Given that, check that the address in our
table is actually within the range of a PCI BAR on a VGA device in the
machine.

This also fixes up the return value from set_system(), which has always
been wrong, but never resulted in bad behavior since there's only ever
been one matching entry in the dmi table.

The patch

1) stops people's machines from crashing when we get their display wrong,
   which seems to be unfortunately inevitable,

2) allows us to support identical dmi data with differing video memory
   configurations

This also adds me as the efifb maintainer, since I've effectively been
acting as such for quite some time.
Signed-off-by: default avatarPeter Jones <pjones@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a0c42bac
...@@ -2199,6 +2199,12 @@ W: http://acpi4asus.sf.net ...@@ -2199,6 +2199,12 @@ W: http://acpi4asus.sf.net
S: Maintained S: Maintained
F: drivers/platform/x86/eeepc-laptop.c F: drivers/platform/x86/eeepc-laptop.c
EFIFB FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
M: Peter Jones <pjones@redhat.com>
S: Maintained
F: drivers/video/efifb.c
EFS FILESYSTEM EFS FILESYSTEM
W: http://aeschi.ch.eu.org/efs/ W: http://aeschi.ch.eu.org/efs/
S: Orphan S: Orphan
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/pci.h>
#include <video/vga.h> #include <video/vga.h>
static struct fb_var_screeninfo efifb_defined __devinitdata = { static struct fb_var_screeninfo efifb_defined __devinitdata = {
...@@ -116,7 +116,7 @@ static int set_system(const struct dmi_system_id *id) ...@@ -116,7 +116,7 @@ static int set_system(const struct dmi_system_id *id)
{ {
struct efifb_dmi_info *info = id->driver_data; struct efifb_dmi_info *info = id->driver_data;
if (info->base == 0) if (info->base == 0)
return -ENODEV; return 0;
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
"(%dx%d, stride %d)\n", id->ident, "(%dx%d, stride %d)\n", id->ident,
...@@ -124,8 +124,39 @@ static int set_system(const struct dmi_system_id *id) ...@@ -124,8 +124,39 @@ static int set_system(const struct dmi_system_id *id)
info->stride); info->stride);
/* Trust the bootloader over the DMI tables */ /* Trust the bootloader over the DMI tables */
if (screen_info.lfb_base == 0) if (screen_info.lfb_base == 0) {
#if defined(CONFIG_PCI)
struct pci_dev *dev = NULL;
int found_bar = 0;
#endif
screen_info.lfb_base = info->base; screen_info.lfb_base = info->base;
#if defined(CONFIG_PCI)
/* make sure that the address in the table is actually on a
* VGA device's PCI BAR */
for_each_pci_dev(dev) {
int i;
if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
continue;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
resource_size_t start, end;
start = pci_resource_start(dev, i);
if (start == 0)
break;
end = pci_resource_end(dev, i);
if (screen_info.lfb_base >= start &&
screen_info.lfb_base < end) {
found_bar = 1;
}
}
}
if (!found_bar)
screen_info.lfb_base = 0;
#endif
}
if (screen_info.lfb_base) {
if (screen_info.lfb_linelength == 0) if (screen_info.lfb_linelength == 0)
screen_info.lfb_linelength = info->stride; screen_info.lfb_linelength = info->stride;
if (screen_info.lfb_width == 0) if (screen_info.lfb_width == 0)
...@@ -134,8 +165,14 @@ static int set_system(const struct dmi_system_id *id) ...@@ -134,8 +165,14 @@ static int set_system(const struct dmi_system_id *id)
screen_info.lfb_height = info->height; screen_info.lfb_height = info->height;
if (screen_info.orig_video_isVGA == 0) if (screen_info.orig_video_isVGA == 0)
screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
} else {
screen_info.lfb_linelength = 0;
screen_info.lfb_width = 0;
screen_info.lfb_height = 0;
screen_info.orig_video_isVGA = 0;
return 0; return 0;
}
return 1;
} }
static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment