|
@@ -45,3 +45,94 @@
|
|
|
/*
|
|
|
* For historical reasons, the following macros are grossly misnamed:
|
|
|
*/
|
|
|
+#define KERNEL_DS ((mm_segment_t) { ~0UL }) /* cf. access_ok() */
|
|
|
+#define USER_DS ((mm_segment_t) { TASK_SIZE-1 }) /* cf. access_ok() */
|
|
|
+
|
|
|
+#define VERIFY_READ 0
|
|
|
+#define VERIFY_WRITE 1
|
|
|
+
|
|
|
+#define get_ds() (KERNEL_DS)
|
|
|
+#define get_fs() (current_thread_info()->addr_limit)
|
|
|
+#define set_fs(x) (current_thread_info()->addr_limit = (x))
|
|
|
+
|
|
|
+#define segment_eq(a, b) ((a).seg == (b).seg)
|
|
|
+
|
|
|
+/*
|
|
|
+ * When accessing user memory, we need to make sure the entire area really is in
|
|
|
+ * user-level space. In order to do this efficiently, we make sure that the page at
|
|
|
+ * address TASK_SIZE is never valid. We also need to make sure that the address doesn't
|
|
|
+ * point inside the virtually mapped linear page table.
|
|
|
+ */
|
|
|
+#define __access_ok(addr, size, segment) \
|
|
|
+({ \
|
|
|
+ __chk_user_ptr(addr); \
|
|
|
+ (likely((unsigned long) (addr) <= (segment).seg) \
|
|
|
+ && ((segment).seg == KERNEL_DS.seg \
|
|
|
+ || likely(REGION_OFFSET((unsigned long) (addr)) < RGN_MAP_LIMIT))); \
|
|
|
+})
|
|
|
+#define access_ok(type, addr, size) __access_ok((addr), (size), get_fs())
|
|
|
+
|
|
|
+/*
|
|
|
+ * These are the main single-value transfer routines. They automatically
|
|
|
+ * use the right size if we just have the right pointer type.
|
|
|
+ *
|
|
|
+ * Careful to not
|
|
|
+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
|
|
|
+ * (b) require any knowledge of processes at this stage
|
|
|
+ */
|
|
|
+#define put_user(x, ptr) __put_user_check((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr)), get_fs())
|
|
|
+#define get_user(x, ptr) __get_user_check((x), (ptr), sizeof(*(ptr)), get_fs())
|
|
|
+
|
|
|
+/*
|
|
|
+ * The "__xxx" versions do not do address space checking, useful when
|
|
|
+ * doing multiple accesses to the same area (the programmer has to do the
|
|
|
+ * checks by hand with "access_ok()")
|
|
|
+ */
|
|
|
+#define __put_user(x, ptr) __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr)))
|
|
|
+#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
|
|
|
+
|
|
|
+extern long __put_user_unaligned_unknown (void);
|
|
|
+
|
|
|
+#define __put_user_unaligned(x, ptr) \
|
|
|
+({ \
|
|
|
+ long __ret; \
|
|
|
+ switch (sizeof(*(ptr))) { \
|
|
|
+ case 1: __ret = __put_user((x), (ptr)); break; \
|
|
|
+ case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \
|
|
|
+ | (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \
|
|
|
+ case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \
|
|
|
+ | (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \
|
|
|
+ case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \
|
|
|
+ | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \
|
|
|
+ default: __ret = __put_user_unaligned_unknown(); \
|
|
|
+ } \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+extern long __get_user_unaligned_unknown (void);
|
|
|
+
|
|
|
+#define __get_user_unaligned(x, ptr) \
|
|
|
+({ \
|
|
|
+ long __ret; \
|
|
|
+ switch (sizeof(*(ptr))) { \
|
|
|
+ case 1: __ret = __get_user((x), (ptr)); break; \
|
|
|
+ case 2: __ret = (__get_user((x), (u8 __user *)(ptr))) \
|
|
|
+ | (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \
|
|
|
+ case 4: __ret = (__get_user((x), (u16 __user *)(ptr))) \
|
|
|
+ | (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \
|
|
|
+ case 8: __ret = (__get_user((x), (u32 __user *)(ptr))) \
|
|
|
+ | (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \
|
|
|
+ default: __ret = __get_user_unaligned_unknown(); \
|
|
|
+ } \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+#ifdef ASM_SUPPORTED
|
|
|
+ struct __large_struct { unsigned long buf[100]; };
|
|
|
+# define __m(x) (*(struct __large_struct __user *)(x))
|
|
|
+
|
|
|
+/* We need to declare the __ex_table section before we can use it in .xdata. */
|
|
|
+asm (".section \"__ex_table\", \"a\"\n\t.previous");
|
|
|
+
|
|
|
+# define __get_user_size(val, addr, n, err) \
|
|
|
+do { \
|