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 */ 27 ENTRY(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 ! 39 1: 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 84 ENTRY(__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 103 1: 104 ! Copy bytes to long word align src 105 EX( mov.b @r5+,r1 ) 106 dt r0 107 add #-1,r6 108 EX( mov.b r1,@r4 ) 109 bf/s 1b 110 add #1,r4 111 112 ! Jump to appropriate routine depending on dest 113 2: 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 142 2: 143 EX_NO_POP( mov.b @r5+,r0 ) 144 dt r6 145 EX_NO_POP( mov.b r0,@r4 ) 146 bf/s 2b 147 add #1,r4 148 149 1: mov #0,r0 ! normal return 150 5000: 151 152 # Exception handler: 153 .section .fixup, "ax" 154 6005: 155 mov.l 8000f,r1 156 mov r3,r0 157 jmp @r1 158 sub r4,r0 159 .align 2 160 8000: .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 183 3: 184 EX( mov.l @r5+,r1 ) 185 dt r0 186 EX( mov.l r1,@r4 ) 187 bf/s 3b 188 add #4,r4 189 190 2: 191 EX( mov.l @r5+,r0 ) 192 EX( mov.l @r5+,r1 ) 193 EX( mov.l @r5+,r2 ) 194 EX( mov.l @r5+,r7 ) 195 EX( mov.l @r5+,r8 ) 196 EX( mov.l @r5+,r9 ) 197 EX( mov.l @r5+,r10 ) 198 EX( mov.l @r5+,r11 ) 199 #ifdef CONFIG_CPU_SH4 200 EX( movca.l r0,@r4 ) 201 #else 202 EX( mov.l r0,@r4 ) 203 #endif 204 add #-32, r6 205 EX( mov.l r1,@(4,r4) ) 206 mov #32, r0 207 EX( mov.l r2,@(8,r4) ) 208 cmp/gt r6, r0 ! r0 (32) > r6 (len) 209 EX( mov.l r7,@(12,r4) ) 210 EX( mov.l r8,@(16,r4) ) 211 EX( mov.l r9,@(20,r4) ) 212 EX( mov.l r10,@(24,r4) ) 213 EX( mov.l r11,@(28,r4) ) 214 bf/s 2b 215 add #32,r4 216 217 1: mov r6, r0 218 shlr2 r0 219 tst r0, r0 220 bt .L_cleanup 221 1: 222 EX( mov.l @r5+,r1 ) 223 dt r0 224 EX( 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 241 2: 242 dt r7 243 #ifdef CONFIG_CPU_LITTLE_ENDIAN 244 EX( mov.l @r5+,r0 ) 245 EX( mov.l @r5+,r1 ) 246 EX( mov.l @r5+,r8 ) 247 EX( mov.l @r5+,r9 ) 248 EX( mov.l @r5+,r10 ) 249 EX( 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 256 EX( mov.l r0,@r4 ) 257 EX( mov.l r1,@(4,r4) ) 258 EX( mov.l r8,@(8,r4) ) 259 EX( mov.l r9,@(12,r4) ) 260 261 EX( mov.l @r5+,r1 ) 262 EX( mov.l @r5+,r8 ) 263 EX( mov.l @r5+,r0 ) 264 xtrct r1,r10 265 xtrct r8,r1 266 xtrct r0,r8 267 shlr16 r0 268 EX( mov.l r10,@(16,r4) ) 269 EX( mov.l r1,@(20,r4) ) 270 EX( mov.l r8,@(24,r4) ) 271 EX( mov.w r0,@(28,r4) ) 272 bf/s 2b 273 add #30,r4 274 #else 275 EX( mov.l @(28,r5),r0 ) 276 EX( mov.l @(24,r5),r8 ) 277 EX( mov.l @(20,r5),r9 ) 278 EX( mov.l @(16,r5),r10 ) 279 EX( mov.w r0,@(30,r4) ) 280 add #-2,r4 281 xtrct r8,r0 282 xtrct r9,r8 283 xtrct r10,r9 284 EX( mov.l r0,@(28,r4) ) 285 EX( mov.l r8,@(24,r4) ) 286 EX( mov.l r9,@(20,r4) ) 287 288 EX( mov.l @(12,r5),r0 ) 289 EX( mov.l @(8,r5),r8 ) 290 xtrct r0,r10 291 EX( mov.l @(4,r5),r9 ) 292 mov.l r10,@(16,r4) 293 EX( mov.l @r5,r10 ) 294 xtrct r8,r0 295 xtrct r9,r8 296 xtrct r10,r9 297 EX( mov.l r0,@(12,r4) ) 298 EX( mov.l r8,@(8,r4) ) 299 swap.w r10,r0 300 EX( mov.l r9,@(4,r4) ) 301 EX( 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 310 1: ! Read longword, write two words per iteration 311 EX( mov.l @r5+,r0 ) 312 dt r2 313 #ifdef CONFIG_CPU_LITTLE_ENDIAN 314 EX( mov.w r0,@r4 ) 315 shlr16 r0 316 EX( mov.w r0,@(2,r4) ) 317 #else 318 EX( mov.w r0,@(2,r4) ) 319 shlr16 r0 320 EX( 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 333 EX( mov.l @r5+,r0 ) 334 dt r2 335 #ifdef CONFIG_CPU_LITTLE_ENDIAN 336 EX( mov.b r0,@r4 ) 337 shlr8 r0 338 add #1,r4 339 EX( mov.w r0,@r4 ) 340 shlr16 r0 341 EX( mov.b r0,@(2,r4) ) 342 bf/s .L_dest01 343 add #3,r4 344 #else 345 EX( mov.b r0,@(3,r4) ) 346 shlr8 r0 347 swap.w r0,r7 348 EX( mov.b r7,@r4 ) 349 add #1,r4 350 EX( 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: 364 EX( mov.b @r5+,r0 ) 365 dt r6 366 EX( 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 373 5000: 374 375 # Exception handler: 376 .section .fixup, "ax" 377 6000: 378 mov.l 8000f,r1 379 mov r3,r0 380 jmp @r1 381 sub r4,r0 382 .align 2 383 8000: .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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.