1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * copy_page, __copy_user_page, __copy_user implementation of SuperH 4 * 5 * Copyright (C) 2001 Niibe Yutaka & Kaz Kojima 6 * Copyright (C) 2002 Toshinobu Sugioka 7 * Copyright (C) 2006 Paul Mundt 8 */ 9#include <linux/linkage.h> 10#include <asm/page.h> 11 12/* 13 * copy_page 14 * @to: P1 address 15 * @from: P1 address 16 * 17 * void copy_page(void *to, void *from) 18 */ 19 20/* 21 * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch 22 * r8 --- from + PAGE_SIZE 23 * r9 --- not used 24 * r10 --- to 25 * r11 --- from 26 */ 27ENTRY(copy_page) 28 mov.l r8,@-r15 29 mov.l r10,@-r15 30 mov.l r11,@-r15 31 mov r4,r10 32 mov r5,r11 33 mov r5,r8 34 mov #(PAGE_SIZE >> 10), r0 35 shll8 r0 36 shll2 r0 37 add r0,r8 38 ! 391: mov.l @r11+,r0 40 mov.l @r11+,r1 41 mov.l @r11+,r2 42 mov.l @r11+,r3 43 mov.l @r11+,r4 44 mov.l @r11+,r5 45 mov.l @r11+,r6 46 mov.l @r11+,r7 47#if defined(CONFIG_CPU_SH4) 48 movca.l r0,@r10 49#else 50 mov.l r0,@r10 51#endif 52 add #32,r10 53 mov.l r7,@-r10 54 mov.l r6,@-r10 55 mov.l r5,@-r10 56 mov.l r4,@-r10 57 mov.l r3,@-r10 58 mov.l r2,@-r10 59 mov.l r1,@-r10 60 cmp/eq r11,r8 61 bf/s 1b 62 add #28,r10 63 ! 64 mov.l @r15+,r11 65 mov.l @r15+,r10 66 mov.l @r15+,r8 67 rts 68 nop 69 70/* 71 * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); 72 * Return the number of bytes NOT copied 73 */ 74#define EX(...) \ 75 9999: __VA_ARGS__ ; \ 76 .section __ex_table, "a"; \ 77 .long 9999b, 6000f ; \ 78 .previous 79#define EX_NO_POP(...) \ 80 9999: __VA_ARGS__ ; \ 81 .section __ex_table, "a"; \ 82 .long 9999b, 6005f ; \ 83 .previous 84ENTRY(__copy_user) 85 ! Check if small number of bytes 86 mov #11,r0 87 mov r4,r3 88 cmp/gt r0,r6 ! r6 (len) > r0 (11) 89 bf/s .L_cleanup_loop_no_pop 90 add r6,r3 ! last destination address 91 92 ! Calculate bytes needed to align to src 93 mov.l r11,@-r15 94 neg r5,r0 95 mov.l r10,@-r15 96 add #4,r0 97 mov.l r9,@-r15 98 and #3,r0 99 mov.l r8,@-r15 100 tst r0,r0 101 bt 2f 102 1031: 104 ! Copy bytes to long word align src 105EX( mov.b @r5+,r1 ) 106 dt r0 107 add #-1,r6 108EX( mov.b r1,@r4 ) 109 bf/s 1b 110 add #1,r4 111 112 ! Jump to appropriate routine depending on dest 1132: mov #3,r1 114 mov r6, r2 115 and r4,r1 116 shlr2 r2 117 shll2 r1 118 mova .L_jump_tbl,r0 119 mov.l @(r0,r1),r1 120 jmp @r1 121 nop 122 123 .align 2 124.L_jump_tbl: 125 .long .L_dest00 126 .long .L_dest01 127 .long .L_dest10 128 .long .L_dest11 129 130/* 131 * Come here if there are less than 12 bytes to copy 132 * 133 * Keep the branch target close, so the bf/s callee doesn't overflow 134 * and result in a more expensive branch being inserted. This is the 135 * fast-path for small copies, the jump via the jump table will hit the 136 * default slow-path cleanup. -PFM. 137 */ 138.L_cleanup_loop_no_pop: 139 tst r6,r6 ! Check explicitly for zero 140 bt 1f 141 1422: 143EX_NO_POP( mov.b @r5+,r0 ) 144 dt r6 145EX_NO_POP( mov.b r0,@r4 ) 146 bf/s 2b 147 add #1,r4 148 1491: mov #0,r0 ! normal return 1505000: 151 152# Exception handler: 153.section .fixup, "ax" 1546005: 155 mov.l 8000f,r1 156 mov r3,r0 157 jmp @r1 158 sub r4,r0 159 .align 2 1608000: .long 5000b 161 162.previous 163 rts 164 nop 165 166! Destination = 00 167 168.L_dest00: 169 ! Skip the large copy for small transfers 170 mov #(32+32-4), r0 171 cmp/gt r6, r0 ! r0 (60) > r6 (len) 172 bt 1f 173 174 ! Align dest to a 32 byte boundary 175 neg r4,r0 176 add #0x20, r0 177 and #0x1f, r0 178 tst r0, r0 179 bt 2f 180 181 sub r0, r6 182 shlr2 r0 1833: 184EX( mov.l @r5+,r1 ) 185 dt r0 186EX( mov.l r1,@r4 ) 187 bf/s 3b 188 add #4,r4 189 1902: 191EX( mov.l @r5+,r0 ) 192EX( mov.l @r5+,r1 ) 193EX( mov.l @r5+,r2 ) 194EX( mov.l @r5+,r7 ) 195EX( mov.l @r5+,r8 ) 196EX( mov.l @r5+,r9 ) 197EX( mov.l @r5+,r10 ) 198EX( mov.l @r5+,r11 ) 199#ifdef CONFIG_CPU_SH4 200EX( movca.l r0,@r4 ) 201#else 202EX( mov.l r0,@r4 ) 203#endif 204 add #-32, r6 205EX( mov.l r1,@(4,r4) ) 206 mov #32, r0 207EX( mov.l r2,@(8,r4) ) 208 cmp/gt r6, r0 ! r0 (32) > r6 (len) 209EX( mov.l r7,@(12,r4) ) 210EX( mov.l r8,@(16,r4) ) 211EX( mov.l r9,@(20,r4) ) 212EX( mov.l r10,@(24,r4) ) 213EX( mov.l r11,@(28,r4) ) 214 bf/s 2b 215 add #32,r4 216 2171: mov r6, r0 218 shlr2 r0 219 tst r0, r0 220 bt .L_cleanup 2211: 222EX( mov.l @r5+,r1 ) 223 dt r0 224EX( mov.l r1,@r4 ) 225 bf/s 1b 226 add #4,r4 227 228 bra .L_cleanup 229 nop 230 231! Destination = 10 232 233.L_dest10: 234 mov r2,r7 235 shlr2 r7 236 shlr r7 237 tst r7,r7 238 mov #7,r0 239 bt/s 1f 240 and r0,r2 2412: 242 dt r7 243#ifdef CONFIG_CPU_LITTLE_ENDIAN 244EX( mov.l @r5+,r0 ) 245EX( mov.l @r5+,r1 ) 246EX( mov.l @r5+,r8 ) 247EX( mov.l @r5+,r9 ) 248EX( mov.l @r5+,r10 ) 249EX( mov.w r0,@r4 ) 250 add #2,r4 251 xtrct r1,r0 252 xtrct r8,r1 253 xtrct r9,r8 254 xtrct r10,r9 255 256EX( mov.l r0,@r4 ) 257EX( mov.l r1,@(4,r4) ) 258EX( mov.l r8,@(8,r4) ) 259EX( mov.l r9,@(12,r4) ) 260 261EX( mov.l @r5+,r1 ) 262EX( mov.l @r5+,r8 ) 263EX( mov.l @r5+,r0 ) 264 xtrct r1,r10 265 xtrct r8,r1 266 xtrct r0,r8 267 shlr16 r0 268EX( mov.l r10,@(16,r4) ) 269EX( mov.l r1,@(20,r4) ) 270EX( mov.l r8,@(24,r4) ) 271EX( mov.w r0,@(28,r4) ) 272 bf/s 2b 273 add #30,r4 274#else 275EX( mov.l @(28,r5),r0 ) 276EX( mov.l @(24,r5),r8 ) 277EX( mov.l @(20,r5),r9 ) 278EX( mov.l @(16,r5),r10 ) 279EX( mov.w r0,@(30,r4) ) 280 add #-2,r4 281 xtrct r8,r0 282 xtrct r9,r8 283 xtrct r10,r9 284EX( mov.l r0,@(28,r4) ) 285EX( mov.l r8,@(24,r4) ) 286EX( mov.l r9,@(20,r4) ) 287 288EX( mov.l @(12,r5),r0 ) 289EX( mov.l @(8,r5),r8 ) 290 xtrct r0,r10 291EX( mov.l @(4,r5),r9 ) 292 mov.l r10,@(16,r4) 293EX( mov.l @r5,r10 ) 294 xtrct r8,r0 295 xtrct r9,r8 296 xtrct r10,r9 297EX( mov.l r0,@(12,r4) ) 298EX( mov.l r8,@(8,r4) ) 299 swap.w r10,r0 300EX( mov.l r9,@(4,r4) ) 301EX( mov.w r0,@(2,r4) ) 302 303 add #32,r5 304 bf/s 2b 305 add #34,r4 306#endif 307 tst r2,r2 308 bt .L_cleanup 309 3101: ! Read longword, write two words per iteration 311EX( mov.l @r5+,r0 ) 312 dt r2 313#ifdef CONFIG_CPU_LITTLE_ENDIAN 314EX( mov.w r0,@r4 ) 315 shlr16 r0 316EX( mov.w r0,@(2,r4) ) 317#else 318EX( mov.w r0,@(2,r4) ) 319 shlr16 r0 320EX( mov.w r0,@r4 ) 321#endif 322 bf/s 1b 323 add #4,r4 324 325 bra .L_cleanup 326 nop 327 328! Destination = 01 or 11 329 330.L_dest01: 331.L_dest11: 332 ! Read longword, write byte, word, byte per iteration 333EX( mov.l @r5+,r0 ) 334 dt r2 335#ifdef CONFIG_CPU_LITTLE_ENDIAN 336EX( mov.b r0,@r4 ) 337 shlr8 r0 338 add #1,r4 339EX( mov.w r0,@r4 ) 340 shlr16 r0 341EX( mov.b r0,@(2,r4) ) 342 bf/s .L_dest01 343 add #3,r4 344#else 345EX( mov.b r0,@(3,r4) ) 346 shlr8 r0 347 swap.w r0,r7 348EX( mov.b r7,@r4 ) 349 add #1,r4 350EX( mov.w r0,@r4 ) 351 bf/s .L_dest01 352 add #3,r4 353#endif 354 355! Cleanup last few bytes 356.L_cleanup: 357 mov r6,r0 358 and #3,r0 359 tst r0,r0 360 bt .L_exit 361 mov r0,r6 362 363.L_cleanup_loop: 364EX( mov.b @r5+,r0 ) 365 dt r6 366EX( mov.b r0,@r4 ) 367 bf/s .L_cleanup_loop 368 add #1,r4 369 370.L_exit: 371 mov #0,r0 ! normal return 372 3735000: 374 375# Exception handler: 376.section .fixup, "ax" 3776000: 378 mov.l 8000f,r1 379 mov r3,r0 380 jmp @r1 381 sub r4,r0 382 .align 2 3838000: .long 5000b 384 385.previous 386 mov.l @r15+,r8 387 mov.l @r15+,r9 388 mov.l @r15+,r10 389 rts 390 mov.l @r15+,r11 391