linux/arch/s390/lib/uaccess_mvcos.c
<<
>>
Prefs
   1/*
   2 *  Optimized user space space access functions based on mvcos.
   3 *
   4 *    Copyright IBM Corp. 2006
   5 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
   6 *               Gerald Schaefer (gerald.schaefer@de.ibm.com)
   7 */
   8
   9#include <linux/errno.h>
  10#include <linux/mm.h>
  11#include <asm/uaccess.h>
  12#include <asm/futex.h>
  13#include "uaccess.h"
  14
  15#ifndef CONFIG_64BIT
  16#define AHI     "ahi"
  17#define ALR     "alr"
  18#define CLR     "clr"
  19#define LHI     "lhi"
  20#define SLR     "slr"
  21#else
  22#define AHI     "aghi"
  23#define ALR     "algr"
  24#define CLR     "clgr"
  25#define LHI     "lghi"
  26#define SLR     "slgr"
  27#endif
  28
  29static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
  30{
  31        register unsigned long reg0 asm("0") = 0x81UL;
  32        unsigned long tmp1, tmp2;
  33
  34        tmp1 = -4096UL;
  35        asm volatile(
  36                "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
  37                "9: jz    7f\n"
  38                "1:"ALR"  %0,%3\n"
  39                "  "SLR"  %1,%3\n"
  40                "  "SLR"  %2,%3\n"
  41                "   j     0b\n"
  42                "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
  43                "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
  44                "  "SLR"  %4,%1\n"
  45                "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
  46                "   jnh   4f\n"
  47                "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
  48                "10:"SLR"  %0,%4\n"
  49                "  "ALR"  %2,%4\n"
  50                "4:"LHI"  %4,-1\n"
  51                "  "ALR"  %4,%0\n"      /* copy remaining size, subtract 1 */
  52                "   bras  %3,6f\n"      /* memset loop */
  53                "   xc    0(1,%2),0(%2)\n"
  54                "5: xc    0(256,%2),0(%2)\n"
  55                "   la    %2,256(%2)\n"
  56                "6:"AHI"  %4,-256\n"
  57                "   jnm   5b\n"
  58                "   ex    %4,0(%3)\n"
  59                "   j     8f\n"
  60                "7:"SLR"  %0,%0\n"
  61                "8: \n"
  62                EX_TABLE(0b,2b) EX_TABLE(3b,4b) EX_TABLE(9b,2b) EX_TABLE(10b,4b)
  63                : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
  64                : "d" (reg0) : "cc", "memory");
  65        return size;
  66}
  67
  68static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
  69{
  70        if (size <= 256)
  71                return copy_from_user_std(size, ptr, x);
  72        return copy_from_user_mvcos(size, ptr, x);
  73}
  74
  75static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
  76{
  77        register unsigned long reg0 asm("0") = 0x810000UL;
  78        unsigned long tmp1, tmp2;
  79
  80        tmp1 = -4096UL;
  81        asm volatile(
  82                "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
  83                "6: jz    4f\n"
  84                "1:"ALR"  %0,%3\n"
  85                "  "SLR"  %1,%3\n"
  86                "  "SLR"  %2,%3\n"
  87                "   j     0b\n"
  88                "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
  89                "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
  90                "  "SLR"  %4,%1\n"
  91                "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
  92                "   jnh   5f\n"
  93                "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
  94                "7:"SLR"  %0,%4\n"
  95                "   j     5f\n"
  96                "4:"SLR"  %0,%0\n"
  97                "5: \n"
  98                EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
  99                : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
 100                : "d" (reg0) : "cc", "memory");
 101        return size;
 102}
 103
 104static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
 105                                       const void *x)
 106{
 107        if (size <= 256)
 108                return copy_to_user_std(size, ptr, x);
 109        return copy_to_user_mvcos(size, ptr, x);
 110}
 111
 112static size_t copy_in_user_mvcos(size_t size, void __user *to,
 113                                 const void __user *from)
 114{
 115        register unsigned long reg0 asm("0") = 0x810081UL;
 116        unsigned long tmp1, tmp2;
 117
 118        tmp1 = -4096UL;
 119        /* FIXME: copy with reduced length. */
 120        asm volatile(
 121                "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
 122                "   jz    2f\n"
 123                "1:"ALR"  %0,%3\n"
 124                "  "SLR"  %1,%3\n"
 125                "  "SLR"  %2,%3\n"
 126                "   j     0b\n"
 127                "2:"SLR"  %0,%0\n"
 128                "3: \n"
 129                EX_TABLE(0b,3b)
 130                : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
 131                : "d" (reg0) : "cc", "memory");
 132        return size;
 133}
 134
 135static size_t clear_user_mvcos(size_t size, void __user *to)
 136{
 137        register unsigned long reg0 asm("0") = 0x810000UL;
 138        unsigned long tmp1, tmp2;
 139
 140        tmp1 = -4096UL;
 141        asm volatile(
 142                "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
 143                "   jz    4f\n"
 144                "1:"ALR"  %0,%2\n"
 145                "  "SLR"  %1,%2\n"
 146                "   j     0b\n"
 147                "2: la    %3,4095(%1)\n"/* %4 = to + 4095 */
 148                "   nr    %3,%2\n"      /* %4 = (to + 4095) & -4096 */
 149                "  "SLR"  %3,%1\n"
 150                "  "CLR"  %0,%3\n"      /* copy crosses next page boundary? */
 151                "   jnh   5f\n"
 152                "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
 153                "  "SLR"  %0,%3\n"
 154                "   j     5f\n"
 155                "4:"SLR"  %0,%0\n"
 156                "5: \n"
 157                EX_TABLE(0b,2b) EX_TABLE(3b,5b)
 158                : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
 159                : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
 160        return size;
 161}
 162
 163static size_t strnlen_user_mvcos(size_t count, const char __user *src)
 164{
 165        size_t done, len, offset, len_str;
 166        char buf[256];
 167
 168        done = 0;
 169        do {
 170                offset = (size_t)src & ~PAGE_MASK;
 171                len = min(256UL, PAGE_SIZE - offset);
 172                len = min(count - done, len);
 173                if (copy_from_user_mvcos(len, src, buf))
 174                        return 0;
 175                len_str = strnlen(buf, len);
 176                done += len_str;
 177                src += len_str;
 178        } while ((len_str == len) && (done < count));
 179        return done + 1;
 180}
 181
 182static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
 183                                      char *dst)
 184{
 185        size_t done, len, offset, len_str;
 186
 187        if (unlikely(!count))
 188                return 0;
 189        done = 0;
 190        do {
 191                offset = (size_t)src & ~PAGE_MASK;
 192                len = min(count - done, PAGE_SIZE - offset);
 193                if (copy_from_user_mvcos(len, src, dst))
 194                        return -EFAULT;
 195                len_str = strnlen(dst, len);
 196                done += len_str;
 197                src += len_str;
 198                dst += len_str;
 199        } while ((len_str == len) && (done < count));
 200        return done;
 201}
 202
 203struct uaccess_ops uaccess_mvcos = {
 204        .copy_from_user = copy_from_user_mvcos_check,
 205        .copy_from_user_small = copy_from_user_std,
 206        .copy_to_user = copy_to_user_mvcos_check,
 207        .copy_to_user_small = copy_to_user_std,
 208        .copy_in_user = copy_in_user_mvcos,
 209        .clear_user = clear_user_mvcos,
 210        .strnlen_user = strnlen_user_std,
 211        .strncpy_from_user = strncpy_from_user_std,
 212        .futex_atomic_op = futex_atomic_op_std,
 213        .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 214};
 215
 216struct uaccess_ops uaccess_mvcos_switch = {
 217        .copy_from_user = copy_from_user_mvcos,
 218        .copy_from_user_small = copy_from_user_mvcos,
 219        .copy_to_user = copy_to_user_mvcos,
 220        .copy_to_user_small = copy_to_user_mvcos,
 221        .copy_in_user = copy_in_user_mvcos,
 222        .clear_user = clear_user_mvcos,
 223        .strnlen_user = strnlen_user_mvcos,
 224        .strncpy_from_user = strncpy_from_user_mvcos,
 225        .futex_atomic_op = futex_atomic_op_pt,
 226        .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
 227};
 228