+229
-4
arch/parisc/kernel/syscall.S
+229
-4
arch/parisc/kernel/syscall.S
···
74
74
/* ADDRESS 0xb0 to 0xb8, lws uses two insns for entry */
75
75
/* Light-weight-syscall entry must always be located at 0xb0 */
76
76
/* WARNING: Keep this number updated with table size changes */
77
-
#define __NR_lws_entries (2)
77
+
#define __NR_lws_entries (3)
78
78
79
79
lws_entry:
80
80
gate lws_start, %r0 /* increase privilege */
···
502
502
503
503
504
504
/***************************************************
505
-
Implementing CAS as an atomic operation:
505
+
Implementing 32bit CAS as an atomic operation:
506
506
507
507
%r26 - Address to examine
508
508
%r25 - Old value to check (old)
···
659
659
ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 3b-linux_gateway_page)
660
660
661
661
662
+
/***************************************************
663
+
New CAS implementation which uses pointers and variable size
664
+
information. The value pointed by old and new MUST NOT change
665
+
while performing CAS. The lock only protect the value at %r26.
666
+
667
+
%r26 - Address to examine
668
+
%r25 - Pointer to the value to check (old)
669
+
%r24 - Pointer to the value to set (new)
670
+
%r23 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
671
+
%r28 - Return non-zero on failure
672
+
%r21 - Kernel error code
673
+
674
+
%r21 has the following meanings:
675
+
676
+
EAGAIN - CAS is busy, ldcw failed, try again.
677
+
EFAULT - Read or write failed.
678
+
679
+
Scratch: r20, r22, r28, r29, r1, fr4 (32bit for 64bit CAS only)
680
+
681
+
****************************************************/
682
+
683
+
/* ELF32 Process entry path */
684
+
lws_compare_and_swap_2:
685
+
#ifdef CONFIG_64BIT
686
+
/* Clip the input registers */
687
+
depdi 0, 31, 32, %r26
688
+
depdi 0, 31, 32, %r25
689
+
depdi 0, 31, 32, %r24
690
+
depdi 0, 31, 32, %r23
691
+
#endif
692
+
693
+
/* Check the validity of the size pointer */
694
+
subi,>>= 4, %r23, %r0
695
+
b,n lws_exit_nosys
696
+
697
+
/* Jump to the functions which will load the old and new values into
698
+
registers depending on the their size */
699
+
shlw %r23, 2, %r29
700
+
blr %r29, %r0
701
+
nop
702
+
703
+
/* 8bit load */
704
+
4: ldb 0(%sr3,%r25), %r25
705
+
b cas2_lock_start
706
+
5: ldb 0(%sr3,%r24), %r24
707
+
nop
708
+
nop
709
+
nop
710
+
nop
711
+
nop
712
+
713
+
/* 16bit load */
714
+
6: ldh 0(%sr3,%r25), %r25
715
+
b cas2_lock_start
716
+
7: ldh 0(%sr3,%r24), %r24
717
+
nop
718
+
nop
719
+
nop
720
+
nop
721
+
nop
722
+
723
+
/* 32bit load */
724
+
8: ldw 0(%sr3,%r25), %r25
725
+
b cas2_lock_start
726
+
9: ldw 0(%sr3,%r24), %r24
727
+
nop
728
+
nop
729
+
nop
730
+
nop
731
+
nop
732
+
733
+
/* 64bit load */
734
+
#ifdef CONFIG_64BIT
735
+
10: ldd 0(%sr3,%r25), %r25
736
+
11: ldd 0(%sr3,%r24), %r24
737
+
#else
738
+
/* Load new value into r22/r23 - high/low */
739
+
10: ldw 0(%sr3,%r25), %r22
740
+
11: ldw 4(%sr3,%r25), %r23
741
+
/* Load new value into fr4 for atomic store later */
742
+
12: flddx 0(%sr3,%r24), %fr4
743
+
#endif
744
+
745
+
cas2_lock_start:
746
+
/* Load start of lock table */
747
+
ldil L%lws_lock_start, %r20
748
+
ldo R%lws_lock_start(%r20), %r28
749
+
750
+
/* Extract four bits from r26 and hash lock (Bits 4-7) */
751
+
extru %r26, 27, 4, %r20
752
+
753
+
/* Find lock to use, the hash is either one of 0 to
754
+
15, multiplied by 16 (keep it 16-byte aligned)
755
+
and add to the lock table offset. */
756
+
shlw %r20, 4, %r20
757
+
add %r20, %r28, %r20
758
+
759
+
rsm PSW_SM_I, %r0 /* Disable interrupts */
760
+
/* COW breaks can cause contention on UP systems */
761
+
LDCW 0(%sr2,%r20), %r28 /* Try to acquire the lock */
762
+
cmpb,<>,n %r0, %r28, cas2_action /* Did we get it? */
763
+
cas2_wouldblock:
764
+
ldo 2(%r0), %r28 /* 2nd case */
765
+
ssm PSW_SM_I, %r0
766
+
b lws_exit /* Contended... */
767
+
ldo -EAGAIN(%r0), %r21 /* Spin in userspace */
768
+
769
+
/*
770
+
prev = *addr;
771
+
if ( prev == old )
772
+
*addr = new;
773
+
return prev;
774
+
*/
775
+
776
+
/* NOTES:
777
+
This all works becuse intr_do_signal
778
+
and schedule both check the return iasq
779
+
and see that we are on the kernel page
780
+
so this process is never scheduled off
781
+
or is ever sent any signal of any sort,
782
+
thus it is wholly atomic from usrspaces
783
+
perspective
784
+
*/
785
+
cas2_action:
786
+
/* Jump to the correct function */
787
+
blr %r29, %r0
788
+
/* Set %r28 as non-zero for now */
789
+
ldo 1(%r0),%r28
790
+
791
+
/* 8bit CAS */
792
+
13: ldb,ma 0(%sr3,%r26), %r29
793
+
sub,= %r29, %r25, %r0
794
+
b,n cas2_end
795
+
14: stb,ma %r24, 0(%sr3,%r26)
796
+
b cas2_end
797
+
copy %r0, %r28
798
+
nop
799
+
nop
800
+
801
+
/* 16bit CAS */
802
+
15: ldh,ma 0(%sr3,%r26), %r29
803
+
sub,= %r29, %r25, %r0
804
+
b,n cas2_end
805
+
16: sth,ma %r24, 0(%sr3,%r26)
806
+
b cas2_end
807
+
copy %r0, %r28
808
+
nop
809
+
nop
810
+
811
+
/* 32bit CAS */
812
+
17: ldw,ma 0(%sr3,%r26), %r29
813
+
sub,= %r29, %r25, %r0
814
+
b,n cas2_end
815
+
18: stw,ma %r24, 0(%sr3,%r26)
816
+
b cas2_end
817
+
copy %r0, %r28
818
+
nop
819
+
nop
820
+
821
+
/* 64bit CAS */
822
+
#ifdef CONFIG_64BIT
823
+
19: ldd,ma 0(%sr3,%r26), %r29
824
+
sub,= %r29, %r25, %r0
825
+
b,n cas2_end
826
+
20: std,ma %r24, 0(%sr3,%r26)
827
+
copy %r0, %r28
828
+
#else
829
+
/* Compare first word */
830
+
19: ldw,ma 0(%sr3,%r26), %r29
831
+
sub,= %r29, %r22, %r0
832
+
b,n cas2_end
833
+
/* Compare second word */
834
+
20: ldw,ma 4(%sr3,%r26), %r29
835
+
sub,= %r29, %r23, %r0
836
+
b,n cas2_end
837
+
/* Perform the store */
838
+
21: fstdx %fr4, 0(%sr3,%r26)
839
+
copy %r0, %r28
840
+
#endif
841
+
842
+
cas2_end:
843
+
/* Free lock */
844
+
stw,ma %r20, 0(%sr2,%r20)
845
+
/* Enable interrupts */
846
+
ssm PSW_SM_I, %r0
847
+
/* Return to userspace, set no error */
848
+
b lws_exit
849
+
copy %r0, %r21
850
+
851
+
22:
852
+
/* Error occurred on load or store */
853
+
/* Free lock */
854
+
stw %r20, 0(%sr2,%r20)
855
+
ssm PSW_SM_I, %r0
856
+
ldo 1(%r0),%r28
857
+
b lws_exit
858
+
ldo -EFAULT(%r0),%r21 /* set errno */
859
+
nop
860
+
nop
861
+
nop
862
+
863
+
/* Exception table entries, for the load and store, return EFAULT.
864
+
Each of the entries must be relocated. */
865
+
ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 22b-linux_gateway_page)
866
+
ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 22b-linux_gateway_page)
867
+
ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 22b-linux_gateway_page)
868
+
ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 22b-linux_gateway_page)
869
+
ASM_EXCEPTIONTABLE_ENTRY(8b-linux_gateway_page, 22b-linux_gateway_page)
870
+
ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 22b-linux_gateway_page)
871
+
ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 22b-linux_gateway_page)
872
+
ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 22b-linux_gateway_page)
873
+
ASM_EXCEPTIONTABLE_ENTRY(13b-linux_gateway_page, 22b-linux_gateway_page)
874
+
ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 22b-linux_gateway_page)
875
+
ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 22b-linux_gateway_page)
876
+
ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 22b-linux_gateway_page)
877
+
ASM_EXCEPTIONTABLE_ENTRY(17b-linux_gateway_page, 22b-linux_gateway_page)
878
+
ASM_EXCEPTIONTABLE_ENTRY(18b-linux_gateway_page, 22b-linux_gateway_page)
879
+
ASM_EXCEPTIONTABLE_ENTRY(19b-linux_gateway_page, 22b-linux_gateway_page)
880
+
ASM_EXCEPTIONTABLE_ENTRY(20b-linux_gateway_page, 22b-linux_gateway_page)
881
+
#ifndef CONFIG_64BIT
882
+
ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 22b-linux_gateway_page)
883
+
ASM_EXCEPTIONTABLE_ENTRY(21b-linux_gateway_page, 22b-linux_gateway_page)
884
+
#endif
885
+
662
886
/* Make sure nothing else is placed on this page */
663
887
.align PAGE_SIZE
664
888
END(linux_gateway_page)
···
899
675
/* Light-weight-syscall table */
900
676
/* Start of lws table. */
901
677
ENTRY(lws_table)
902
-
LWS_ENTRY(compare_and_swap32) /* 0 - ELF32 Atomic compare and swap */
903
-
LWS_ENTRY(compare_and_swap64) /* 1 - ELF64 Atomic compare and swap */
678
+
LWS_ENTRY(compare_and_swap32) /* 0 - ELF32 Atomic 32bit CAS */
679
+
LWS_ENTRY(compare_and_swap64) /* 1 - ELF64 Atomic 32bit CAS */
680
+
LWS_ENTRY(compare_and_swap_2) /* 2 - ELF32 Atomic 64bit CAS */
904
681
END(lws_table)
905
682
/* End of lws table */
906
683