Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Standard user space access functions based on mvcp/mvcs and doing
0004  *  interesting things in the secondary space mode.
0005  *
0006  *    Copyright IBM Corp. 2006,2014
0007  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
0008  *       Gerald Schaefer (gerald.schaefer@de.ibm.com)
0009  */
0010 
0011 #include <linux/uaccess.h>
0012 #include <linux/export.h>
0013 #include <linux/mm.h>
0014 #include <asm/asm-extable.h>
0015 
0016 #ifdef CONFIG_DEBUG_ENTRY
0017 void debug_user_asce(int exit)
0018 {
0019     unsigned long cr1, cr7;
0020 
0021     __ctl_store(cr1, 1, 1);
0022     __ctl_store(cr7, 7, 7);
0023     if (cr1 == S390_lowcore.kernel_asce && cr7 == S390_lowcore.user_asce)
0024         return;
0025     panic("incorrect ASCE on kernel %s\n"
0026           "cr1:    %016lx cr7:  %016lx\n"
0027           "kernel: %016llx user: %016llx\n",
0028           exit ? "exit" : "entry", cr1, cr7,
0029           S390_lowcore.kernel_asce, S390_lowcore.user_asce);
0030 
0031 }
0032 #endif /*CONFIG_DEBUG_ENTRY */
0033 
0034 static unsigned long raw_copy_from_user_key(void *to, const void __user *from,
0035                         unsigned long size, unsigned long key)
0036 {
0037     unsigned long tmp1, tmp2;
0038     union oac spec = {
0039         .oac2.key = key,
0040         .oac2.as = PSW_BITS_AS_SECONDARY,
0041         .oac2.k = 1,
0042         .oac2.a = 1,
0043     };
0044 
0045     tmp1 = -4096UL;
0046     asm volatile(
0047         "   lr    0,%[spec]\n"
0048         "0: mvcos 0(%2),0(%1),%0\n"
0049         "6: jz    4f\n"
0050         "1: algr  %0,%3\n"
0051         "   slgr  %1,%3\n"
0052         "   slgr  %2,%3\n"
0053         "   j     0b\n"
0054         "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
0055         "   nr    %4,%3\n"  /* %4 = (ptr + 4095) & -4096 */
0056         "   slgr  %4,%1\n"
0057         "   clgr  %0,%4\n"  /* copy crosses next page boundary? */
0058         "   jnh   5f\n"
0059         "3: mvcos 0(%2),0(%1),%4\n"
0060         "7: slgr  %0,%4\n"
0061         "   j     5f\n"
0062         "4: slgr  %0,%0\n"
0063         "5:\n"
0064         EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
0065         : "+a" (size), "+a" (from), "+a" (to), "+a" (tmp1), "=a" (tmp2)
0066         : [spec] "d" (spec.val)
0067         : "cc", "memory", "0");
0068     return size;
0069 }
0070 
0071 unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
0072 {
0073     return raw_copy_from_user_key(to, from, n, 0);
0074 }
0075 EXPORT_SYMBOL(raw_copy_from_user);
0076 
0077 unsigned long _copy_from_user_key(void *to, const void __user *from,
0078                   unsigned long n, unsigned long key)
0079 {
0080     unsigned long res = n;
0081 
0082     might_fault();
0083     if (!should_fail_usercopy()) {
0084         instrument_copy_from_user(to, from, n);
0085         res = raw_copy_from_user_key(to, from, n, key);
0086     }
0087     if (unlikely(res))
0088         memset(to + (n - res), 0, res);
0089     return res;
0090 }
0091 EXPORT_SYMBOL(_copy_from_user_key);
0092 
0093 static unsigned long raw_copy_to_user_key(void __user *to, const void *from,
0094                       unsigned long size, unsigned long key)
0095 {
0096     unsigned long tmp1, tmp2;
0097     union oac spec = {
0098         .oac1.key = key,
0099         .oac1.as = PSW_BITS_AS_SECONDARY,
0100         .oac1.k = 1,
0101         .oac1.a = 1,
0102     };
0103 
0104     tmp1 = -4096UL;
0105     asm volatile(
0106         "   lr    0,%[spec]\n"
0107         "0: mvcos 0(%1),0(%2),%0\n"
0108         "6: jz    4f\n"
0109         "1: algr  %0,%3\n"
0110         "   slgr  %1,%3\n"
0111         "   slgr  %2,%3\n"
0112         "   j     0b\n"
0113         "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
0114         "   nr    %4,%3\n"  /* %4 = (ptr + 4095) & -4096 */
0115         "   slgr  %4,%1\n"
0116         "   clgr  %0,%4\n"  /* copy crosses next page boundary? */
0117         "   jnh   5f\n"
0118         "3: mvcos 0(%1),0(%2),%4\n"
0119         "7: slgr  %0,%4\n"
0120         "   j     5f\n"
0121         "4: slgr  %0,%0\n"
0122         "5:\n"
0123         EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
0124         : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
0125         : [spec] "d" (spec.val)
0126         : "cc", "memory", "0");
0127     return size;
0128 }
0129 
0130 unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
0131 {
0132     return raw_copy_to_user_key(to, from, n, 0);
0133 }
0134 EXPORT_SYMBOL(raw_copy_to_user);
0135 
0136 unsigned long _copy_to_user_key(void __user *to, const void *from,
0137                 unsigned long n, unsigned long key)
0138 {
0139     might_fault();
0140     if (should_fail_usercopy())
0141         return n;
0142     instrument_copy_to_user(to, from, n);
0143     return raw_copy_to_user_key(to, from, n, key);
0144 }
0145 EXPORT_SYMBOL(_copy_to_user_key);
0146 
0147 unsigned long __clear_user(void __user *to, unsigned long size)
0148 {
0149     unsigned long tmp1, tmp2;
0150     union oac spec = {
0151         .oac1.as = PSW_BITS_AS_SECONDARY,
0152         .oac1.a = 1,
0153     };
0154 
0155     tmp1 = -4096UL;
0156     asm volatile(
0157         "   lr    0,%[spec]\n"
0158         "0: mvcos 0(%1),0(%4),%0\n"
0159         "   jz    4f\n"
0160         "1: algr  %0,%2\n"
0161         "   slgr  %1,%2\n"
0162         "   j     0b\n"
0163         "2: la    %3,4095(%1)\n"/* %4 = to + 4095 */
0164         "   nr    %3,%2\n"  /* %4 = (to + 4095) & -4096 */
0165         "   slgr  %3,%1\n"
0166         "   clgr  %0,%3\n"  /* copy crosses next page boundary? */
0167         "   jnh   5f\n"
0168         "3: mvcos 0(%1),0(%4),%3\n"
0169         "   slgr  %0,%3\n"
0170         "   j     5f\n"
0171         "4: slgr  %0,%0\n"
0172         "5:\n"
0173         EX_TABLE(0b,2b) EX_TABLE(3b,5b)
0174         : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
0175         : "a" (empty_zero_page), [spec] "d" (spec.val)
0176         : "cc", "memory", "0");
0177     return size;
0178 }
0179 EXPORT_SYMBOL(__clear_user);