@@ -49,51 +49,85 @@ int __get_user_bad(void) __attribute__((noreturn));
4949
5050#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
5151
52- #define __put_get_user_asm (to , from , size , insn ) \
53- ({ \
54- int __rc; \
55- \
56- asm volatile( \
57- insn " 0,%[spec]\n" \
58- "0: mvcos %[_to],%[_from],%[_size]\n" \
59- "1: xr %[rc],%[rc]\n" \
60- "2:\n" \
61- ".pushsection .fixup, \"ax\"\n" \
62- "3: lhi %[rc],%[retval]\n" \
63- " jg 2b\n" \
64- ".popsection\n" \
65- EX_TABLE(0b,3b) EX_TABLE(1b,3b) \
66- : [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \
67- : [_size] "d" (size), [_from] "Q" (*(from)), \
68- [retval] "K" (-EFAULT), [spec] "K" (0x81UL) \
69- : "cc", "0"); \
70- __rc; \
52+ union oac {
53+ unsigned int val ;
54+ struct {
55+ struct {
56+ unsigned short key : 4 ;
57+ unsigned short : 4 ;
58+ unsigned short as : 2 ;
59+ unsigned short : 4 ;
60+ unsigned short k : 1 ;
61+ unsigned short a : 1 ;
62+ } oac1 ;
63+ struct {
64+ unsigned short key : 4 ;
65+ unsigned short : 4 ;
66+ unsigned short as : 2 ;
67+ unsigned short : 4 ;
68+ unsigned short k : 1 ;
69+ unsigned short a : 1 ;
70+ } oac2 ;
71+ };
72+ };
73+
74+ #define __put_get_user_asm (to , from , size , oac_spec ) \
75+ ({ \
76+ int __rc; \
77+ \
78+ asm volatile( \
79+ " lr 0,%[spec]\n" \
80+ "0: mvcos %[_to],%[_from],%[_size]\n" \
81+ "1: xr %[rc],%[rc]\n" \
82+ "2:\n" \
83+ ".pushsection .fixup, \"ax\"\n" \
84+ "3: lhi %[rc],%[retval]\n" \
85+ " jg 2b\n" \
86+ ".popsection\n" \
87+ EX_TABLE(0b,3b) EX_TABLE(1b,3b) \
88+ : [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \
89+ : [_size] "d" (size), [_from] "Q" (*(from)), \
90+ [retval] "K" (-EFAULT), [spec] "d" (oac_spec.val) \
91+ : "cc", "0"); \
92+ __rc; \
7193})
7294
95+ #define __put_user_asm (to , from , size ) \
96+ __put_get_user_asm(to, from, size, ((union oac) { \
97+ .oac1.as = PSW_BITS_AS_SECONDARY, \
98+ .oac1.a = 1 \
99+ }))
100+
101+ #define __get_user_asm (to , from , size ) \
102+ __put_get_user_asm(to, from, size, ((union oac) { \
103+ .oac2.as = PSW_BITS_AS_SECONDARY, \
104+ .oac2.a = 1 \
105+ })) \
106+
73107static __always_inline int __put_user_fn (void * x , void __user * ptr , unsigned long size )
74108{
75109 int rc ;
76110
77111 switch (size ) {
78112 case 1 :
79- rc = __put_get_user_asm ((unsigned char __user * )ptr ,
80- (unsigned char * )x ,
81- size , "llilh" );
113+ rc = __put_user_asm ((unsigned char __user * )ptr ,
114+ (unsigned char * )x ,
115+ size );
82116 break ;
83117 case 2 :
84- rc = __put_get_user_asm ((unsigned short __user * )ptr ,
85- (unsigned short * )x ,
86- size , "llilh" );
118+ rc = __put_user_asm ((unsigned short __user * )ptr ,
119+ (unsigned short * )x ,
120+ size );
87121 break ;
88122 case 4 :
89- rc = __put_get_user_asm ((unsigned int __user * )ptr ,
90- (unsigned int * )x ,
91- size , "llilh" );
123+ rc = __put_user_asm ((unsigned int __user * )ptr ,
124+ (unsigned int * )x ,
125+ size );
92126 break ;
93127 case 8 :
94- rc = __put_get_user_asm ((unsigned long __user * )ptr ,
95- (unsigned long * )x ,
96- size , "llilh" );
128+ rc = __put_user_asm ((unsigned long __user * )ptr ,
129+ (unsigned long * )x ,
130+ size );
97131 break ;
98132 default :
99133 __put_user_bad ();
@@ -108,24 +142,24 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign
108142
109143 switch (size ) {
110144 case 1 :
111- rc = __put_get_user_asm ((unsigned char * )x ,
112- (unsigned char __user * )ptr ,
113- size , "lghi" );
145+ rc = __get_user_asm ((unsigned char * )x ,
146+ (unsigned char __user * )ptr ,
147+ size );
114148 break ;
115149 case 2 :
116- rc = __put_get_user_asm ((unsigned short * )x ,
117- (unsigned short __user * )ptr ,
118- size , "lghi" );
150+ rc = __get_user_asm ((unsigned short * )x ,
151+ (unsigned short __user * )ptr ,
152+ size );
119153 break ;
120154 case 4 :
121- rc = __put_get_user_asm ((unsigned int * )x ,
122- (unsigned int __user * )ptr ,
123- size , "lghi" );
155+ rc = __get_user_asm ((unsigned int * )x ,
156+ (unsigned int __user * )ptr ,
157+ size );
124158 break ;
125159 case 8 :
126- rc = __put_get_user_asm ((unsigned long * )x ,
127- (unsigned long __user * )ptr ,
128- size , "lghi" );
160+ rc = __get_user_asm ((unsigned long * )x ,
161+ (unsigned long __user * )ptr ,
162+ size );
129163 break ;
130164 default :
131165 __get_user_bad ();
0 commit comments