15d8544e2SPalmer Dabbelt#include <linux/linkage.h> 24d47ce15SLuc Van Oostenryck#include <asm-generic/export.h> 35d8544e2SPalmer Dabbelt#include <asm/asm.h> 46dd10d91SJisheng Zhang#include <asm/asm-extable.h> 55d8544e2SPalmer Dabbelt#include <asm/csr.h> 65d8544e2SPalmer Dabbelt 75d8544e2SPalmer Dabbelt .macro fixup op reg addr lbl 8abc71bf0SPalmer Dabbelt100: 95d8544e2SPalmer Dabbelt \op \reg, \addr 106dd10d91SJisheng Zhang _asm_extable 100b, \lbl 115d8544e2SPalmer Dabbelt .endm 125d8544e2SPalmer Dabbelt 1386406d51SLuc Van OostenryckENTRY(__asm_copy_to_user) 1486406d51SLuc Van OostenryckENTRY(__asm_copy_from_user) 155d8544e2SPalmer Dabbelt 165d8544e2SPalmer Dabbelt /* Enable access to user memory */ 175d8544e2SPalmer Dabbelt li t6, SR_SUM 18a4c3733dSChristoph Hellwig csrs CSR_STATUS, t6 195d8544e2SPalmer Dabbelt 20*4b05b993SAlexandre Ghiti /* 21*4b05b993SAlexandre Ghiti * Save the terminal address which will be used to compute the number 22*4b05b993SAlexandre Ghiti * of bytes copied in case of a fixup exception. 23*4b05b993SAlexandre Ghiti */ 24*4b05b993SAlexandre Ghiti add t5, a0, a2 255d8544e2SPalmer Dabbelt 265d8544e2SPalmer Dabbelt /* 27ca6eaaa2SAkira Tsukamoto * Register allocation for code below: 28ca6eaaa2SAkira Tsukamoto * a0 - start of uncopied dst 29ca6eaaa2SAkira Tsukamoto * a1 - start of uncopied src 30ca6eaaa2SAkira Tsukamoto * a2 - size 31ca6eaaa2SAkira Tsukamoto * t0 - end of uncopied dst 325d8544e2SPalmer Dabbelt */ 33ca6eaaa2SAkira Tsukamoto add t0, a0, a2 34ca6eaaa2SAkira Tsukamoto 35ca6eaaa2SAkira Tsukamoto /* 36ca6eaaa2SAkira Tsukamoto * Use byte copy only if too small. 37ea196c54SAkira Tsukamoto * SZREG holds 4 for RV32 and 8 for RV64 38ca6eaaa2SAkira Tsukamoto */ 396010d300SAkira Tsukamoto li a3, 9*SZREG /* size must be larger than size in word_copy */ 40ca6eaaa2SAkira Tsukamoto bltu a2, a3, .Lbyte_copy_tail 41ca6eaaa2SAkira Tsukamoto 42ca6eaaa2SAkira Tsukamoto /* 43ea196c54SAkira Tsukamoto * Copy first bytes until dst is aligned to word boundary. 44ca6eaaa2SAkira Tsukamoto * a0 - start of dst 45ca6eaaa2SAkira Tsukamoto * t1 - start of aligned dst 46ca6eaaa2SAkira Tsukamoto */ 47ca6eaaa2SAkira Tsukamoto addi t1, a0, SZREG-1 48ca6eaaa2SAkira Tsukamoto andi t1, t1, ~(SZREG-1) 49ca6eaaa2SAkira Tsukamoto /* dst is already aligned, skip */ 50ea196c54SAkira Tsukamoto beq a0, t1, .Lskip_align_dst 515d8544e2SPalmer Dabbelt1: 52ca6eaaa2SAkira Tsukamoto /* a5 - one byte for copying data */ 53ca6eaaa2SAkira Tsukamoto fixup lb a5, 0(a1), 10f 54ca6eaaa2SAkira Tsukamoto addi a1, a1, 1 /* src */ 55ca6eaaa2SAkira Tsukamoto fixup sb a5, 0(a0), 10f 56ca6eaaa2SAkira Tsukamoto addi a0, a0, 1 /* dst */ 57ca6eaaa2SAkira Tsukamoto bltu a0, t1, 1b /* t1 - start of aligned dst */ 58ca6eaaa2SAkira Tsukamoto 59ea196c54SAkira Tsukamoto.Lskip_align_dst: 60ca6eaaa2SAkira Tsukamoto /* 61ca6eaaa2SAkira Tsukamoto * Now dst is aligned. 62ca6eaaa2SAkira Tsukamoto * Use shift-copy if src is misaligned. 63ca6eaaa2SAkira Tsukamoto * Use word-copy if both src and dst are aligned because 64ca6eaaa2SAkira Tsukamoto * can not use shift-copy which do not require shifting 65ca6eaaa2SAkira Tsukamoto */ 66ca6eaaa2SAkira Tsukamoto /* a1 - start of src */ 67ca6eaaa2SAkira Tsukamoto andi a3, a1, SZREG-1 68ca6eaaa2SAkira Tsukamoto bnez a3, .Lshift_copy 69ca6eaaa2SAkira Tsukamoto 70ca6eaaa2SAkira Tsukamoto.Lword_copy: 71ca6eaaa2SAkira Tsukamoto /* 72ca6eaaa2SAkira Tsukamoto * Both src and dst are aligned, unrolled word copy 73ca6eaaa2SAkira Tsukamoto * 74ca6eaaa2SAkira Tsukamoto * a0 - start of aligned dst 75ca6eaaa2SAkira Tsukamoto * a1 - start of aligned src 76ca6eaaa2SAkira Tsukamoto * t0 - end of aligned dst 77ca6eaaa2SAkira Tsukamoto */ 786010d300SAkira Tsukamoto addi t0, t0, -(8*SZREG) /* not to over run */ 795d8544e2SPalmer Dabbelt2: 80ca6eaaa2SAkira Tsukamoto fixup REG_L a4, 0(a1), 10f 81ca6eaaa2SAkira Tsukamoto fixup REG_L a5, SZREG(a1), 10f 82ca6eaaa2SAkira Tsukamoto fixup REG_L a6, 2*SZREG(a1), 10f 83ca6eaaa2SAkira Tsukamoto fixup REG_L a7, 3*SZREG(a1), 10f 84ca6eaaa2SAkira Tsukamoto fixup REG_L t1, 4*SZREG(a1), 10f 85ca6eaaa2SAkira Tsukamoto fixup REG_L t2, 5*SZREG(a1), 10f 86ca6eaaa2SAkira Tsukamoto fixup REG_L t3, 6*SZREG(a1), 10f 87ca6eaaa2SAkira Tsukamoto fixup REG_L t4, 7*SZREG(a1), 10f 88ca6eaaa2SAkira Tsukamoto fixup REG_S a4, 0(a0), 10f 89ca6eaaa2SAkira Tsukamoto fixup REG_S a5, SZREG(a0), 10f 90ca6eaaa2SAkira Tsukamoto fixup REG_S a6, 2*SZREG(a0), 10f 91ca6eaaa2SAkira Tsukamoto fixup REG_S a7, 3*SZREG(a0), 10f 92ca6eaaa2SAkira Tsukamoto fixup REG_S t1, 4*SZREG(a0), 10f 93ca6eaaa2SAkira Tsukamoto fixup REG_S t2, 5*SZREG(a0), 10f 94ca6eaaa2SAkira Tsukamoto fixup REG_S t3, 6*SZREG(a0), 10f 95ca6eaaa2SAkira Tsukamoto fixup REG_S t4, 7*SZREG(a0), 10f 96ca6eaaa2SAkira Tsukamoto addi a0, a0, 8*SZREG 97ca6eaaa2SAkira Tsukamoto addi a1, a1, 8*SZREG 98ca6eaaa2SAkira Tsukamoto bltu a0, t0, 2b 99ca6eaaa2SAkira Tsukamoto 1006010d300SAkira Tsukamoto addi t0, t0, 8*SZREG /* revert to original value */ 101ca6eaaa2SAkira Tsukamoto j .Lbyte_copy_tail 102ca6eaaa2SAkira Tsukamoto 103ca6eaaa2SAkira Tsukamoto.Lshift_copy: 104ca6eaaa2SAkira Tsukamoto 105ca6eaaa2SAkira Tsukamoto /* 106ca6eaaa2SAkira Tsukamoto * Word copy with shifting. 107ca6eaaa2SAkira Tsukamoto * For misaligned copy we still perform aligned word copy, but 108ca6eaaa2SAkira Tsukamoto * we need to use the value fetched from the previous iteration and 109ca6eaaa2SAkira Tsukamoto * do some shifts. 110ea196c54SAkira Tsukamoto * This is safe because reading is less than a word size. 111ca6eaaa2SAkira Tsukamoto * 112ca6eaaa2SAkira Tsukamoto * a0 - start of aligned dst 113ca6eaaa2SAkira Tsukamoto * a1 - start of src 114ca6eaaa2SAkira Tsukamoto * a3 - a1 & mask:(SZREG-1) 115ca6eaaa2SAkira Tsukamoto * t0 - end of uncopied dst 116ca6eaaa2SAkira Tsukamoto * t1 - end of aligned dst 117ca6eaaa2SAkira Tsukamoto */ 118ca6eaaa2SAkira Tsukamoto /* calculating aligned word boundary for dst */ 119ca6eaaa2SAkira Tsukamoto andi t1, t0, ~(SZREG-1) 120ea196c54SAkira Tsukamoto /* Converting unaligned src to aligned src */ 121ca6eaaa2SAkira Tsukamoto andi a1, a1, ~(SZREG-1) 122ca6eaaa2SAkira Tsukamoto 123ca6eaaa2SAkira Tsukamoto /* 124ca6eaaa2SAkira Tsukamoto * Calculate shifts 125ca6eaaa2SAkira Tsukamoto * t3 - prev shift 126ca6eaaa2SAkira Tsukamoto * t4 - current shift 127ca6eaaa2SAkira Tsukamoto */ 12822b5f16fSAkira Tsukamoto slli t3, a3, 3 /* converting bytes in a3 to bits */ 129ca6eaaa2SAkira Tsukamoto li a5, SZREG*8 130ca6eaaa2SAkira Tsukamoto sub t4, a5, t3 131ca6eaaa2SAkira Tsukamoto 132ea196c54SAkira Tsukamoto /* Load the first word to combine with second word */ 133ca6eaaa2SAkira Tsukamoto fixup REG_L a5, 0(a1), 10f 1345d8544e2SPalmer Dabbelt 1355d8544e2SPalmer Dabbelt3: 136ca6eaaa2SAkira Tsukamoto /* Main shifting copy 137ca6eaaa2SAkira Tsukamoto * 138ca6eaaa2SAkira Tsukamoto * a0 - start of aligned dst 139ca6eaaa2SAkira Tsukamoto * a1 - start of aligned src 140ca6eaaa2SAkira Tsukamoto * t1 - end of aligned dst 141ca6eaaa2SAkira Tsukamoto */ 142ca6eaaa2SAkira Tsukamoto 143ca6eaaa2SAkira Tsukamoto /* At least one iteration will be executed */ 144ca6eaaa2SAkira Tsukamoto srl a4, a5, t3 145ca6eaaa2SAkira Tsukamoto fixup REG_L a5, SZREG(a1), 10f 146ca6eaaa2SAkira Tsukamoto addi a1, a1, SZREG 147ca6eaaa2SAkira Tsukamoto sll a2, a5, t4 148ca6eaaa2SAkira Tsukamoto or a2, a2, a4 149ca6eaaa2SAkira Tsukamoto fixup REG_S a2, 0(a0), 10f 150ca6eaaa2SAkira Tsukamoto addi a0, a0, SZREG 151ca6eaaa2SAkira Tsukamoto bltu a0, t1, 3b 152ca6eaaa2SAkira Tsukamoto 153ca6eaaa2SAkira Tsukamoto /* Revert src to original unaligned value */ 154ca6eaaa2SAkira Tsukamoto add a1, a1, a3 155ca6eaaa2SAkira Tsukamoto 156ca6eaaa2SAkira Tsukamoto.Lbyte_copy_tail: 157ca6eaaa2SAkira Tsukamoto /* 158ca6eaaa2SAkira Tsukamoto * Byte copy anything left. 159ca6eaaa2SAkira Tsukamoto * 160ca6eaaa2SAkira Tsukamoto * a0 - start of remaining dst 161ca6eaaa2SAkira Tsukamoto * a1 - start of remaining src 162ca6eaaa2SAkira Tsukamoto * t0 - end of remaining dst 163ca6eaaa2SAkira Tsukamoto */ 164ea196c54SAkira Tsukamoto bgeu a0, t0, .Lout_copy_user /* check if end of copy */ 165ca6eaaa2SAkira Tsukamoto4: 166ca6eaaa2SAkira Tsukamoto fixup lb a5, 0(a1), 10f 167ca6eaaa2SAkira Tsukamoto addi a1, a1, 1 /* src */ 168ca6eaaa2SAkira Tsukamoto fixup sb a5, 0(a0), 10f 169ca6eaaa2SAkira Tsukamoto addi a0, a0, 1 /* dst */ 170ca6eaaa2SAkira Tsukamoto bltu a0, t0, 4b /* t0 - end of dst */ 171ca6eaaa2SAkira Tsukamoto 172ea196c54SAkira Tsukamoto.Lout_copy_user: 1735d8544e2SPalmer Dabbelt /* Disable access to user memory */ 174a4c3733dSChristoph Hellwig csrc CSR_STATUS, t6 1755d8544e2SPalmer Dabbelt li a0, 0 1765d8544e2SPalmer Dabbelt ret 1779d504f9aSJisheng Zhang 1789d504f9aSJisheng Zhang /* Exception fixup code */ 1799d504f9aSJisheng Zhang10: 1809d504f9aSJisheng Zhang /* Disable access to user memory */ 181c08b4848SChen Lifu csrc CSR_STATUS, t6 182*4b05b993SAlexandre Ghiti sub a0, t5, a0 1839d504f9aSJisheng Zhang ret 18486406d51SLuc Van OostenryckENDPROC(__asm_copy_to_user) 18586406d51SLuc Van OostenryckENDPROC(__asm_copy_from_user) 1864d47ce15SLuc Van OostenryckEXPORT_SYMBOL(__asm_copy_to_user) 1874d47ce15SLuc Van OostenryckEXPORT_SYMBOL(__asm_copy_from_user) 1885d8544e2SPalmer Dabbelt 1895d8544e2SPalmer Dabbelt 1905d8544e2SPalmer DabbeltENTRY(__clear_user) 1915d8544e2SPalmer Dabbelt 1925d8544e2SPalmer Dabbelt /* Enable access to user memory */ 1935d8544e2SPalmer Dabbelt li t6, SR_SUM 194a4c3733dSChristoph Hellwig csrs CSR_STATUS, t6 1955d8544e2SPalmer Dabbelt 1965d8544e2SPalmer Dabbelt add a3, a0, a1 1975d8544e2SPalmer Dabbelt addi t0, a0, SZREG-1 1985d8544e2SPalmer Dabbelt andi t1, a3, ~(SZREG-1) 1995d8544e2SPalmer Dabbelt andi t0, t0, ~(SZREG-1) 2005d8544e2SPalmer Dabbelt /* 2015d8544e2SPalmer Dabbelt * a3: terminal address of target region 2025d8544e2SPalmer Dabbelt * t0: lowest doubleword-aligned address in target region 2035d8544e2SPalmer Dabbelt * t1: highest doubleword-aligned address in target region 2045d8544e2SPalmer Dabbelt */ 2055d8544e2SPalmer Dabbelt bgeu t0, t1, 2f 2065d8544e2SPalmer Dabbelt bltu a0, t0, 4f 2075d8544e2SPalmer Dabbelt1: 208ebcbd75eSAlan Kao fixup REG_S, zero, (a0), 11f 2095d8544e2SPalmer Dabbelt addi a0, a0, SZREG 2105d8544e2SPalmer Dabbelt bltu a0, t1, 1b 2115d8544e2SPalmer Dabbelt2: 2125d8544e2SPalmer Dabbelt bltu a0, a3, 5f 2135d8544e2SPalmer Dabbelt 2145d8544e2SPalmer Dabbelt3: 2155d8544e2SPalmer Dabbelt /* Disable access to user memory */ 216a4c3733dSChristoph Hellwig csrc CSR_STATUS, t6 2175d8544e2SPalmer Dabbelt li a0, 0 2185d8544e2SPalmer Dabbelt ret 2195d8544e2SPalmer Dabbelt4: /* Edge case: unalignment */ 220ebcbd75eSAlan Kao fixup sb, zero, (a0), 11f 2215d8544e2SPalmer Dabbelt addi a0, a0, 1 2225d8544e2SPalmer Dabbelt bltu a0, t0, 4b 2235d8544e2SPalmer Dabbelt j 1b 2245d8544e2SPalmer Dabbelt5: /* Edge case: remainder */ 225ebcbd75eSAlan Kao fixup sb, zero, (a0), 11f 2265d8544e2SPalmer Dabbelt addi a0, a0, 1 2275d8544e2SPalmer Dabbelt bltu a0, a3, 5b 2285d8544e2SPalmer Dabbelt j 3b 2295d8544e2SPalmer Dabbelt 2309d504f9aSJisheng Zhang /* Exception fixup code */ 231ebcbd75eSAlan Kao11: 2329d504f9aSJisheng Zhang /* Disable access to user memory */ 233c08b4848SChen Lifu csrc CSR_STATUS, t6 234*4b05b993SAlexandre Ghiti sub a0, a3, a0 2355d8544e2SPalmer Dabbelt ret 2369d504f9aSJisheng ZhangENDPROC(__clear_user) 2379d504f9aSJisheng ZhangEXPORT_SYMBOL(__clear_user) 238