Linux Audio

Check our new training course

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