|
@@ -11,6 +11,7 @@
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/types.h>
|
|
|
#include <linux/errno.h>
|
|
|
+#include <linux/gfp.h>
|
|
|
#include <asm/system.h>
|
|
|
|
|
|
/*
|
|
@@ -60,6 +61,9 @@ long probe_kernel_write(void *dst, const void *src, size_t size)
|
|
|
return copied < 0 ? -EFAULT : 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Copy memory in real mode (kernel to kernel)
|
|
|
+ */
|
|
|
int memcpy_real(void *dest, void *src, size_t count)
|
|
|
{
|
|
|
register unsigned long _dest asm("2") = (unsigned long) dest;
|
|
@@ -101,3 +105,55 @@ void copy_to_absolute_zero(void *dest, void *src, size_t count)
|
|
|
__ctl_load(cr0, 0, 0);
|
|
|
preempt_enable();
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Copy memory from kernel (real) to user (virtual)
|
|
|
+ */
|
|
|
+int copy_to_user_real(void __user *dest, void *src, size_t count)
|
|
|
+{
|
|
|
+ int offs = 0, size, rc;
|
|
|
+ char *buf;
|
|
|
+
|
|
|
+ buf = (char *) __get_free_page(GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+ rc = -EFAULT;
|
|
|
+ while (offs < count) {
|
|
|
+ size = min(PAGE_SIZE, count - offs);
|
|
|
+ if (memcpy_real(buf, src + offs, size))
|
|
|
+ goto out;
|
|
|
+ if (copy_to_user(dest + offs, buf, size))
|
|
|
+ goto out;
|
|
|
+ offs += size;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+out:
|
|
|
+ free_page((unsigned long) buf);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Copy memory from user (virtual) to kernel (real)
|
|
|
+ */
|
|
|
+int copy_from_user_real(void *dest, void __user *src, size_t count)
|
|
|
+{
|
|
|
+ int offs = 0, size, rc;
|
|
|
+ char *buf;
|
|
|
+
|
|
|
+ buf = (char *) __get_free_page(GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+ rc = -EFAULT;
|
|
|
+ while (offs < count) {
|
|
|
+ size = min(PAGE_SIZE, count - offs);
|
|
|
+ if (copy_from_user(buf, src + offs, size))
|
|
|
+ goto out;
|
|
|
+ if (memcpy_real(dest + offs, buf, size))
|
|
|
+ goto out;
|
|
|
+ offs += size;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+out:
|
|
|
+ free_page((unsigned long) buf);
|
|
|
+ return rc;
|
|
|
+}
|