#include <linux/kernel.h>
#include <linux/types.h>

#include <asm/uaccess.h>
#include <asm/errno.h>


unsigned long __copy_user_8      (void *dest, void *src, Int n);
unsigned long __copy_user_32     (void *dest, void *src, Int n);
unsigned long __copy_to_user_64  (void *dest, void *src, Int n);
unsigned long __copy_from_user_64(void *dest, void *src, Int n);


unsigned long __copy_to_user(void *Dest, void *Src, size_t n)
{
    char *dest = Dest;
    char *src = Src;  
    int   ret;

    if(n > 32){
        int alig = (Int)dest&0x7;

        if( alig == ((Int)src&0x7)){

            if ( alig > 0){
                alig = 8 - alig;    
                if((ret = __copy_user_8(dest,src,alig)) != 0) return(ret);
                dest += alig;
                src  += alig;
                n    -= alig;
            }
            return (__copy_to_user_64( dest, src, n ));

        } else {
            alig = (Int)dest&0x3;
            if(alig == ((Int)src&0x3)){
                Int n32;

                if (alig > 0) {
                    alig = 4 - alig;
		    if((ret = __copy_user_8(dest,src,alig)) != 0) return(ret);
                    dest += alig;
                    src  += alig;
                    n    -= alig;
                }
                n32 = n/4;
		if((ret = __copy_user_32(dest,src,n32)) != 0) return(ret);
                dest += n32*4;
                src  += n32*4;
                n    -= n32*4;
            }
	}
    }
    return( __copy_user_8(dest, src, n) );
}

unsigned long __copy_from_user(void *Dest, void *Src, size_t n)
{
    char *dest = Dest;
    char *src = Src;
    int   ret;

    if(n > 32){
        int alig = (Int)dest&0x7;
        if( alig == ((Int)src&0x7)){

            if(alig > 0){
                alig = 8 - alig;    
                if((ret = __copy_user_8(dest,src,alig)) != 0) {
                    return(ret);
                }
                dest += alig;
                src += alig;
                n -= alig;
            }
            return (__copy_from_user_64( dest, src, n ));

        } else {
            alig = (Int)dest&0x3;
            if(alig == ((Int)src&0x3)){
                Int n32;

                if (alig > 0) {
                    alig = 4 - alig;
		    if((ret = __copy_user_8(dest,src,alig)) != 0) return(ret);
                    dest += alig;
                    src  += alig;
                    n    -= alig;
                }
                n32 = n/4;
		if((ret = __copy_user_32(dest,src,n32)) != 0) return(ret);
                dest += n32*4;
                src  += n32*4;
                n    -= n32*4;
            }
        }
    }
    return( __copy_user_8(dest, src, n) );
}


asm("
	.text
	.type		__copy_user_8,@function
__copy_user_8:
	.f0             cle.s32/p       all:p2   r34  r62 
	;
	.i0               mv.32         cl1:r13  r33 
	;
	.i0 ( p2 )          bra             r63
	.f0 ( p2 )        mv.32             r32  16@(0)
	;
	.i0               prset             r62
	.f0 ( p3 )        mv.32         cl1:r4   r34 
	.i1               prset             r62
	;
	;
	.i0             decr.32             r4   r32  16@1
	.i1                mv.1         all:p2   p1  
	.f1             decr.32             r13  r13  16@1
	;

.L__copy_user_8.MS.5:
	.i0 ( p9 )        tst.8             r11  r4   6@1
	.i1 ( p3 )       tld.u8         all:r5   r13  6@1
	.f1             cgt.s32         all:p9   r4   6@0
	;
.Lcu8_st1:
	.i0 ( p8 )        tst.8             r10  r4   6@1
	.i1 ( p10)       tld.u8         all:r12  r13  6@1
	.f1             cgt.s32         all:p8   r4   6@1
	;
.Lcu8_st2:
	.i0 ( p7 )        tst.8             r9   r4   6@1
	.i1 ( p9 )       tld.u8         all:r11  r13  6@1
	.f1             cgt.s32         all:p7   r4   6@2
	;
.Lcu8_st3:
	.i0 ( p6 )        tst.8             r8   r4   6@1
	.i1 ( p8 )       tld.u8         all:r10  r13  6@1
	.f1             cgt.s32         all:p6   r4   6@3
	;
.Lcu8_st4:
	.i0 ( p5 )        tst.8             r7   r4   6@1
	.i1 ( p7 )       tld.u8         all:r9   r13  6@1
	.f1             cgt.s32         all:p5   r4   6@4
	;
.Lcu8_st5:
	.i0 ( p4 )        tst.8             r6   r4   6@1
	.i1 ( p6 )       tld.u8         all:r8   r13  6@1
	.f1             cgt.s32         all:p4   r4   6@5
	;
.Lcu8_st6:
	.i0 ( p2 )          bra             19@(.L__copy_user_8.MS.5)
	.i1             decr.32             r4   r4   16@8
	.f1             cgt.s32         all:p2   r4   6@8
	;
	.i0 ( p3 )        tst.8             r5   r4   6@1
	.i1 ( p5 )       tld.u8         all:r7   r13  6@1
	.f1             cgt.s32         all:p3   r4   6@(-2)
	;
.Lcu8_st7:
	.i0 ( p10)        tst.8             r12  r4   6@1
	.i1 ( p4 )       tld.u8         all:r6   r13  6@1
	.f1             cgt.s32         all:p10  r4   6@(-1)
	;
.Lcu8_st8:

	.i0                 bra             r63
	;
	.i0               mv.32             r32  16@(0);
	;
	;


        .type           __copy_user_32,@function
__copy_user_32:
        .f0             cle.s32/p       all:p2   r34  r62
        ;
        .i0               mv.32         cl1:r13  r33  
        ;
        .i0 ( p2 )          bra             r63
	.f0 ( p2 )        mv.32             r32  16@(0)
        ;
        .i0               prset             r62  
        .f0 ( p3 )        mv.32         cl1:r4   r34  
        .i1               prset             r62
        ;
        ;
        .i0             decr.32             r4   r32  16@4
        .i1                mv.1         all:p2   p1
        .f1             decr.32             r13  r13  16@4
        ;

.L__copy_user_32.MS.5:
        .i0 ( p9 )      tsst.32             r11  r4   6@1
        .i1 ( p3 )      tsld.32         all:r5   r13  6@1
        .f1             cgt.s32         all:p9   r4   6@0
        ;
.Lcu32_st1:
        .i0 ( p8 )      tsst.32             r10  r4   6@1
        .i1 ( p10)      tsld.32         all:r12  r13  6@1
        .f1             cgt.s32         all:p8   r4   6@1
        ;
.Lcu32_st2:
        .i0 ( p7 )      tsst.32             r9   r4   6@1
        .i1 ( p9 )      tsld.32         all:r11  r13  6@1
        .f1             cgt.s32         all:p7   r4   6@2
        ;
.Lcu32_st3:
        .i0 ( p6 )      tsst.32             r8   r4   6@1
        .i1 ( p8 )      tsld.32         all:r10  r13  6@1
        .f1             cgt.s32         all:p6   r4   6@3
        ;
.Lcu32_st4:
        .i0 ( p5 )      tsst.32             r7   r4   6@1
        .i1 ( p7 )      tsld.32         all:r9   r13  6@1
        .f1             cgt.s32         all:p5   r4   6@4
        ;
.Lcu32_st5:
        .i0 ( p4 )      tsst.32             r6   r4   6@1
        .i1 ( p6 )      tsld.32         all:r8   r13  6@1
        .f1             cgt.s32         all:p4   r4   6@5
        ;
.Lcu32_st6:
        .i0 ( p2 )          bra             19@(.L__copy_user_32.MS.5)
        .i1             decr.32             r4   r4   16@8
        .f1             cgt.s32         all:p2   r4   6@8
        ;
        .i0 ( p3 )      tsst.32             r5   r4   6@1
        .i1 ( p5 )      tsld.32         all:r7   r13  6@1
        .f1             cgt.s32         all:p3   r4   6@(-2)
        ;
.Lcu32_st7:
        .i0 ( p10)      tsst.32             r12  r4   6@1
        .i1 ( p4 )      tsld.32         all:r6   r13  6@1
        .f1             cgt.s32         all:p10  r4   6@(-1)
        ;
.Lcu32_st8:

        .i0                 bra             r63
        ;
	.i0               mv.32             r32  16@(0)
        ;
        ;


	.global __clear_user
__clear_user:
;
	.i0               mv.32             r61  r33 
	.f0               mv.32             r55  r32 ;
.LL6.3:
	.i0              sub.32             r61  r61  6@(1)
	.f0             cne.u32             r60  r61  zero;
;
.LL7.3:
	.i0             neqv.32         all:p15  zero r60 
	.i1                mnop             1;
	.i1 (!p15)          bra             19@(.LL8.3);
	.i1 ( p15)          bra             19@.LL6.3;
;
	.i0                st.8             zero r55  6@(0)
	.f0              add.32             r55  r55  6@(1);
.Lclu8_st:
.LL8.3:
	.i0               mv.32             r32  16@(0);
	.i0                 bra             r63 ;
;
;


	.global __strnlen_user
__strnlen_user:
;
	.i0               mv.32             r55  r32 
	.f0               mv.32             r61  r33 ;
.LL15.3:
	.i0              sub.32             r61  r61  6@(1)
	.f0             cne.u32             r60  r61  zero;
;
.LL16.3:
	.i0             neqv.32         all:p15  zero r60 
	.i1                mnop             1;
	.i1 (!p15)          bra             19@(.LL18.3);
;
;
	.i0               ld.s8             r60  r55  6@(0)
	.i1                mnop             3;
.Lstr8_ld:
;
;
	.f0             cne.u32             r60  r60  zero;
.LL17.3:
	.i0             neqv.32         all:p15  zero r60 
	.i1                mnop             1;
	.i1 (!p15)          bra             19@(.LL19.3);
	.i1 ( p15)          bra             19@.LL15.3;
;
	.f0              add.32             r55  r55  6@(1);
.LL19.3:
	.i0               mv.32             r61  r32 
	.f0               mv.32             r60  r63 ;
;
.LL20.3:
	.f0              sub.32             r61  r55  r61 ;
	.f0              add.32             r32  r61  6@(1);
	.f0               mv.32             r63  r60 
	.i1                mnop             1;
	.i0                 bra             r63 ;
;
;
.LL18.3:
	.i0               mv.32             r61  r32 
	.f0               mv.32             r60  r63 
	.i1                 bra             19@.LL20.3;
;
;
.Lf1:	.i0		    bra		    r63;
	.i0		  mv.32		    r32  zero;
;

	.global		__copy_to_user_64
__copy_to_user_64:
.L__copy_to_user_64.prologue:
	.i0         band_s2i.32         all:r9   r34  6@7
	.f0             band.32             p15  r34  6@7
	.i1               mv.32         cl0:r4   16@1
	;
	.i0              sub.32         all:r37  r33  6@48
	.f0             cge.u32         all:p2   r34  6@8
	.i1               mv.32         cl0:r6   16@48
	;
	.i0             cge.u32             p4   r34  6@24
	.f0              add.32         all:r10  r37  r9  
	.i1             cge.u32             p3   r9   6@16
	.f1             cge.u32             p5   r9   6@32
	;
	.i0 ( p15)       tld.32         cl1:r41  r6   r10 
	.f0             band.32             r5   r34  6@4
	.i1 ( p2 )       sld.64         cl0:r50  r37  6@6
	.f1             cge.u32         all:p6   r9   6@40
	;
	.i0 ( p15)       ld.u16             r42  r6   r5  
	.f0              sub.32         all:r35  r32  6@8
	.i1 ( p3 )      tsld.64             r50  r37  6@7
	.f1             cge.u32             p7   r9   6@48
	;

.L__copy_to_user_64.kernel:
	.i0 ( p4 )      tsld.64             r52  r33  6@2
	.f0             clt.u32             p8   r33  r10 
	.i1 ( p5 )      tsld.64             r52  r37  6@2
	.f1             clt.u32/a:p3        p8   r37  r10 
	;
	.i0 ( p6 )      tsld.64             r54  r33  6@2
	.f0             clt.u32             p9   r33  r10 
	.i1 ( p7 )      tsld.64             r54  r37  6@2
	.f1             clt.u32/a:p3        p9   r37  r10 
	;
	.i0 ( p8 )      tsld.64             r46  r33  6@2
	.f0             clt.u32             p10  r33  r10 
	.i1 ( p8 )      tsld.64             r46  r37  6@2
	.f1             clt.u32/a:p3        p10  r37  r10 
	;
	.i0 ( p9 )      tsld.64             r48  r33  6@2
	.f0             clt.u32         all:p11  r33  r10 
	.i1 ( p9 )      tsld.64             r48  r37  6@2
	.f1             clt.u32/a:p3        p12  r37  r10;
        
	.i0 ( p2 )      tsst.64             r50  r35  r4  
	.f0             clt.u32             p14  r33  r10 
	.i1 ( p10)      tsld.64             r60  r37  6@2
	.f1             clt.u32/a:p3        p14  r37  r10 ; 
.Lctu64_st1:        
	.i0 ( p10)      tsld.64             r50  r33  6@2
	.f0                mv.1/a:p15       p13 !p11 
	.i1 ( p3 )      tsst.64             r50  r35  6@2
	.f1                mv.1             p3   p10 ;
.Lctu64_st2:
	.i0 ( p4 )      tsst.64             r52  r35  6@2
	.f0             band.32         all:r7   r34  6@6
	.i1 ( p5 )      tsst.64             r52  r35  6@2
	.f1                mv.1             p5   p12; 
.Lctu64_st3: 	
	.i0 ( p13)        ld.u8         cl1:r43  r6   r7  
	.f0                mv.1             p2   p10 
	.i1 ( p7 )      tsst.64             r54  r35  6@2
	.f1                mv.1             p7   p14;
.Lctu64_st4:        
	.i0 ( p6 )      tsst.64             r54  r35  6@2
	.f0              add.32         all:r8   r32  r9  
	.i1 ( p11)          bra             19@(.L__copy_to_user_64.kernel)
	.f1             band.32             p13  r7   6@4;
.Lctu64_st5:       
	.i0 ( p8 )      tsst.64             r46  r35  6@2
	.f0                mv.1             p4   p11 
	.i1 ( p8 )      tsst.64             r46  r35  6@2
	.f1               mv.32         cl0:r4   16@2;
.Lctu64_st6:       
	.i0 ( p9 )      tsst.64             r48  r35  6@2
	.f0                mv.1             p6   p14 
	.i1 ( p9 )      tsst.64             r48  r35  6@2
	.f1               mv.64             r50  r60;
.Lctu64_st7:        
.Lcopy__user_64.epilogue:
	.i0                 bra             r63 
	.f0             band.32         all:p15  r34  6@1
	.i1 ( p13)        st.32             r41  r8   r62 
	.f1             band.32         all:p14  r7   6@2;
.Lctu64_st8:  
	.i0 ( p2 )      tsst.64             r50  r35  6@2
	.i1 ( p3 )      tsst.64             r50  r35  6@2;
.Lctu64_st9:	
	.i0 ( p14)        st.16             r42  r8   r5  
        .f0               mv.32		    r32  0
	.i1 ( p15)         st.8             r43  r8   r7;

.Lctu64_st10:
        ;
        ;
	.global		__copy_from_user_64
__copy_from_user_64:
.L__copy_from_user_64.prologue:
	.i0         band_s2i.32         all:r9   r34  6@7
	.f0             band.32             p15  r34  6@7
	.i1               mv.32         cl0:r4   16@1
	;
	.i0              sub.32         all:r37  r33  6@48
	.f0             cge.u32         all:p2   r34  6@8
	.i1               mv.32         cl0:r6   16@48
	;
	.i0             cge.u32             p4   r34  6@24
	.f0              add.32         all:r10  r37  r9  
	.i1             cge.u32             p3   r9   6@16
	.f1             cge.u32             p5   r9   6@32
	;
	.i0 ( p15)       tld.32         cl1:r41  r6   r10 
	.f0             band.32             r5   r34  6@4
	.i1 ( p2 )       sld.64         cl0:r50  r37  6@6
	.f1             cge.u32         all:p6   r9   6@40;
.Lcfu64_ld1:   
	.i0 ( p15)       ld.u16             r42  r6   r5  
	.f0              sub.32         all:r35  r32  6@8
	.i1 ( p3 )      tsld.64             r50  r37  6@7
	.f1             cge.u32             p7   r9   6@48;
.Lcfu64_ld2:        

.L__copy_from_user_64.kernel:
	.i0 ( p4 )      tsld.64             r52  r33  6@2
	.f0             clt.u32             p8   r33  r10 
	.i1 ( p5 )      tsld.64             r52  r37  6@2
	.f1             clt.u32/a:p3        p8   r37  r10;
.Lcfu64_ld3:        
	.i0 ( p6 )      tsld.64             r54  r33  6@2
	.f0             clt.u32             p9   r33  r10 
	.i1 ( p7 )      tsld.64             r54  r37  6@2
	.f1             clt.u32/a:p3        p9   r37  r10;
.Lcfu64_ld4:
	.i0 ( p8 )      tsld.64             r46  r33  6@2
	.f0             clt.u32             p10  r33  r10 
	.i1 ( p8 )      tsld.64             r46  r37  6@2
	.f1             clt.u32/a:p3        p10  r37  r10;
.Lcfu64_ld5:        
	.i0 ( p9 )      tsld.64             r48  r33  6@2
	.f0             clt.u32         all:p11  r33  r10 
	.i1 ( p9 )      tsld.64             r48  r37  6@2
	.f1             clt.u32/a:p3        p12  r37  r10;
.Lcfu64_ld6:        
	.i0 ( p2 )      tsst.64             r50  r35  r4  
	.f0             clt.u32             p14  r33  r10 
	.i1 ( p10)      tsld.64             r60  r37  6@2
	.f1             clt.u32/a:p3        p14  r37  r10;
.Lcfu64_ld7:         
	.i0 ( p10)      tsld.64             r50  r33  6@2
	.f0                mv.1/a:p15       p13 !p11 
	.i1 ( p3 )      tsst.64             r50  r35  6@2
	.f1                mv.1             p3   p10 ;
.Lcfu64_ld8:
	.i0 ( p4 )      tsst.64             r52  r35  6@2
	.f0             band.32         all:r7   r34  6@6
	.i1 ( p5 )      tsst.64             r52  r35  6@2
	.f1                mv.1             p5   p12
        ; 
	.i0 ( p13)        ld.u8         cl1:r43  r6   r7  
	.f0                mv.1             p2   p10 
	.i1 ( p7 )      tsst.64             r54  r35  6@2
	.f1                mv.1             p7   p14;
.Lcfu64_ld9:        
	.i0 ( p6 )      tsst.64             r54  r35  6@2
	.f0              add.32         all:r8   r32  r9  
	.i1 ( p11)          bra             19@(.L__copy_from_user_64.kernel)
	.f1             band.32             p13  r7   6@4
        ;
	.i0 ( p8 )      tsst.64             r46  r35  6@2
	.f0                mv.1             p4   p11 
	.i1 ( p8 )      tsst.64             r46  r35  6@2
	.f1               mv.32         cl0:r4   16@2
        ;
	.i0 ( p9 )      tsst.64             r48  r35  6@2
	.f0                mv.1             p6   p14 
	.i1 ( p9 )      tsst.64             r48  r35  6@2
	.f1               mv.64             r50  r60;        
.L__copy_from_user_64.epilogue:
	.i0                 bra             r63 
	.f0             band.32         all:p15  r34  6@1
	.i1 ( p13)        st.32             r41  r8   r62 
	.f1             band.32         all:p14  r7   6@2
        ;
 
	.i0 ( p2 )      tsst.64             r50  r35  6@2
	.i1 ( p3 )      tsst.64             r50  r35  6@2
        ;

	.i0 ( p14)        st.16             r42  r8   r5
        .f0               mv.32		    r32  0        
	.i1 ( p15)         st.8             r43  r8   r7
        ;
        ;

.L__exit_on_user_exception:
	.i0                 bra             r63 
	.f0		  mv.32		    r32  16@(-14)
        ;
        ;
        ;
        
	.section __ex_table, \"a\", @progbits
	.align   4
	.word	.Lcu8_st1,   .L__exit_on_user_exception
	.word	.Lcu8_st2,   .L__exit_on_user_exception
	.word	.Lcu8_st3,   .L__exit_on_user_exception
	.word	.Lcu8_st4,   .L__exit_on_user_exception
	.word	.Lcu8_st5,   .L__exit_on_user_exception
	.word	.Lcu8_st6,   .L__exit_on_user_exception
	.word	.Lcu8_st7,   .L__exit_on_user_exception
	.word	.Lcu8_st8,   .L__exit_on_user_exception
	.word	.Lcu32_st1,  .L__exit_on_user_exception
	.word	.Lcu32_st2,  .L__exit_on_user_exception
	.word	.Lcu32_st3,  .L__exit_on_user_exception
	.word	.Lcu32_st4,  .L__exit_on_user_exception
	.word	.Lcu32_st5,  .L__exit_on_user_exception
	.word	.Lcu32_st6,  .L__exit_on_user_exception
	.word	.Lcu32_st7,  .L__exit_on_user_exception
	.word	.Lcu32_st8,  .L__exit_on_user_exception
	.word	.Lclu8_st,   .L__exit_on_user_exception
	.word	.Lstr8_ld,   .Lf1
	.word	.Lctu64_st1, .L__exit_on_user_exception
	.word	.Lctu64_st2, .L__exit_on_user_exception     
	.word	.Lctu64_st3, .L__exit_on_user_exception     
	.word	.Lctu64_st4, .L__exit_on_user_exception   
	.word	.Lctu64_st5, .L__exit_on_user_exception
	.word	.Lctu64_st6, .L__exit_on_user_exception     
	.word	.Lctu64_st7, .L__exit_on_user_exception     
	.word	.Lctu64_st8, .L__exit_on_user_exception   
	.word	.Lctu64_st9, .L__exit_on_user_exception        
	.word	.Lctu64_st10,.L__exit_on_user_exception
	.word	.Lcfu64_ld1, .L__exit_on_user_exception
	.word	.Lcfu64_ld2, .L__exit_on_user_exception     
	.word	.Lcfu64_ld3, .L__exit_on_user_exception     
	.word	.Lcfu64_ld4, .L__exit_on_user_exception   
	.word	.Lcfu64_ld5, .L__exit_on_user_exception
	.word	.Lcfu64_ld6, .L__exit_on_user_exception     
	.word	.Lcfu64_ld7, .L__exit_on_user_exception     
	.word	.Lcfu64_ld8, .L__exit_on_user_exception   
	.word	.Lcfu64_ld9, .L__exit_on_user_exception                                                                                   
");



long
__strncpy_from_user(char *__to, const char *__from, long __len)
{
        long len;

        len = __strnlen_user(__from, __len); /* strlen +  '\0' */
        len = (len < __len) ? len : __len;

        if (len) __copy_from_user(__to, (void *)__from, len);
        return len;
}
