OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [x86/] [lib/] [copy_user_64.S] - Rev 3

Compare with Previous | Blame | View Log

/* Copyright 2002 Andi Kleen, SuSE Labs.
 * Subject to the GNU Public License v2.
 * 
 * Functions to copy from and to user space.            
 */              

#include <linux/linkage.h>
#include <asm/dwarf2.h>

#define FIX_ALIGNMENT 1

#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/cpufeature.h>

        .macro ALTERNATIVE_JUMP feature,orig,alt
0:
        .byte 0xe9      /* 32bit jump */
        .long \orig-1f  /* by default jump to orig */
1:
        .section .altinstr_replacement,"ax"
2:      .byte 0xe9                   /* near jump with 32bit immediate */
        .long \alt-1b /* offset */   /* or alternatively to alt */
        .previous
        .section .altinstructions,"a"
        .align 8
        .quad  0b
        .quad  2b
        .byte  \feature              /* when feature is set */
        .byte  5
        .byte  5
        .previous
        .endm

/* Standard copy_to_user with segment limit checking */         
ENTRY(copy_to_user)
        CFI_STARTPROC
        GET_THREAD_INFO(%rax)
        movq %rdi,%rcx
        addq %rdx,%rcx
        jc  bad_to_user
        cmpq threadinfo_addr_limit(%rax),%rcx
        jae bad_to_user
        xorl %eax,%eax  /* clear zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC

ENTRY(copy_user_generic)
        CFI_STARTPROC
        movl $1,%ecx    /* set zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC

ENTRY(__copy_from_user_inatomic)
        CFI_STARTPROC
        xorl %ecx,%ecx  /* clear zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC

/* Standard copy_from_user with segment limit checking */       
ENTRY(copy_from_user)
        CFI_STARTPROC
        GET_THREAD_INFO(%rax)
        movq %rsi,%rcx
        addq %rdx,%rcx
        jc  bad_from_user
        cmpq threadinfo_addr_limit(%rax),%rcx
        jae  bad_from_user
        movl $1,%ecx    /* set zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
ENDPROC(copy_from_user)
        
        .section .fixup,"ax"
        /* must zero dest */
bad_from_user:
        CFI_STARTPROC
        movl %edx,%ecx
        xorl %eax,%eax
        rep
        stosb
bad_to_user:
        movl    %edx,%eax
        ret
        CFI_ENDPROC
END(bad_from_user)
        .previous
        
                
/*
 * copy_user_generic_unrolled - memory copy with exception handling.
 * This version is for CPUs like P4 that don't have efficient micro code for rep movsq
 *      
 * Input:       
 * rdi destination
 * rsi source
 * rdx count
 * ecx zero flag -- if true zero destination on error
 *
 * Output:              
 * eax uncopied bytes or 0 if successful.
 */
ENTRY(copy_user_generic_unrolled)
        CFI_STARTPROC
        pushq %rbx
        CFI_ADJUST_CFA_OFFSET 8
        CFI_REL_OFFSET rbx, 0
        pushq %rcx
        CFI_ADJUST_CFA_OFFSET 8
        CFI_REL_OFFSET rcx, 0
        xorl %eax,%eax          /*zero for the exception handler */

#ifdef FIX_ALIGNMENT
        /* check for bad alignment of destination */
        movl %edi,%ecx
        andl $7,%ecx
        jnz  .Lbad_alignment
.Lafter_bad_alignment:
#endif

        movq %rdx,%rcx

        movl $64,%ebx
        shrq $6,%rdx
        decq %rdx
        js   .Lhandle_tail

        .p2align 4
.Lloop:
.Ls1:   movq (%rsi),%r11
.Ls2:   movq 1*8(%rsi),%r8
.Ls3:   movq 2*8(%rsi),%r9
.Ls4:   movq 3*8(%rsi),%r10
.Ld1:   movq %r11,(%rdi)
.Ld2:   movq %r8,1*8(%rdi)
.Ld3:   movq %r9,2*8(%rdi)
.Ld4:   movq %r10,3*8(%rdi)

.Ls5:   movq 4*8(%rsi),%r11
.Ls6:   movq 5*8(%rsi),%r8
.Ls7:   movq 6*8(%rsi),%r9
.Ls8:   movq 7*8(%rsi),%r10
.Ld5:   movq %r11,4*8(%rdi)
.Ld6:   movq %r8,5*8(%rdi)
.Ld7:   movq %r9,6*8(%rdi)
.Ld8:   movq %r10,7*8(%rdi)

        decq %rdx

        leaq 64(%rsi),%rsi
        leaq 64(%rdi),%rdi

        jns  .Lloop

        .p2align 4
.Lhandle_tail:
        movl %ecx,%edx
        andl $63,%ecx
        shrl $3,%ecx
        jz   .Lhandle_7
        movl $8,%ebx
        .p2align 4
.Lloop_8:
.Ls9:   movq (%rsi),%r8
.Ld9:   movq %r8,(%rdi)
        decl %ecx
        leaq 8(%rdi),%rdi
        leaq 8(%rsi),%rsi
        jnz .Lloop_8

.Lhandle_7:
        movl %edx,%ecx
        andl $7,%ecx
        jz   .Lende
        .p2align 4
.Lloop_1:
.Ls10:  movb (%rsi),%bl
.Ld10:  movb %bl,(%rdi)
        incq %rdi
        incq %rsi
        decl %ecx
        jnz .Lloop_1

        CFI_REMEMBER_STATE
.Lende:
        popq %rcx
        CFI_ADJUST_CFA_OFFSET -8
        CFI_RESTORE rcx
        popq %rbx
        CFI_ADJUST_CFA_OFFSET -8
        CFI_RESTORE rbx
        ret
        CFI_RESTORE_STATE

#ifdef FIX_ALIGNMENT
        /* align destination */
        .p2align 4
.Lbad_alignment:
        movl $8,%r9d
        subl %ecx,%r9d
        movl %r9d,%ecx
        cmpq %r9,%rdx
        jz   .Lhandle_7
        js   .Lhandle_7
.Lalign_1:
.Ls11:  movb (%rsi),%bl
.Ld11:  movb %bl,(%rdi)
        incq %rsi
        incq %rdi
        decl %ecx
        jnz .Lalign_1
        subq %r9,%rdx
        jmp .Lafter_bad_alignment
#endif

        /* table sorted by exception address */
        .section __ex_table,"a"
        .align 8
        .quad .Ls1,.Ls1e
        .quad .Ls2,.Ls2e
        .quad .Ls3,.Ls3e
        .quad .Ls4,.Ls4e
        .quad .Ld1,.Ls1e
        .quad .Ld2,.Ls2e
        .quad .Ld3,.Ls3e
        .quad .Ld4,.Ls4e
        .quad .Ls5,.Ls5e
        .quad .Ls6,.Ls6e
        .quad .Ls7,.Ls7e
        .quad .Ls8,.Ls8e
        .quad .Ld5,.Ls5e
        .quad .Ld6,.Ls6e
        .quad .Ld7,.Ls7e
        .quad .Ld8,.Ls8e
        .quad .Ls9,.Le_quad
        .quad .Ld9,.Le_quad
        .quad .Ls10,.Le_byte
        .quad .Ld10,.Le_byte
#ifdef FIX_ALIGNMENT
        .quad .Ls11,.Lzero_rest
        .quad .Ld11,.Lzero_rest
#endif
        .quad .Le5,.Le_zero
        .previous

        /* compute 64-offset for main loop. 8 bytes accuracy with error on the
           pessimistic side. this is gross. it would be better to fix the
           interface. */
        /* eax: zero, ebx: 64 */
.Ls1e:  addl $8,%eax
.Ls2e:  addl $8,%eax
.Ls3e:  addl $8,%eax
.Ls4e:  addl $8,%eax
.Ls5e:  addl $8,%eax
.Ls6e:  addl $8,%eax
.Ls7e:  addl $8,%eax
.Ls8e:  addl $8,%eax
        addq %rbx,%rdi  /* +64 */
        subq %rax,%rdi  /* correct destination with computed offset */

        shlq $6,%rdx    /* loop counter * 64 (stride length) */
        addq %rax,%rdx  /* add offset to loopcnt */
        andl $63,%ecx   /* remaining bytes */
        addq %rcx,%rdx  /* add them */
        jmp .Lzero_rest

        /* exception on quad word loop in tail handling */
        /* ecx: loopcnt/8, %edx: length, rdi: correct */
.Le_quad:
        shll $3,%ecx
        andl $7,%edx
        addl %ecx,%edx
        /* edx: bytes to zero, rdi: dest, eax:zero */
.Lzero_rest:
        cmpl $0,(%rsp)
        jz   .Le_zero
        movq %rdx,%rcx
.Le_byte:
        xorl %eax,%eax
.Le5:   rep
        stosb
        /* when there is another exception while zeroing the rest just return */
.Le_zero:
        movq %rdx,%rax
        jmp .Lende
        CFI_ENDPROC
ENDPROC(copy_user_generic)


        /* Some CPUs run faster using the string copy instructions.
           This is also a lot simpler. Use them when possible.
           Patch in jmps to this code instead of copying it fully
           to avoid unwanted aliasing in the exception tables. */

 /* rdi destination
  * rsi source
  * rdx count
  * ecx zero flag
  *
  * Output:
  * eax uncopied bytes or 0 if successfull.
  *
  * Only 4GB of copy is supported. This shouldn't be a problem
  * because the kernel normally only writes from/to page sized chunks
  * even if user space passed a longer buffer.
  * And more would be dangerous because both Intel and AMD have
  * errata with rep movsq > 4GB. If someone feels the need to fix
  * this please consider this.
  */
ENTRY(copy_user_generic_string)
        CFI_STARTPROC
        movl %ecx,%r8d          /* save zero flag */
        movl %edx,%ecx
        shrl $3,%ecx
        andl $7,%edx    
        jz   10f
1:      rep 
        movsq 
        movl %edx,%ecx
2:      rep
        movsb
9:      movl %ecx,%eax
        ret

        /* multiple of 8 byte */
10:     rep
        movsq
        xor %eax,%eax
        ret

        /* exception handling */
3:      lea (%rdx,%rcx,8),%rax  /* exception on quad loop */
        jmp 6f
5:      movl %ecx,%eax          /* exception on byte loop */
        /* eax: left over bytes */
6:      testl %r8d,%r8d         /* zero flag set? */
        jz 7f
        movl %eax,%ecx          /* initialize x86 loop counter */
        push %rax
        xorl %eax,%eax
8:      rep
        stosb                   /* zero the rest */
11:     pop %rax
7:      ret
        CFI_ENDPROC
END(copy_user_generic_c)

        .section __ex_table,"a"
        .quad 1b,3b
        .quad 2b,5b
        .quad 8b,11b
        .quad 10b,3b
        .previous

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.