/* 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;
}
return -EINVAL;
}
+ if ((len >> PAGE_SHIFT) > num_physpages) {
+ printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
+ return -EINVAL;
+ }
+
down(µcode_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;