text: /*
   *  include/asm-s390/uaccess.h
   *
   *  S390 version
   *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
   *    Author(s): Hartmut Penner (hp@de.ibm.com),
   *               Martin Schwidefsky (schwidefsky@de.ibm.com)
   *
   *  Derived from "include/asm-i386/uaccess.h"
   */
  #ifndef __S390_UACCESS_H
  #define __S390_UACCESS_H
  
  /*
   * User space memory access functions
   */
  #include <linux/sched.h>
  #include <linux/errno.h>
  
  #define VERIFY_READ     0
  #define VERIFY_WRITE    1
  
  
  /*
   * The fs value determines whether argument validity checking should be
   * performed or not.  If get_fs() == USER_DS, checking is performed, with
   * get_fs() == KERNEL_DS, checking is bypassed.
   *
   * For historical reasons, these macros are grossly misnamed.
   */
  
  #define MAKE_MM_SEG(a)  ((mm_segment_t) { (a) })
  
  
  #define KERNEL_DS       MAKE_MM_SEG(0)
  #define USER_DS         MAKE_MM_SEG(1)
  
  #define get_ds()        (KERNEL_DS)
  #define get_fs()        ({ mm_segment_t __x; \
  			   asm volatile("ear   %0,4":"=a" (__x)); \
  			   __x;})
  #define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));})
  
  #define segment_eq(a,b) ((a).ar4 == (b).ar4)
  
  
  #define __access_ok(addr,size) (1)
  
  #define access_ok(type,addr,size) __access_ok(addr,size)
  
  extern inline int verify_area(int type, const void * addr, unsigned long size)
  {
          return access_ok(type,addr,size)?0:-EFAULT;
  }
  
  /*
   * The exception table consists of pairs of addresses: the first is the
   * address of an instruction that is allowed to fault, and the second is
   * the address at which the program should continue.  No registers are
   * modified, so it is entirely up to the continuation code to figure out
   * what to do.
   *
   * All the routines below use bits of fixup code that are out of line
   * with the main instruction path.  This means when everything is well,
   * we don't even have to jump over them.  Further, they do not intrude
   * on our cache or tlb entries.
   */
  
  struct exception_table_entry
  {
          unsigned long insn, fixup;
  };
  
  /*
   * Standard fixup section for uaccess inline functions.
   * local label 0: is the fault point
   * local label 1: is the return point
   * %0 is the error variable
   * %3 is the error value -EFAULT
   */
  #ifndef __s390x__
  #define __uaccess_fixup \
  	".section .fixup,\"ax\"\n"	\
  	"8: sacf  0\n"			\
  	"   lhi	  %0,%h3\n"		\
  	"   bras  4,9f\n"		\
  	"   .long 1b\n"			\
  	"9: l	  4,0(4)\n"		\
  	"   br	  4\n"			\
  	".previous\n"			\
  	".section __ex_table,\"a\"\n"	\
  	"   .align 4\n"			\
  	"   .long  0b,8b\n"		\
  	".previous"
  #else /* __s390x__ */
  #define __uaccess_fixup \
  	".section .fixup,\"ax\"\n"	\
  	"9: sacf  0\n"			\
  	"   lhi	  %0,%h3\n"		\
  	"   jg	  1b\n"			\
  	".previous\n"			\
  	".section __ex_table,\"a\"\n"	\
  	"   .align 8\n"			\
  	"   .quad  0b,9b\n"		\
  	".previous"
  #endif /* __s390x__ */
  
  /*
   * These are the main single-value transfer routines.  They automatically
   * use the right size if we just have the right pointer type.
   */
  #ifndef __s390x__
  
  #define __put_user_asm_8(x, ptr, err) \
  ({								\
  	register __typeof__(x) const * __from asm("2");		\
  	register __typeof__(*(ptr)) * __to asm("4");		\
  	__from = &(x);						\
  	__to = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: mvc	  0(8,%1),0(%2)\n"			\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err)					\
  		: "a" (__to),"a" (__from),"K" (-EFAULT),"0" (0)	\
  		: "cc" );					\
  })
  
  #else /* __s390x__ */
  
  #define __put_user_asm_8(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) * __ptr asm("4");		\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: stg	  %2,0(%1)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err)					\
  		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
  		: "cc" );					\
  })
  
  #endif /* __s390x__ */
  
  #define __put_user_asm_4(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) * __ptr asm("4");		\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: st	  %2,0(%1)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err)					\
  		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
  		: "cc" );					\
  })
  
  #define __put_user_asm_2(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) * __ptr asm("4");		\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: sth	  %2,0(%1)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err)					\
  		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
  		: "cc" );					\
  })
  
  #define __put_user_asm_1(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) * __ptr asm("4");		\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: stc	  %2,0(%1)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err)					\
  		: "a" (__ptr), "d" (x),	"K" (-EFAULT), "0" (0)	\
  		: "cc" );					\
  })
  
  #define __put_user(x, ptr) \
  ({								\
  	__typeof__(*(ptr)) __x = (x);				\
  	int __pu_err;						\
  	switch (sizeof (*(ptr))) {				\
  	case 1:							\
  		__put_user_asm_1(__x, ptr, __pu_err);		\
  		break;						\
  	case 2:							\
  		__put_user_asm_2(__x, ptr, __pu_err);		\
  		break;						\
  	case 4:							\
  		__put_user_asm_4(__x, ptr, __pu_err);		\
  		break;						\
  	case 8:							\
  		__put_user_asm_8(__x, ptr, __pu_err);		\
  		break;						\
  	default:						\
  		__pu_err = __put_user_bad();			\
  		break;						\
  	 }							\
  	__pu_err;						\
  })
  
  #define put_user(x, ptr)					\
  ({								\
  	might_sleep();						\
  	__put_user(x, ptr);					\
  })
  
  
  extern int __put_user_bad(void);
  
  #ifndef __s390x__
  
  #define __get_user_asm_8(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) const * __from asm("4");	\
  	register __typeof__(x) * __to asm("2");			\
  	__from = (ptr);						\
  	__to = &(x);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: mvc	  0(8,%2),0(%4)\n"			\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err), "=m" (x)				\
  		: "a" (__to),"K" (-EFAULT),"a" (__from),"0" (0)	\
  		: "cc" );					\
  })
  
  #else /* __s390x__ */
  
  #define __get_user_asm_8(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) const * __ptr asm("4");	\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: lg	  %1,0(%2)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err), "=d" (x)				\
  		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
  		: "cc" );					\
  })
  
  #endif /* __s390x__ */
  
  
  #define __get_user_asm_4(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) const * __ptr asm("4");	\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: l	  %1,0(%2)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err), "=d" (x)				\
  		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
  		: "cc" );					\
  })
  
  #define __get_user_asm_2(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) const * __ptr asm("4");	\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sacf  512\n"				\
  		"0: lh	  %1,0(%2)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err), "=d" (x)				\
  		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
  		: "cc" );					\
  })
  
  #define __get_user_asm_1(x, ptr, err) \
  ({								\
  	register __typeof__(*(ptr)) const * __ptr asm("4");	\
  	__ptr = (ptr);						\
  	__asm__ __volatile__ (					\
  		"   sr	  %1,%1\n"				\
  		"   sacf  512\n"				\
  		"0: ic	  %1,0(%2)\n"				\
  		"   sacf  0\n"					\
  		"1:\n"						\
  		__uaccess_fixup					\
  		: "=&d" (err), "=&d" (x)			\
  		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
  		: "cc" );					\
  })
  
  #define __get_user(x, ptr)					\
  ({								\
  	__typeof__(*(ptr)) __x;					\
  	int __gu_err;						\
  	switch (sizeof(*(ptr))) {				\
  	case 1:							\
  		__get_user_asm_1(__x, ptr, __gu_err);		\
  		break;						\
  	case 2:							\
  		__get_user_asm_2(__x, ptr, __gu_err);		\
  		break;						\
  	case 4:							\
  		__get_user_asm_4(__x, ptr, __gu_err);		\
  		break;						\
  	case 8:							\
  		__get_user_asm_8(__x, ptr, __gu_err);		\
  		break;						\
  	default:						\
  		__x = 0;					\
  		__gu_err = __get_user_bad();			\
  		break;						\
  	}							\
  	(x) = __x;						\
  	__gu_err;						\
  })
  
  #define get_user(x, ptr)					\
  ({								\
  	might_sleep();						\
  	__get_user(x, ptr);					\
  })
  
  extern int __get_user_bad(void);
  
  /*
   * access register are set up, that 4 points to secondary (user),
   * 2 to primary (kernel)
   */
  
  extern long __copy_to_user_asm(const void *from, long n, const void *to);
  
  #define __copy_to_user(to, from, n)                             \
  ({                                                              \
          __copy_to_user_asm(from, n, to);                        \
  })
  
  #define copy_to_user(to, from, n)                               \
  ({                                                              \
          long err = 0;                                           \
          __typeof__(n) __n = (n);                                \
          might_sleep();						\
          if (__access_ok(to,__n)) {                              \
                  err = __copy_to_user_asm(from, __n, to);        \
          }                                                       \
          else                                                    \
                  err = __n;                                      \
          err;                                                    \
  })
  
  extern long __copy_from_user_asm(void *to, long n, const void *from);
  
  #define __copy_from_user(to, from, n)                           \
  ({                                                              \
          __copy_from_user_asm(to, n, from);                      \
  })
  
  #define copy_from_user(to, from, n)                             \
  ({                                                              \
          long err = 0;                                           \
          __typeof__(n) __n = (n);                                \
          might_sleep();						\
          if (__access_ok(from,__n)) {                            \
                  err = __copy_from_user_asm(to, __n, from);      \
          }                                                       \
          else                                                    \
                  err = __n;                                      \
          err;                                                    \
  })
  
  /*
   * Copy a null terminated string from userspace.
   */
  
  #ifndef __s390x__
  
  static inline long
  __strncpy_from_user(char *dst, const char *src, long count)
  {
          int len;
          __asm__ __volatile__ (
  		"   slr   %0,%0\n"
  		"   lr    2,%1\n"
                  "   lr    4,%2\n"
                  "   slr   3,3\n"
                  "   sacf  512\n"
  		"0: ic	  3,0(%0,4)\n"
  		"1: stc	  3,0(%0,2)\n"
  		"   ltr	  3,3\n"
  		"   jz	  2f\n"
  		"   ahi	  %0,1\n"
  		"   clr	  %0,%3\n"
  		"   jl	  0b\n"
  		"2: sacf  0\n"
  		".section .fixup,\"ax\"\n"
  		"3: lhi	  %0,%h4\n"
  		"   basr  3,0\n"
  		"   l	  3,4f-.(3)\n"
  		"   br	  3\n"
  		"4: .long 2b\n"
  		".previous\n"
  		".section __ex_table,\"a\"\n"
  		"   .align 4\n"
  		"   .long  0b,3b\n"
  		"   .long  1b,3b\n"
  		".previous"
  		: "=&a" (len)
  		: "a" (dst), "d" (src), "d" (count), "K" (-EFAULT)
  		: "2", "3", "4", "memory", "cc" );
  	return len;
  }
  
  #else /* __s390x__ */
  
  static inline long
  __strncpy_from_user(char *dst, const char *src, long count)
  {
  	long len;
  	__asm__ __volatile__ (
  		"   slgr  %0,%0\n"
  		"   lgr	  2,%1\n"
  		"   lgr	  4,%2\n"
  		"   slr	  3,3\n"
  		"   sacf  512\n"
  		"0: ic	  3,0(%0,4)\n"
  		"1: stc	  3,0(%0,2)\n"
  		"   ltr	  3,3\n"
  		"   jz	  2f\n"
  		"   aghi  %0,1\n"
  		"   cgr	  %0,%3\n"
  		"   jl	  0b\n"
  		"2: sacf  0\n"
  		".section .fixup,\"ax\"\n"
  		"3: lghi  %0,%h4\n"
  		"   jg	  2b\n"	 
  		".previous\n"
  		".section __ex_table,\"a\"\n"
  		"   .align 8\n"
  		"   .quad  0b,3b\n"
  		"   .quad  1b,3b\n"
  		".previous"
  		: "=&a" (len)
  		: "a"  (dst), "d" (src), "d" (count), "K" (-EFAULT)
  		: "cc", "2" ,"3", "4" );
  	return len;
  }
  
  #endif /* __s390x__ */
  
  static inline long
  strncpy_from_user(char *dst, const char *src, long count)
  {
          long res = -EFAULT;
          might_sleep();
          if (access_ok(VERIFY_READ, src, 1))
                  res = __strncpy_from_user(dst, src, count);
          return res;
  }
  
  
  /*
   * Return the size of a string (including the ending 0)
   *
   * Return 0 for error
   */
  #ifndef __s390x__
  
  static inline unsigned long
  strnlen_user(const char * src, unsigned long n)
  {
  	might_sleep();
  	__asm__ __volatile__ (
  		"   alr   %0,%1\n"
  		"   slr   0,0\n"
  		"   lr    4,%1\n"
  		"   sacf  512\n"
  		"0: srst  %0,4\n"
  		"   jo    0b\n"
  		"   slr   %0,%1\n"
  		"   ahi   %0,1\n"
  		"   sacf  0\n"
  		"1:\n"
  		".section .fixup,\"ax\"\n"
  		"2: sacf  0\n"
  		"   slr   %0,%0\n"
  		"   bras  4,3f\n"
  		"   .long 1b\n"
  		"3: l     4,0(4)\n"
  		"   br    4\n"
  		".previous\n"
  		".section __ex_table,\"a\"\n"
  		"  .align 4\n"
  		"  .long  0b,2b\n"
  		".previous"
  		: "+&a" (n) : "d" (src)
  		: "cc", "0", "4" );
  	return n;
  }
  
  #else /* __s390x__ */
  
  static inline unsigned long
  strnlen_user(const char * src, unsigned long n)
  {
  	might_sleep();
  #if 0
  	__asm__ __volatile__ (
  		"   algr  %0,%1\n"
  		"   slgr  0,0\n"
  		"   lgr	  4,%1\n"
  		"   sacf  512\n"
  		"0: srst  %0,4\n"
  		"   jo	0b\n"
  		"   slgr  %0,%1\n"
  		"   aghi  %0,1\n"
  		"1: sacf  0\n"
  		".section .fixup,\"ax\"\n"
  		"2: slgr  %0,%0\n"
  		"   jg	  1b\n"
  		".previous\n"
  		".section __ex_table,\"a\"\n"
  		"  .align 8\n"
  		"  .quad  0b,2b\n"
  		".previous"
  		: "+&a" (n) : "d" (src)
  		: "cc", "0", "4" );
  #else
  	__asm__ __volatile__ (
  		"   lgr	  4,%1\n"
  		"   sacf  512\n"
  		"0: cli   0(4),0x00\n"
  		"   la    4,1(4)\n"
  		"   je    1f\n"
  		"   brctg %0,0b\n"
  		"1: lgr	  %0,4\n"
  		"   slgr  %0,%1\n"
  		"2: sacf  0\n"
  		".section .fixup,\"ax\"\n"
  		"3: slgr  %0,%0\n"
  		"   jg    2b\n"  
  		".previous\n"
  		".section __ex_table,\"a\"\n"
  		"  .align 8\n"
  		"  .quad  0b,3b\n"
  		".previous"
  		: "+&a" (n) : "d" (src)
  		: "cc", "4" );
  #endif
  	return n;
  }
  
  #endif /* __s390x__ */
  
  #define strlen_user(str) strnlen_user(str, ~0UL)
  
  /*
   * Zero Userspace
   */
  
  extern long __clear_user_asm(void *to, long n);
  
  #define __clear_user(to, n)					\
  ({								\
  	__clear_user_asm(to, n);				\
  })
  
  static inline unsigned long
  clear_user(void *to, unsigned long n)
  {
  	might_sleep();
  	if (access_ok(VERIFY_WRITE, to, n))
  		n = __clear_user(to, n);
  	return n;
  }
  
  
  #endif				       /* _S390_UACCESS_H		   */
  