Commit f94c128e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'metag-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag

Pull metag updates from James Hogan:
 "These patches primarily make some usercopy improvements (following on
  from the recent usercopy fixes):

   - reformat and simplify rapf copy loops

   - add 64-bit get_user support

  And fix a couple more uaccess issues, partily pointed out by Al:

   - fix access_ok() serious shortcomings

   - fix strncpy_from_user() address validation

  Also included is a trivial removal of a redundant increment"

* tag 'metag-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag:
  metag/mm: Drop pointless increment
  metag/uaccess: Check access_ok in strncpy_from_user
  metag/uaccess: Fix access_ok()
  metag/usercopy: Add 64-bit get_user support
  metag/usercopy: Simplify rapf loop fixup corner case
  metag/usercopy: Reformat rapf loop inline asm
parents c44b5943 e3cd7f01
...@@ -24,24 +24,32 @@ ...@@ -24,24 +24,32 @@
#define segment_eq(a, b) ((a).seg == (b).seg) #define segment_eq(a, b) ((a).seg == (b).seg)
#define __kernel_ok (uaccess_kernel())
/*
* Explicitly allow NULL pointers here. Parts of the kernel such
* as readv/writev use access_ok to validate pointers, but want
* to allow NULL pointers for various reasons. NULL pointers are
* safe to allow through because the first page is not mappable on
* Meta.
*
* We also wish to avoid letting user code access the system area
* and the kernel half of the address space.
*/
#define __user_bad(addr, size) (((addr) > 0 && (addr) < META_MEMORY_BASE) || \
((addr) > PAGE_OFFSET && \
(addr) < LINCORE_BASE))
static inline int __access_ok(unsigned long addr, unsigned long size) static inline int __access_ok(unsigned long addr, unsigned long size)
{ {
return __kernel_ok || !__user_bad(addr, size); /*
* Allow access to the user mapped memory area, but not the system area
* before it. The check extends to the top of the address space when
* kernel access is allowed (there's no real reason to user copy to the
* system area in any case).
*/
if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg &&
size <= get_fs().seg - addr))
return true;
/*
* Explicitly allow NULL pointers here. Parts of the kernel such
* as readv/writev use access_ok to validate pointers, but want
* to allow NULL pointers for various reasons. NULL pointers are
* safe to allow through because the first page is not mappable on
* Meta.
*/
if (!addr)
return true;
/* Allow access to core code memory area... */
if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT &&
size <= LINCORE_CODE_LIMIT + 1 - addr)
return true;
/* ... but no other areas. */
return false;
} }
#define access_ok(type, addr, size) __access_ok((unsigned long)(addr), \ #define access_ok(type, addr, size) __access_ok((unsigned long)(addr), \
...@@ -113,7 +121,8 @@ extern long __get_user_bad(void); ...@@ -113,7 +121,8 @@ extern long __get_user_bad(void);
#define __get_user_nocheck(x, ptr, size) \ #define __get_user_nocheck(x, ptr, size) \
({ \ ({ \
long __gu_err, __gu_val; \ long __gu_err; \
long long __gu_val; \
__get_user_size(__gu_val, (ptr), (size), __gu_err); \ __get_user_size(__gu_val, (ptr), (size), __gu_err); \
(x) = (__force __typeof__(*(ptr)))__gu_val; \ (x) = (__force __typeof__(*(ptr)))__gu_val; \
__gu_err; \ __gu_err; \
...@@ -121,7 +130,8 @@ extern long __get_user_bad(void); ...@@ -121,7 +130,8 @@ extern long __get_user_bad(void);
#define __get_user_check(x, ptr, size) \ #define __get_user_check(x, ptr, size) \
({ \ ({ \
long __gu_err = -EFAULT, __gu_val = 0; \ long __gu_err = -EFAULT; \
long long __gu_val = 0; \
const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
if (access_ok(VERIFY_READ, __gu_addr, size)) \ if (access_ok(VERIFY_READ, __gu_addr, size)) \
__get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
...@@ -132,6 +142,7 @@ extern long __get_user_bad(void); ...@@ -132,6 +142,7 @@ extern long __get_user_bad(void);
extern unsigned char __get_user_asm_b(const void __user *addr, long *err); extern unsigned char __get_user_asm_b(const void __user *addr, long *err);
extern unsigned short __get_user_asm_w(const void __user *addr, long *err); extern unsigned short __get_user_asm_w(const void __user *addr, long *err);
extern unsigned int __get_user_asm_d(const void __user *addr, long *err); extern unsigned int __get_user_asm_d(const void __user *addr, long *err);
extern unsigned long long __get_user_asm_l(const void __user *addr, long *err);
#define __get_user_size(x, ptr, size, retval) \ #define __get_user_size(x, ptr, size, retval) \
do { \ do { \
...@@ -143,6 +154,8 @@ do { \ ...@@ -143,6 +154,8 @@ do { \
x = __get_user_asm_w(ptr, &retval); break; \ x = __get_user_asm_w(ptr, &retval); break; \
case 4: \ case 4: \
x = __get_user_asm_d(ptr, &retval); break; \ x = __get_user_asm_d(ptr, &retval); break; \
case 8: \
x = __get_user_asm_l(ptr, &retval); break; \
default: \ default: \
(x) = __get_user_bad(); \ (x) = __get_user_bad(); \
} \ } \
...@@ -161,8 +174,13 @@ do { \ ...@@ -161,8 +174,13 @@ do { \
extern long __must_check __strncpy_from_user(char *dst, const char __user *src, extern long __must_check __strncpy_from_user(char *dst, const char __user *src,
long count); long count);
#define strncpy_from_user(dst, src, count) __strncpy_from_user(dst, src, count) static inline long
strncpy_from_user(char *dst, const char __user *src, long count)
{
if (!access_ok(VERIFY_READ, src, 1))
return -EFAULT;
return __strncpy_from_user(dst, src, count);
}
/* /*
* Return the size of a string (including the ending 0) * Return the size of a string (including the ending 0)
* *
......
...@@ -246,65 +246,47 @@ ...@@ -246,65 +246,47 @@
#define __asm_copy_user_64bit_rapf_loop( \ #define __asm_copy_user_64bit_rapf_loop( \
to, from, ret, n, id, FIXUP) \ to, from, ret, n, id, FIXUP) \
asm volatile ( \ asm volatile ( \
".balign 8\n" \ ".balign 8\n" \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"MSETL [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n" \ " MSETL [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n" \
"MOV D0Ar6, #0\n" \ " MOV D0Ar6, #0\n" \
"LSR D1Ar5, %3, #6\n" \ " LSR D1Ar5, %3, #6\n" \
"SUB TXRPT, D1Ar5, #2\n" \ " SUB TXRPT, D1Ar5, #2\n" \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"$Lloop"id":\n" \ "$Lloop"id":\n" \
"ADD RAPF, %1, #64\n" \ " ADD RAPF, %1, #64\n" \
"21:\n" \ "21: MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "22: MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"22:\n" \ "23: SUB %3, %3, #32\n" \
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "24: MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"23:\n" \ "25: MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #32\n" \ "26: SUB %3, %3, #32\n" \
"24:\n" \ " DCACHE [%1+#-64], D0Ar6\n" \
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ " BR $Lloop"id"\n" \
"25:\n" \
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"26:\n" \
"SUB %3, %3, #32\n" \
"DCACHE [%1+#-64], D0Ar6\n" \
"BR $Lloop"id"\n" \
\ \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"27:\n" \ "27: MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "28: MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"28:\n" \ "29: SUB %3, %3, #32\n" \
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "30: MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"29:\n" \ "31: MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #32\n" \ "32: SETL [%0+#-8], D0.7, D1.7\n" \
"30:\n" \ " SUB %3, %3, #32\n" \
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "1: DCACHE [%1+#-64], D0Ar6\n" \
"31:\n" \ " GETL D0Ar6, D1Ar5, [A0StP+#-40]\n" \
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ " GETL D0FrT, D1RtP, [A0StP+#-32]\n" \
"32:\n" \ " GETL D0.5, D1.5, [A0StP+#-24]\n" \
"SUB %0, %0, #8\n" \ " GETL D0.6, D1.6, [A0StP+#-16]\n" \
"33:\n" \ " GETL D0.7, D1.7, [A0StP+#-8]\n" \
"SETL [%0++], D0.7, D1.7\n" \ " SUB A0StP, A0StP, #40\n" \
"SUB %3, %3, #32\n" \
"1:" \
"DCACHE [%1+#-64], D0Ar6\n" \
"GETL D0Ar6, D1Ar5, [A0StP+#-40]\n" \
"GETL D0FrT, D1RtP, [A0StP+#-32]\n" \
"GETL D0.5, D1.5, [A0StP+#-24]\n" \
"GETL D0.6, D1.6, [A0StP+#-16]\n" \
"GETL D0.7, D1.7, [A0StP+#-8]\n" \
"SUB A0StP, A0StP, #40\n" \
" .section .fixup,\"ax\"\n" \ " .section .fixup,\"ax\"\n" \
"4:\n" \ "3: MOV D0Ar2, TXSTATUS\n" \
" ADD %0, %0, #8\n" \
"3:\n" \
" MOV D0Ar2, TXSTATUS\n" \
" MOV D1Ar1, TXSTATUS\n" \ " MOV D1Ar1, TXSTATUS\n" \
" AND D1Ar1, D1Ar1, #0xFFFFF8FF\n" \ " AND D1Ar1, D1Ar1, #0xFFFFF8FF\n" \
" MOV TXSTATUS, D1Ar1\n" \ " MOV TXSTATUS, D1Ar1\n" \
FIXUP \ FIXUP \
" MOVT D0Ar2,#HI(1b)\n" \ " MOVT D0Ar2, #HI(1b)\n" \
" JUMP D0Ar2,#LO(1b)\n" \ " JUMP D0Ar2, #LO(1b)\n" \
" .previous\n" \ " .previous\n" \
" .section __ex_table,\"a\"\n" \ " .section __ex_table,\"a\"\n" \
" .long 21b,3b\n" \ " .long 21b,3b\n" \
...@@ -319,7 +301,6 @@ ...@@ -319,7 +301,6 @@
" .long 30b,3b\n" \ " .long 30b,3b\n" \
" .long 31b,3b\n" \ " .long 31b,3b\n" \
" .long 32b,3b\n" \ " .long 32b,3b\n" \
" .long 33b,4b\n" \
" .previous\n" \ " .previous\n" \
: "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \ : "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \
: "0" (to), "1" (from), "2" (ret), "3" (n) \ : "0" (to), "1" (from), "2" (ret), "3" (n) \
...@@ -397,89 +378,59 @@ ...@@ -397,89 +378,59 @@
#define __asm_copy_user_32bit_rapf_loop( \ #define __asm_copy_user_32bit_rapf_loop( \
to, from, ret, n, id, FIXUP) \ to, from, ret, n, id, FIXUP) \
asm volatile ( \ asm volatile ( \
".balign 8\n" \ ".balign 8\n" \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"MSETL [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n" \ " MSETL [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n" \
"MOV D0Ar6, #0\n" \ " MOV D0Ar6, #0\n" \
"LSR D1Ar5, %3, #6\n" \ " LSR D1Ar5, %3, #6\n" \
"SUB TXRPT, D1Ar5, #2\n" \ " SUB TXRPT, D1Ar5, #2\n" \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"$Lloop"id":\n" \ "$Lloop"id":\n" \
"ADD RAPF, %1, #64\n" \ " ADD RAPF, %1, #64\n" \
"21:\n" \ "21: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "22: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"22:\n" \ "23: SUB %3, %3, #16\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "24: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"23:\n" \ "25: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #16\n" \ "26: SUB %3, %3, #16\n" \
"24:\n" \ "27: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "28: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"25:\n" \ "29: SUB %3, %3, #16\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "30: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"26:\n" \ "31: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #16\n" \ "32: SUB %3, %3, #16\n" \
"27:\n" \ " DCACHE [%1+#-64], D0Ar6\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ " BR $Lloop"id"\n" \
"28:\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"29:\n" \
"SUB %3, %3, #16\n" \
"30:\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"31:\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"32:\n" \
"SUB %3, %3, #16\n" \
"DCACHE [%1+#-64], D0Ar6\n" \
"BR $Lloop"id"\n" \
\ \
"MOV RAPF, %1\n" \ " MOV RAPF, %1\n" \
"33:\n" \ "33: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "34: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"34:\n" \ "35: SUB %3, %3, #16\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "36: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"35:\n" \ "37: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #16\n" \ "38: SUB %3, %3, #16\n" \
"36:\n" \ "39: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "40: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"37:\n" \ "41: SUB %3, %3, #16\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ "42: MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
"38:\n" \ "43: MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"SUB %3, %3, #16\n" \ "44: SETD [%0+#-4], D0.7\n" \
"39:\n" \ " SUB %3, %3, #16\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ "1: DCACHE [%1+#-64], D0Ar6\n" \
"40:\n" \ " GETL D0Ar6, D1Ar5, [A0StP+#-40]\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \ " GETL D0FrT, D1RtP, [A0StP+#-32]\n" \
"41:\n" \ " GETL D0.5, D1.5, [A0StP+#-24]\n" \
"SUB %3, %3, #16\n" \ " GETL D0.6, D1.6, [A0StP+#-16]\n" \
"42:\n" \ " GETL D0.7, D1.7, [A0StP+#-8]\n" \
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \ " SUB A0StP, A0StP, #40\n" \
"43:\n" \
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
"44:\n" \
"SUB %0, %0, #4\n" \
"45:\n" \
"SETD [%0++], D0.7\n" \
"SUB %3, %3, #16\n" \
"1:" \
"DCACHE [%1+#-64], D0Ar6\n" \
"GETL D0Ar6, D1Ar5, [A0StP+#-40]\n" \
"GETL D0FrT, D1RtP, [A0StP+#-32]\n" \
"GETL D0.5, D1.5, [A0StP+#-24]\n" \
"GETL D0.6, D1.6, [A0StP+#-16]\n" \
"GETL D0.7, D1.7, [A0StP+#-8]\n" \
"SUB A0StP, A0StP, #40\n" \
" .section .fixup,\"ax\"\n" \ " .section .fixup,\"ax\"\n" \
"4:\n" \ "3: MOV D0Ar2, TXSTATUS\n" \
" ADD %0, %0, #4\n" \
"3:\n" \
" MOV D0Ar2, TXSTATUS\n" \
" MOV D1Ar1, TXSTATUS\n" \ " MOV D1Ar1, TXSTATUS\n" \
" AND D1Ar1, D1Ar1, #0xFFFFF8FF\n" \ " AND D1Ar1, D1Ar1, #0xFFFFF8FF\n" \
" MOV TXSTATUS, D1Ar1\n" \ " MOV TXSTATUS, D1Ar1\n" \
FIXUP \ FIXUP \
" MOVT D0Ar2,#HI(1b)\n" \ " MOVT D0Ar2, #HI(1b)\n" \
" JUMP D0Ar2,#LO(1b)\n" \ " JUMP D0Ar2, #LO(1b)\n" \
" .previous\n" \ " .previous\n" \
" .section __ex_table,\"a\"\n" \ " .section __ex_table,\"a\"\n" \
" .long 21b,3b\n" \ " .long 21b,3b\n" \
...@@ -506,7 +457,6 @@ ...@@ -506,7 +457,6 @@
" .long 42b,3b\n" \ " .long 42b,3b\n" \
" .long 43b,3b\n" \ " .long 43b,3b\n" \
" .long 44b,3b\n" \ " .long 44b,3b\n" \
" .long 45b,4b\n" \
" .previous\n" \ " .previous\n" \
: "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \ : "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \
: "0" (to), "1" (from), "2" (ret), "3" (n) \ : "0" (to), "1" (from), "2" (ret), "3" (n) \
...@@ -1094,6 +1044,30 @@ unsigned int __get_user_asm_d(const void __user *addr, long *err) ...@@ -1094,6 +1044,30 @@ unsigned int __get_user_asm_d(const void __user *addr, long *err)
} }
EXPORT_SYMBOL(__get_user_asm_d); EXPORT_SYMBOL(__get_user_asm_d);
unsigned long long __get_user_asm_l(const void __user *addr, long *err)
{
register unsigned long long x asm ("D0Re0") = 0;
asm volatile (
" GETL %0,%t0,[%2]\n"
"1:\n"
" GETL %0,%t0,[%2]\n"
"2:\n"
" .section .fixup,\"ax\"\n"
"3: MOV D0FrT,%3\n"
" SETD [%1],D0FrT\n"
" MOVT D0FrT,#HI(2b)\n"
" JUMP D0FrT,#LO(2b)\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .long 1b,3b\n"
" .previous\n"
: "=r" (x)
: "r" (err), "r" (addr), "P" (-EFAULT)
: "D0FrT");
return x;
}
EXPORT_SYMBOL(__get_user_asm_l);
long __put_user_asm_b(unsigned int x, void __user *addr) long __put_user_asm_b(unsigned int x, void __user *addr)
{ {
register unsigned int err asm ("D0Re0") = 0; register unsigned int err asm ("D0Re0") = 0;
......
...@@ -152,6 +152,5 @@ void __init mmu_init(unsigned long mem_end) ...@@ -152,6 +152,5 @@ void __init mmu_init(unsigned long mem_end)
p_swapper_pg_dir++; p_swapper_pg_dir++;
addr += PGDIR_SIZE; addr += PGDIR_SIZE;
entry++;
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment