- 2.6.17 port work build breaks, but the patch set is relativly stable
[linux-flexiantxendom0-3.2.10.git] / arch / i386 / kernel / microcode-xen.c
index 89c6a8c..07db5cc 100644 (file)
@@ -51,32 +51,30 @@ MODULE_LICENSE("GPL");
 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
 static DECLARE_MUTEX(microcode_sem);
 
+static void __user *user_buffer;       /* user area microcode data buffer */
+static unsigned int user_buffer_size;  /* it's size */
+                               
 static int microcode_open (struct inode *unused1, struct file *unused2)
 {
        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
 
-static int do_microcode_update (const void __user *ubuf, size_t len)
+static int do_microcode_update (void)
 {
        int err;
-       void *kbuf;
+       dom0_op_t op;
 
-       kbuf = vmalloc(len);
-       if (!kbuf)
-               return -ENOMEM;
+       err = sys_mlock((unsigned long)user_buffer, user_buffer_size);
+       if (err != 0)
+               return err;
 
-       if (copy_from_user(kbuf, ubuf, len) == 0) {
-               dom0_op_t op;
+       op.cmd = DOM0_MICROCODE;
+       op.u.microcode.data = user_buffer;
+       op.u.microcode.length = user_buffer_size;
+       err = HYPERVISOR_dom0_op(&op);
 
-               op.cmd = DOM0_MICROCODE;
-               op.u.microcode.data = kbuf;
-               op.u.microcode.length = len;
-               err = HYPERVISOR_dom0_op(&op);
-       } else
-               err = -EFAULT;
-
-       vfree(kbuf);
+       (void)sys_munlock((unsigned long)user_buffer, user_buffer_size);
 
        return err;
 }
@@ -90,9 +88,17 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
                return -EINVAL;
        }
 
+       if ((len >> PAGE_SHIFT) > num_physpages) {
+               printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
+               return -EINVAL;
+       }
+
        down(&microcode_sem);
 
-       ret = do_microcode_update(buf, len);
+       user_buffer = (void __user *) buf;
+       user_buffer_size = (int) len;
+
+       ret = do_microcode_update();
        if (!ret)
                ret = (ssize_t)len;