video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
[linux-flexiantxendom0.git] / drivers / video / uvesafb.c
index 54fbb29..bbfa6c9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 #include <video/edid.h>
 #include <video/uvesafb.h>
 #ifdef CONFIG_X86
@@ -72,7 +73,7 @@ static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *ns
        struct uvesafb_task *utask;
        struct uvesafb_ktask *task;
 
-       if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN))
+       if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
                return;
 
        if (msg->seq >= UVESAFB_TASKS_MAX)
@@ -120,7 +121,7 @@ static int uvesafb_helper_start(void)
                NULL,
        };
 
-       return call_usermodehelper(v86d_path, argv, envp, 1);
+       return call_usermodehelper(v86d_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /*
@@ -814,8 +815,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
        par->pmi_setpal = pmi_setpal;
        par->ypan = ypan;
 
-       if (par->pmi_setpal || par->ypan)
-               uvesafb_vbe_getpmi(task, par);
+       if (par->pmi_setpal || par->ypan) {
+               if (__supported_pte_mask & _PAGE_NX) {
+                       par->pmi_setpal = par->ypan = 0;
+                       printk(KERN_WARNING "uvesafb: NX protection is actively."
+                               "We have better not to use the PMI.\n");
+               } else {
+                       uvesafb_vbe_getpmi(task, par);
+               }
+       }
 #else
        /* The protected mode interface is not available on non-x86. */
        par->pmi_setpal = par->ypan = 0;
@@ -1551,8 +1559,7 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
                        int rc;
 
                        /* Find the largest power-of-two */
-                       while (temp_size & (temp_size - 1))
-                               temp_size &= (temp_size - 1);
+                       temp_size = roundup_pow_of_two(temp_size);
 
                        /* Try and find a power of two to add */
                        do {
@@ -1565,6 +1572,28 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
 #endif /* CONFIG_MTRR */
 }
 
+static void __devinit uvesafb_ioremap(struct fb_info *info)
+{
+#ifdef CONFIG_X86
+       switch (mtrr) {
+       case 1: /* uncachable */
+               info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 2: /* write-back */
+               info->screen_base = ioremap_cache(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 3: /* write-combining */
+               info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 4: /* write-through */
+       default:
+               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+               break;
+       }
+#else
+       info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+#endif /* CONFIG_X86 */
+}
 
 static ssize_t uvesafb_show_vbe_ver(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -1735,15 +1764,22 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
 
        uvesafb_init_info(info, mode);
 
+       if (!request_region(0x3c0, 32, "uvesafb")) {
+               printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
+               err = -EIO;
+               goto out_mode;
+       }
+
        if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
                                "uvesafb")) {
                printk(KERN_ERR "uvesafb: cannot reserve video memory at "
                                "0x%lx\n", info->fix.smem_start);
                err = -EIO;
-               goto out_mode;
+               goto out_reg;
        }
 
-       info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+       uvesafb_init_mtrr(info);
+       uvesafb_ioremap(info);
 
        if (!info->screen_base) {
                printk(KERN_ERR
@@ -1754,20 +1790,13 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
                goto out_mem;
        }
 
-       if (!request_region(0x3c0, 32, "uvesafb")) {
-               printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
-               err = -EIO;
-               goto out_unmap;
-       }
-
-       uvesafb_init_mtrr(info);
        platform_set_drvdata(dev, info);
 
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR
                        "uvesafb: failed to register framebuffer device\n");
                err = -EINVAL;
-               goto out_reg;
+               goto out_unmap;
        }
 
        printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
@@ -1784,12 +1813,12 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
 
        return 0;
 
-out_reg:
-       release_region(0x3c0, 32);
 out_unmap:
        iounmap(info->screen_base);
 out_mem:
        release_mem_region(info->fix.smem_start, info->fix.smem_len);
+out_reg:
+       release_region(0x3c0, 32);
 out_mode:
        if (!list_empty(&info->modelist))
                fb_destroy_modelist(&info->modelist);
@@ -1976,8 +2005,7 @@ static void __devexit uvesafb_exit(void)
 
 module_exit(uvesafb_exit);
 
-#define param_get_scroll NULL
-static int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, const struct kernel_param *kp)
 {
        ypan = 0;
 
@@ -1992,7 +2020,9 @@ static int param_set_scroll(const char *val, struct kernel_param *kp)
 
        return 0;
 }
-
+static struct kernel_param_ops param_ops_scroll = {
+       .set = param_set_scroll,
+};
 #define param_check_scroll(name, p) __param_check(name, p, void)
 
 module_param_named(scroll, ypan, scroll, 0);