1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <asm/processor.h>
23#include <asm/uaccess.h>
24#include <asm/system.h>
25#include <asm/cache.h>
26#include <asm/cputable.h>
27
28struct aligninfo {
29 unsigned char len;
30 unsigned char flags;
31};
32
33#define IS_XFORM(inst) (((inst) >> 26) == 31)
34#define IS_DSFORM(inst) (((inst) >> 26) >= 56)
35
36#define INVALID { 0, 0 }
37
38
39#define LD 0
40#define ST 1
41#define SE 2
42#define F 4
43#define U 8
44#define M 0x10
45#define SW 0x20
46#define S 0x40
47#define SX 0x40
48#define HARD 0x80
49#define E4 0x40
50#define E8 0x80
51#define SPLT 0x80
52
53
54#define DCBZ 0x5f
55
56#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
57
58
59
60
61
62
63
64static struct aligninfo aligninfo[128] = {
65 { 4, LD },
66 INVALID,
67 { 4, ST },
68 INVALID,
69 { 2, LD },
70 { 2, LD+SE },
71 { 2, ST },
72 { 4, LD+M },
73 { 4, LD+F+S },
74 { 8, LD+F },
75 { 4, ST+F+S },
76 { 8, ST+F },
77 INVALID,
78 { 8, LD },
79 INVALID,
80 { 8, ST },
81 { 4, LD+U },
82 INVALID,
83 { 4, ST+U },
84 INVALID,
85 { 2, LD+U },
86 { 2, LD+SE+U },
87 { 2, ST+U },
88 { 4, ST+M },
89 { 4, LD+F+S+U },
90 { 8, LD+F+U },
91 { 4, ST+F+S+U },
92 { 8, ST+F+U },
93 { 16, LD+F },
94 INVALID,
95 { 16, ST+F },
96 INVALID,
97 { 8, LD },
98 INVALID,
99 { 8, ST },
100 INVALID,
101 INVALID,
102 { 4, LD+SE },
103 INVALID,
104 INVALID,
105 { 4, LD+M+HARD+SX },
106 { 4, LD+M+HARD },
107 { 4, ST+M+HARD+SX },
108 { 4, ST+M+HARD },
109 INVALID,
110 { 8, LD+U },
111 INVALID,
112 { 8, ST+U },
113 { 8, LD+U },
114 INVALID,
115 { 8, ST+U },
116 INVALID,
117 INVALID,
118 { 4, LD+SE+U },
119 INVALID,
120 INVALID,
121 INVALID,
122 INVALID,
123 INVALID,
124 INVALID,
125 INVALID,
126 INVALID,
127 INVALID,
128 INVALID,
129 INVALID,
130 INVALID,
131 INVALID,
132 INVALID,
133 INVALID,
134 INVALID,
135 INVALID,
136 INVALID,
137 { 4, LD+SW },
138 INVALID,
139 { 4, ST+SW },
140 INVALID,
141 { 2, LD+SW },
142 { 4, LD+SE },
143 { 2, ST+SW },
144 INVALID,
145 INVALID,
146 INVALID,
147 INVALID,
148 INVALID,
149 INVALID,
150 INVALID,
151 INVALID,
152 INVALID,
153 INVALID,
154 INVALID,
155 INVALID,
156 INVALID,
157 INVALID,
158 INVALID,
159 INVALID,
160 { 0, ST+HARD },
161 { 4, LD },
162 INVALID,
163 { 4, ST },
164 INVALID,
165 { 2, LD },
166 { 2, LD+SE },
167 { 2, ST },
168 INVALID,
169 { 4, LD+F+S },
170 { 8, LD+F },
171 { 4, ST+F+S },
172 { 8, ST+F },
173 { 16, LD+F },
174 { 4, LD+F+SE },
175 { 16, ST+F },
176 { 4, ST+F },
177 { 4, LD+U },
178 INVALID,
179 { 4, ST+U },
180 INVALID,
181 { 2, LD+U },
182 { 2, LD+SE+U },
183 { 2, ST+U },
184 INVALID,
185 { 4, LD+F+S+U },
186 { 8, LD+F+U },
187 { 4, ST+F+S+U },
188 { 8, ST+F+U },
189 INVALID,
190 { 4, LD+F },
191 INVALID,
192 INVALID,
193};
194
195
196
197
198static inline unsigned make_dsisr(unsigned instr)
199{
200 unsigned dsisr;
201
202
203
204 dsisr = (instr & 0x03ff0000) >> 16;
205
206 if (IS_XFORM(instr)) {
207
208 dsisr |= (instr & 0x00000006) << 14;
209
210 dsisr |= (instr & 0x00000040) << 8;
211
212 dsisr |= (instr & 0x00000780) << 3;
213 } else {
214
215 dsisr |= (instr & 0x04000000) >> 12;
216
217 dsisr |= (instr & 0x78000000) >> 17;
218
219 if (IS_DSFORM(instr))
220 dsisr |= (instr & 0x00000003) << 18;
221 }
222
223 return dsisr;
224}
225
226
227
228
229
230
231
232
233static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
234{
235 long __user *p;
236 int i, size;
237
238#ifdef __powerpc64__
239 size = ppc64_caches.dline_size;
240#else
241 size = L1_CACHE_BYTES;
242#endif
243 p = (long __user *) (regs->dar & -size);
244 if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
245 return -EFAULT;
246 for (i = 0; i < size / sizeof(long); ++i)
247 if (__put_user_inatomic(0, p+i))
248 return -EFAULT;
249 return 1;
250}
251
252
253
254
255
256
257
258#ifdef CONFIG_PPC64
259#define REG_BYTE(rp, i) *((u8 *)((rp) + ((i) >> 2)) + ((i) & 3) + 4)
260#else
261#define REG_BYTE(rp, i) *((u8 *)(rp) + (i))
262#endif
263
264#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz))
265
266static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
267 unsigned int reg, unsigned int nb,
268 unsigned int flags, unsigned int instr,
269 unsigned long swiz)
270{
271 unsigned long *rptr;
272 unsigned int nb0, i, bswiz;
273 unsigned long p;
274
275
276
277
278
279
280
281 if (unlikely((nb > 4) || !user_mode(regs)))
282 return 0;
283
284
285 nb0 = 0;
286 if (flags & HARD) {
287 if (flags & SX) {
288 nb = regs->xer & 127;
289 if (nb == 0)
290 return 1;
291 } else {
292 unsigned long pc = regs->nip ^ (swiz & 4);
293
294 if (__get_user_inatomic(instr,
295 (unsigned int __user *)pc))
296 return -EFAULT;
297 if (swiz == 0 && (flags & SW))
298 instr = cpu_to_le32(instr);
299 nb = (instr >> 11) & 0x1f;
300 if (nb == 0)
301 nb = 32;
302 }
303 if (nb + reg * 4 > 128) {
304 nb0 = nb + reg * 4 - 128;
305 nb = 128 - reg * 4;
306 }
307 } else {
308
309 nb = (32 - reg) * 4;
310 }
311
312 if (!access_ok((flags & ST ? VERIFY_WRITE: VERIFY_READ), addr, nb+nb0))
313 return -EFAULT;
314
315 rptr = ®s->gpr[reg];
316 p = (unsigned long) addr;
317 bswiz = (flags & SW)? 3: 0;
318
319 if (!(flags & ST)) {
320
321
322
323
324
325 memset(rptr, 0, ((nb + 3) / 4) * sizeof(unsigned long));
326 if (nb0 > 0)
327 memset(®s->gpr[0], 0,
328 ((nb0 + 3) / 4) * sizeof(unsigned long));
329
330 for (i = 0; i < nb; ++i, ++p)
331 if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
332 SWIZ_PTR(p)))
333 return -EFAULT;
334 if (nb0 > 0) {
335 rptr = ®s->gpr[0];
336 addr += nb;
337 for (i = 0; i < nb0; ++i, ++p)
338 if (__get_user_inatomic(REG_BYTE(rptr,
339 i ^ bswiz),
340 SWIZ_PTR(p)))
341 return -EFAULT;
342 }
343
344 } else {
345 for (i = 0; i < nb; ++i, ++p)
346 if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
347 SWIZ_PTR(p)))
348 return -EFAULT;
349 if (nb0 > 0) {
350 rptr = ®s->gpr[0];
351 addr += nb;
352 for (i = 0; i < nb0; ++i, ++p)
353 if (__put_user_inatomic(REG_BYTE(rptr,
354 i ^ bswiz),
355 SWIZ_PTR(p)))
356 return -EFAULT;
357 }
358 }
359 return 1;
360}
361
362
363
364
365
366
367static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
368 unsigned int flags)
369{
370 char *ptr0 = (char *) ¤t->thread.TS_FPR(reg);
371 char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1);
372 int i, ret, sw = 0;
373
374 if (!(flags & F))
375 return 0;
376 if (reg & 1)
377 return 0;
378 if (flags & SW)
379 sw = 7;
380 ret = 0;
381 for (i = 0; i < 8; ++i) {
382 if (!(flags & ST)) {
383 ret |= __get_user(ptr0[i^sw], addr + i);
384 ret |= __get_user(ptr1[i^sw], addr + i + 8);
385 } else {
386 ret |= __put_user(ptr0[i^sw], addr + i);
387 ret |= __put_user(ptr1[i^sw], addr + i + 8);
388 }
389 }
390 if (ret)
391 return -EFAULT;
392 return 1;
393}
394
395#ifdef CONFIG_SPE
396
397static struct aligninfo spe_aligninfo[32] = {
398 { 8, LD+E8 },
399 { 8, LD+E4 },
400 { 8, LD },
401 INVALID,
402 { 2, LD },
403 INVALID,
404 { 2, LD },
405 { 2, LD+SE },
406 { 4, LD },
407 INVALID,
408 { 4, LD },
409 { 4, LD+SE },
410 { 4, LD+E4 },
411 INVALID,
412 { 4, LD },
413 INVALID,
414
415 { 8, ST+E8 },
416 { 8, ST+E4 },
417 { 8, ST },
418 INVALID,
419 INVALID,
420 INVALID,
421 INVALID,
422 INVALID,
423 { 4, ST },
424 INVALID,
425 { 4, ST },
426 INVALID,
427 { 4, ST+E4 },
428 INVALID,
429 { 4, ST+E4 },
430 INVALID,
431};
432
433#define EVLDD 0x00
434#define EVLDW 0x01
435#define EVLDH 0x02
436#define EVLHHESPLAT 0x04
437#define EVLHHOUSPLAT 0x06
438#define EVLHHOSSPLAT 0x07
439#define EVLWHE 0x08
440#define EVLWHOU 0x0A
441#define EVLWHOS 0x0B
442#define EVLWWSPLAT 0x0C
443#define EVLWHSPLAT 0x0E
444#define EVSTDD 0x10
445#define EVSTDW 0x11
446#define EVSTDH 0x12
447#define EVSTWHE 0x18
448#define EVSTWHO 0x1A
449#define EVSTWWE 0x1C
450#define EVSTWWO 0x1E
451
452
453
454
455
456
457static int emulate_spe(struct pt_regs *regs, unsigned int reg,
458 unsigned int instr)
459{
460 int t, ret;
461 union {
462 u64 ll;
463 u32 w[2];
464 u16 h[4];
465 u8 v[8];
466 } data, temp;
467 unsigned char __user *p, *addr;
468 unsigned long *evr = ¤t->thread.evr[reg];
469 unsigned int nb, flags;
470
471 instr = (instr >> 1) & 0x1f;
472
473
474 addr = (unsigned char __user *)regs->dar;
475
476 nb = spe_aligninfo[instr].len;
477 flags = spe_aligninfo[instr].flags;
478
479
480 if (unlikely(user_mode(regs) &&
481 !access_ok((flags & ST ? VERIFY_WRITE : VERIFY_READ),
482 addr, nb)))
483 return -EFAULT;
484
485
486 if (unlikely(!user_mode(regs)))
487 return 0;
488
489 flush_spe_to_thread(current);
490
491
492
493
494 if (flags & ST) {
495 data.ll = 0;
496 switch (instr) {
497 case EVSTDD:
498 case EVSTDW:
499 case EVSTDH:
500 data.w[0] = *evr;
501 data.w[1] = regs->gpr[reg];
502 break;
503 case EVSTWHE:
504 data.h[2] = *evr >> 16;
505 data.h[3] = regs->gpr[reg] >> 16;
506 break;
507 case EVSTWHO:
508 data.h[2] = *evr & 0xffff;
509 data.h[3] = regs->gpr[reg] & 0xffff;
510 break;
511 case EVSTWWE:
512 data.w[1] = *evr;
513 break;
514 case EVSTWWO:
515 data.w[1] = regs->gpr[reg];
516 break;
517 default:
518 return -EINVAL;
519 }
520 } else {
521 temp.ll = data.ll = 0;
522 ret = 0;
523 p = addr;
524
525 switch (nb) {
526 case 8:
527 ret |= __get_user_inatomic(temp.v[0], p++);
528 ret |= __get_user_inatomic(temp.v[1], p++);
529 ret |= __get_user_inatomic(temp.v[2], p++);
530 ret |= __get_user_inatomic(temp.v[3], p++);
531 case 4:
532 ret |= __get_user_inatomic(temp.v[4], p++);
533 ret |= __get_user_inatomic(temp.v[5], p++);
534 case 2:
535 ret |= __get_user_inatomic(temp.v[6], p++);
536 ret |= __get_user_inatomic(temp.v[7], p++);
537 if (unlikely(ret))
538 return -EFAULT;
539 }
540
541 switch (instr) {
542 case EVLDD:
543 case EVLDW:
544 case EVLDH:
545 data.ll = temp.ll;
546 break;
547 case EVLHHESPLAT:
548 data.h[0] = temp.h[3];
549 data.h[2] = temp.h[3];
550 break;
551 case EVLHHOUSPLAT:
552 case EVLHHOSSPLAT:
553 data.h[1] = temp.h[3];
554 data.h[3] = temp.h[3];
555 break;
556 case EVLWHE:
557 data.h[0] = temp.h[2];
558 data.h[2] = temp.h[3];
559 break;
560 case EVLWHOU:
561 case EVLWHOS:
562 data.h[1] = temp.h[2];
563 data.h[3] = temp.h[3];
564 break;
565 case EVLWWSPLAT:
566 data.w[0] = temp.w[1];
567 data.w[1] = temp.w[1];
568 break;
569 case EVLWHSPLAT:
570 data.h[0] = temp.h[2];
571 data.h[1] = temp.h[2];
572 data.h[2] = temp.h[3];
573 data.h[3] = temp.h[3];
574 break;
575 default:
576 return -EINVAL;
577 }
578 }
579
580 if (flags & SW) {
581 switch (flags & 0xf0) {
582 case E8:
583 SWAP(data.v[0], data.v[7]);
584 SWAP(data.v[1], data.v[6]);
585 SWAP(data.v[2], data.v[5]);
586 SWAP(data.v[3], data.v[4]);
587 break;
588 case E4:
589
590 SWAP(data.v[0], data.v[3]);
591 SWAP(data.v[1], data.v[2]);
592 SWAP(data.v[4], data.v[7]);
593 SWAP(data.v[5], data.v[6]);
594 break;
595
596 default:
597 SWAP(data.v[0], data.v[1]);
598 SWAP(data.v[2], data.v[3]);
599 SWAP(data.v[4], data.v[5]);
600 SWAP(data.v[6], data.v[7]);
601 break;
602 }
603 }
604
605 if (flags & SE) {
606 data.w[0] = (s16)data.h[1];
607 data.w[1] = (s16)data.h[3];
608 }
609
610
611 if (flags & ST) {
612 ret = 0;
613 p = addr;
614 switch (nb) {
615 case 8:
616 ret |= __put_user_inatomic(data.v[0], p++);
617 ret |= __put_user_inatomic(data.v[1], p++);
618 ret |= __put_user_inatomic(data.v[2], p++);
619 ret |= __put_user_inatomic(data.v[3], p++);
620 case 4:
621 ret |= __put_user_inatomic(data.v[4], p++);
622 ret |= __put_user_inatomic(data.v[5], p++);
623 case 2:
624 ret |= __put_user_inatomic(data.v[6], p++);
625 ret |= __put_user_inatomic(data.v[7], p++);
626 }
627 if (unlikely(ret))
628 return -EFAULT;
629 } else {
630 *evr = data.w[0];
631 regs->gpr[reg] = data.w[1];
632 }
633
634 return 1;
635}
636#endif
637
638#ifdef CONFIG_VSX
639
640
641
642static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
643 unsigned int areg, struct pt_regs *regs,
644 unsigned int flags, unsigned int length)
645{
646 char *ptr;
647 int ret = 0;
648
649 flush_vsx_to_thread(current);
650
651 if (reg < 32)
652 ptr = (char *) ¤t->thread.TS_FPR(reg);
653 else
654 ptr = (char *) ¤t->thread.vr[reg - 32];
655
656 if (flags & ST)
657 ret = __copy_to_user(addr, ptr, length);
658 else {
659 if (flags & SPLT){
660 ret = __copy_from_user(ptr, addr, length);
661 ptr += length;
662 }
663 ret |= __copy_from_user(ptr, addr, length);
664 }
665 if (flags & U)
666 regs->gpr[areg] = regs->dar;
667 if (ret)
668 return -EFAULT;
669 return 1;
670}
671#endif
672
673
674
675
676
677
678
679
680
681int fix_alignment(struct pt_regs *regs)
682{
683 unsigned int instr, nb, flags, instruction = 0;
684 unsigned int reg, areg;
685 unsigned int dsisr;
686 unsigned char __user *addr;
687 unsigned long p, swiz;
688 int ret, t;
689 union {
690 u64 ll;
691 double dd;
692 unsigned char v[8];
693 struct {
694 unsigned hi32;
695 int low32;
696 } x32;
697 struct {
698 unsigned char hi48[6];
699 short low16;
700 } x16;
701 } data;
702
703
704
705
706
707 CHECK_FULL_REGS(regs);
708
709 dsisr = regs->dsisr;
710
711
712
713
714 if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) {
715 unsigned long pc = regs->nip;
716
717 if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
718 pc ^= 4;
719 if (unlikely(__get_user_inatomic(instr,
720 (unsigned int __user *)pc)))
721 return -EFAULT;
722 if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
723 instr = cpu_to_le32(instr);
724 dsisr = make_dsisr(instr);
725 instruction = instr;
726 }
727
728
729 reg = (dsisr >> 5) & 0x1f;
730 areg = dsisr & 0x1f;
731
732#ifdef CONFIG_SPE
733 if ((instr >> 26) == 0x4)
734 return emulate_spe(regs, reg, instr);
735#endif
736
737 instr = (dsisr >> 10) & 0x7f;
738 instr |= (dsisr >> 13) & 0x60;
739
740
741 nb = aligninfo[instr].len;
742 flags = aligninfo[instr].flags;
743
744
745 swiz = 0;
746 if (regs->msr & MSR_LE) {
747 flags ^= SW;
748
749
750
751
752
753
754
755
756
757
758 if (cpu_has_feature(CPU_FTR_PPC_LE))
759 swiz = 7;
760 }
761
762
763 addr = (unsigned char __user *)regs->dar;
764
765#ifdef CONFIG_VSX
766 if ((instruction & 0xfc00003e) == 0x7c000018) {
767
768 reg |= (instruction & 0x1) << 5;
769
770 if (instruction & 0x200)
771 nb = 16;
772 else if (instruction & 0x080)
773 nb = 8;
774 else
775 nb = 4;
776 flags = 0;
777 if (instruction & 0x100)
778 flags |= ST;
779 if (instruction & 0x040)
780 flags |= U;
781
782 if ((instruction & 0x400) == 0){
783 flags |= SPLT;
784 nb = 8;
785 }
786 return emulate_vsx(addr, reg, areg, regs, flags, nb);
787 }
788#endif
789
790
791
792 if (instr == DCBZ)
793 return emulate_dcbz(regs, addr);
794 if (unlikely(nb == 0))
795 return 0;
796
797
798
799
800 if (flags & M)
801 return emulate_multiple(regs, addr, reg, nb,
802 flags, instr, swiz);
803
804
805 if (unlikely(user_mode(regs) &&
806 !access_ok((flags & ST ? VERIFY_WRITE : VERIFY_READ),
807 addr, nb)))
808 return -EFAULT;
809
810
811 if (flags & F) {
812
813 if (unlikely(!user_mode(regs)))
814 return 0;
815 flush_fp_to_thread(current);
816 }
817
818
819 if (nb == 16)
820 return emulate_fp_pair(addr, reg, flags);
821
822
823
824
825 if (!(flags & ST)) {
826 data.ll = 0;
827 ret = 0;
828 p = (unsigned long) addr;
829 switch (nb) {
830 case 8:
831 ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
832 ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
833 ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
834 ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
835 case 4:
836 ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
837 ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
838 case 2:
839 ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
840 ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
841 if (unlikely(ret))
842 return -EFAULT;
843 }
844 } else if (flags & F) {
845 data.dd = current->thread.TS_FPR(reg);
846 if (flags & S) {
847
848#ifdef CONFIG_PPC_FPU
849 preempt_disable();
850 enable_kernel_fp();
851 cvt_df(&data.dd, (float *)&data.v[4], ¤t->thread);
852 preempt_enable();
853#else
854 return 0;
855#endif
856 }
857 } else
858 data.ll = regs->gpr[reg];
859
860 if (flags & SW) {
861 switch (nb) {
862 case 8:
863 SWAP(data.v[0], data.v[7]);
864 SWAP(data.v[1], data.v[6]);
865 SWAP(data.v[2], data.v[5]);
866 SWAP(data.v[3], data.v[4]);
867 break;
868 case 4:
869 SWAP(data.v[4], data.v[7]);
870 SWAP(data.v[5], data.v[6]);
871 break;
872 case 2:
873 SWAP(data.v[6], data.v[7]);
874 break;
875 }
876 }
877
878
879
880
881 switch (flags & ~(U|SW)) {
882 case LD+SE:
883 case LD+F+SE:
884 if ( nb == 2 )
885 data.ll = data.x16.low16;
886 else
887 data.ll = data.x32.low32;
888 break;
889
890
891 case LD+F+S:
892#ifdef CONFIG_PPC_FPU
893 preempt_disable();
894 enable_kernel_fp();
895 cvt_fd((float *)&data.v[4], &data.dd, ¤t->thread);
896 preempt_enable();
897#else
898 return 0;
899#endif
900 break;
901 }
902
903
904 if (flags & ST) {
905 ret = 0;
906 p = (unsigned long) addr;
907 switch (nb) {
908 case 8:
909 ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
910 ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
911 ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
912 ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
913 case 4:
914 ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
915 ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
916 case 2:
917 ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
918 ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
919 }
920 if (unlikely(ret))
921 return -EFAULT;
922 } else if (flags & F)
923 current->thread.TS_FPR(reg) = data.dd;
924 else
925 regs->gpr[reg] = data.ll;
926
927
928 if (flags & U)
929 regs->gpr[areg] = regs->dar;
930
931 return 1;
932}
933