Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * arch/alpha/lib/copy_user.S |
| 3 | * |
| 4 | * Copy to/from user space, handling exceptions as we go.. This |
| 5 | * isn't exactly pretty. |
| 6 | * |
| 7 | * This is essentially the same as "memcpy()", but with a few twists. |
| 8 | * Notably, we have to make sure that $0 is always up-to-date and |
| 9 | * contains the right "bytes left to copy" value (and that it is updated |
| 10 | * only _after_ a successful copy). There is also some rather minor |
| 11 | * exception setup stuff.. |
| 12 | * |
| 13 | * NOTE! This is not directly C-callable, because the calling semantics are |
| 14 | * different: |
| 15 | * |
| 16 | * Inputs: |
| 17 | * length in $0 |
| 18 | * destination address in $6 |
| 19 | * source address in $7 |
| 20 | * return address in $28 |
| 21 | * |
| 22 | * Outputs: |
| 23 | * bytes left to copy in $0 |
| 24 | * |
| 25 | * Clobbers: |
| 26 | * $1,$2,$3,$4,$5,$6,$7 |
| 27 | */ |
| 28 | |
Al Viro | 00fc0e0 | 2016-01-11 09:51:29 -0500 | [diff] [blame] | 29 | #include <asm/export.h> |
| 30 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | /* Allow an exception for an insn; exit if we get one. */ |
| 32 | #define EXI(x,y...) \ |
| 33 | 99: x,##y; \ |
| 34 | .section __ex_table,"a"; \ |
| 35 | .long 99b - .; \ |
| 36 | lda $31, $exitin-99b($31); \ |
| 37 | .previous |
| 38 | |
| 39 | #define EXO(x,y...) \ |
| 40 | 99: x,##y; \ |
| 41 | .section __ex_table,"a"; \ |
| 42 | .long 99b - .; \ |
| 43 | lda $31, $exitout-99b($31); \ |
| 44 | .previous |
| 45 | |
| 46 | .set noat |
| 47 | .align 4 |
| 48 | .globl __copy_user |
| 49 | .ent __copy_user |
| 50 | __copy_user: |
| 51 | .prologue 0 |
| 52 | and $6,7,$3 |
| 53 | beq $0,$35 |
| 54 | beq $3,$36 |
| 55 | subq $3,8,$3 |
| 56 | .align 4 |
| 57 | $37: |
| 58 | EXI( ldq_u $1,0($7) ) |
| 59 | EXO( ldq_u $2,0($6) ) |
| 60 | extbl $1,$7,$1 |
| 61 | mskbl $2,$6,$2 |
| 62 | insbl $1,$6,$1 |
| 63 | addq $3,1,$3 |
| 64 | bis $1,$2,$1 |
| 65 | EXO( stq_u $1,0($6) ) |
| 66 | subq $0,1,$0 |
| 67 | addq $6,1,$6 |
| 68 | addq $7,1,$7 |
| 69 | beq $0,$41 |
| 70 | bne $3,$37 |
| 71 | $36: |
| 72 | and $7,7,$1 |
| 73 | bic $0,7,$4 |
| 74 | beq $1,$43 |
| 75 | beq $4,$48 |
| 76 | EXI( ldq_u $3,0($7) ) |
| 77 | .align 4 |
| 78 | $50: |
| 79 | EXI( ldq_u $2,8($7) ) |
| 80 | subq $4,8,$4 |
| 81 | extql $3,$7,$3 |
| 82 | extqh $2,$7,$1 |
| 83 | bis $3,$1,$1 |
| 84 | EXO( stq $1,0($6) ) |
| 85 | addq $7,8,$7 |
| 86 | subq $0,8,$0 |
| 87 | addq $6,8,$6 |
| 88 | bis $2,$2,$3 |
| 89 | bne $4,$50 |
| 90 | $48: |
| 91 | beq $0,$41 |
| 92 | .align 4 |
| 93 | $57: |
| 94 | EXI( ldq_u $1,0($7) ) |
| 95 | EXO( ldq_u $2,0($6) ) |
| 96 | extbl $1,$7,$1 |
| 97 | mskbl $2,$6,$2 |
| 98 | insbl $1,$6,$1 |
| 99 | bis $1,$2,$1 |
| 100 | EXO( stq_u $1,0($6) ) |
| 101 | subq $0,1,$0 |
| 102 | addq $6,1,$6 |
| 103 | addq $7,1,$7 |
| 104 | bne $0,$57 |
| 105 | br $31,$41 |
| 106 | .align 4 |
| 107 | $43: |
| 108 | beq $4,$65 |
| 109 | .align 4 |
| 110 | $66: |
| 111 | EXI( ldq $1,0($7) ) |
| 112 | subq $4,8,$4 |
| 113 | EXO( stq $1,0($6) ) |
| 114 | addq $7,8,$7 |
| 115 | subq $0,8,$0 |
| 116 | addq $6,8,$6 |
| 117 | bne $4,$66 |
| 118 | $65: |
| 119 | beq $0,$41 |
| 120 | EXI( ldq $2,0($7) ) |
| 121 | EXO( ldq $1,0($6) ) |
| 122 | mskql $2,$0,$2 |
| 123 | mskqh $1,$0,$1 |
| 124 | bis $2,$1,$2 |
| 125 | EXO( stq $2,0($6) ) |
| 126 | bis $31,$31,$0 |
| 127 | $41: |
| 128 | $35: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | $exitin: |
Al Viro | 085354f | 2016-09-10 16:21:34 -0400 | [diff] [blame] | 130 | $exitout: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | ret $31,($28),1 |
| 132 | |
| 133 | .end __copy_user |
Al Viro | 00fc0e0 | 2016-01-11 09:51:29 -0500 | [diff] [blame] | 134 | EXPORT_SYMBOL(__copy_user) |