| 1 | /* SPDX-License-Identifier: GPL-2.0-only */
|
| 2 | /*
|
| 3 | * linux/arch/arm/kernel/entry-common.S
|
| 4 | *
|
| 5 | * Copyright (C) 2000 Russell King
|
| 6 | */
|
| 7 |
|
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 |
|
| 17 | .equ NR_syscalls, __NR_syscalls
|
| 18 |
|
| 19 | |
| 20 |
|
| 21 | saved_psr .req r8
|
| 22 | |
| 23 | saved_pc .req r9
|
| 24 | |
| 25 | |
| 26 | saved_pc .req lr
|
| 27 | |
| 28 | |
| 29 |
|
| 30 | .section .entry.text,"ax",%progbits
|
| 31 | .align 5
|
| 32 | |
| 33 | IS_ENABLED(CONFIG_DEBUG_RSEQ))
|
| 34 | /*
|
| 35 | * This is the fast syscall return path. We do as little as possible here,
|
| 36 | * such as avoiding writing r0 to the stack. We only use this path if we
|
| 37 | * have tracing, context tracking and rseq debug disabled - the overheads
|
| 38 | * from those features make this path too inefficient.
|
| 39 | */
|
| 40 | ret_fast_syscall:
|
| 41 | __ret_fast_syscall:
|
| 42 | UNWIND(.fnstart )
|
| 43 | UNWIND(.cantunwind )
|
| 44 | disable_irq_notrace @ disable interrupts
|
| 45 | ldr r1, [tsk, |
| 46 | movs r1, r1, lsl |
| 47 | bne fast_work_pending
|
| 48 |
|
| 49 | restore_user_regs fast = 1, offset = S_OFF
|
| 50 | UNWIND(.fnend )
|
| 51 | ENDPROC(ret_fast_syscall)
|
| 52 |
|
| 53 | /* Ok, we need to do extra processing, enter the slow path. */
|
| 54 | fast_work_pending:
|
| 55 | str r0, [sp, |
| 56 | /* fall through to work_pending */
|
| 57 | |
| 58 | /*
|
| 59 | * The "replacement" ret_fast_syscall for when tracing, context tracking,
|
| 60 | * or rseq debug is enabled. As we will need to call out to some C functions,
|
| 61 | * we save r0 first to avoid needing to save registers around each C function
|
| 62 | * call.
|
| 63 | */
|
| 64 | ret_fast_syscall:
|
| 65 | __ret_fast_syscall:
|
| 66 | UNWIND(.fnstart )
|
| 67 | UNWIND(.cantunwind )
|
| 68 | str r0, [sp, |
| 69 | |
| 70 | /* do_rseq_syscall needs interrupts enabled. */
|
| 71 | mov r0, sp @ 'regs'
|
| 72 | bl do_rseq_syscall
|
| 73 | |
| 74 | disable_irq_notrace @ disable interrupts
|
| 75 | ldr r1, [tsk, |
| 76 | movs r1, r1, lsl |
| 77 | beq no_work_pending
|
| 78 | UNWIND(.fnend )
|
| 79 | ENDPROC(ret_fast_syscall)
|
| 80 |
|
| 81 | /* Slower path - fall through to work_pending */
|
| 82 | |
| 83 |
|
| 84 | tst r1, |
| 85 | bne __sys_trace_return_nosave
|
| 86 | slow_work_pending:
|
| 87 | mov r0, sp @ 'regs'
|
| 88 | mov r2, why @ 'syscall'
|
| 89 | bl do_work_pending
|
| 90 | cmp r0, |
| 91 | beq no_work_pending
|
| 92 | movlt scno, |
| 93 | str scno, [tsk, |
| 94 | ldmia sp, {r0 - r6} @ have to reload r0 - r6
|
| 95 | b local_restart @ ... and off we go
|
| 96 | ENDPROC(ret_fast_syscall)
|
| 97 |
|
| 98 | /*
|
| 99 | * "slow" syscall return path. "why" tells us if this was a real syscall.
|
| 100 | * IRQs may be enabled here, so always disable them. Note that we use the
|
| 101 | * "notrace" version to avoid calling into the tracing code unnecessarily.
|
| 102 | * do_work_pending() will update this state if necessary.
|
| 103 | */
|
| 104 | ENTRY(ret_to_user)
|
| 105 | ret_slow_syscall:
|
| 106 | |
| 107 | /* do_rseq_syscall needs interrupts enabled. */
|
| 108 | enable_irq_notrace @ enable interrupts
|
| 109 | mov r0, sp @ 'regs'
|
| 110 | bl do_rseq_syscall
|
| 111 | |
| 112 | disable_irq_notrace @ disable interrupts
|
| 113 | ENTRY(ret_to_user_from_irq)
|
| 114 | ldr r1, [tsk, |
| 115 | movs r1, r1, lsl |
| 116 | bne slow_work_pending
|
| 117 | no_work_pending:
|
| 118 | asm_trace_hardirqs_on save = 0
|
| 119 |
|
| 120 | ct_user_enter save = 0
|
| 121 |
|
| 122 | |
| 123 | bl stackleak_erase_on_task_stack
|
| 124 | |
| 125 | restore_user_regs fast = 0, offset = 0
|
| 126 | ENDPROC(ret_to_user_from_irq)
|
| 127 | ENDPROC(ret_to_user)
|
| 128 |
|
| 129 | /*
|
| 130 | * This is how we return from a fork.
|
| 131 | */
|
| 132 | ENTRY(ret_from_fork)
|
| 133 | bl schedule_tail
|
| 134 | cmp r5, |
| 135 | movne r0, r4
|
| 136 | badrne lr, 1f
|
| 137 | retne r5
|
| 138 | 1: get_thread_info tsk
|
| 139 | b ret_slow_syscall
|
| 140 | ENDPROC(ret_from_fork)
|
| 141 |
|
| 142 | /*=============================================================================
|
| 143 | * SWI handler
|
| 144 | *-----------------------------------------------------------------------------
|
| 145 | */
|
| 146 |
|
| 147 | .align 5
|
| 148 | |
| 149 | ENTRY(vector_bhb_loop8_swi)
|
| 150 | sub sp, sp, |
| 151 | stmia sp, {r0 - r12}
|
| 152 | mov r8, |
| 153 | 1: b 2f
|
| 154 | 2: subs r8, r8, |
| 155 | bne 1b
|
| 156 | dsb nsh
|
| 157 | isb
|
| 158 | b 3f
|
| 159 | ENDPROC(vector_bhb_loop8_swi)
|
| 160 |
|
| 161 | .align 5
|
| 162 | ENTRY(vector_bhb_bpiall_swi)
|
| 163 | sub sp, sp, |
| 164 | stmia sp, {r0 - r12}
|
| 165 | mcr p15, 0, r8, c7, c5, 6 @ BPIALL
|
| 166 | isb
|
| 167 | b 3f
|
| 168 | ENDPROC(vector_bhb_bpiall_swi)
|
| 169 | |
| 170 | .align 5
|
| 171 | ENTRY(vector_swi)
|
| 172 | |
| 173 | v7m_exception_entry
|
| 174 | |
| 175 | sub sp, sp, |
| 176 | stmia sp, {r0 - r12} @ Calling r0 - r12
|
| 177 | 3:
|
| 178 | ARM( add r8, sp, |
| 179 | ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
|
| 180 | THUMB( mov r8, sp )
|
| 181 | THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
|
| 182 | mrs saved_psr, spsr @ called from non-FIQ mode, so ok.
|
| 183 | TRACE( mov saved_pc, lr )
|
| 184 | str saved_pc, [sp, |
| 185 | str saved_psr, [sp, |
| 186 | str r0, [sp, |
| 187 | |
| 188 | reload_current r10, ip
|
| 189 | zero_fp
|
| 190 | alignment_trap r10, ip, cr_alignment
|
| 191 | asm_trace_hardirqs_on save=0
|
| 192 | enable_irq_notrace
|
| 193 | ct_user_exit save=0
|
| 194 |
|
| 195 | /*
|
| 196 | * Get the system call number.
|
| 197 | */
|
| 198 |
|
| 199 | |
| 200 |
|
| 201 | /*
|
| 202 | * If we have CONFIG_OABI_COMPAT then we need to look at the swi
|
| 203 | * value to determine if it is an EABI or an old ABI call.
|
| 204 | */
|
| 205 | |
| 206 | tst saved_psr, |
| 207 | movne r10, |
| 208 | USER( ldreq r10, [saved_pc, |
| 209 | |
| 210 | USER( ldr r10, [saved_pc, |
| 211 | |
| 212 | ARM_BE8(rev r10, r10) @ little endian instruction
|
| 213 |
|
| 214 | |
| 215 |
|
| 216 | /*
|
| 217 | * Pure EABI user space always put syscall number into scno (r7).
|
| 218 | */
|
| 219 | |
| 220 | /* Legacy ABI only, possibly thumb mode. */
|
| 221 | tst saved_psr, |
| 222 | addne scno, r7, |
| 223 | USER( ldreq scno, [saved_pc, |
| 224 |
|
| 225 | |
| 226 | /* Legacy ABI only. */
|
| 227 | USER( ldr scno, [saved_pc, |
| 228 | |
| 229 |
|
| 230 | /* saved_psr and saved_pc are now dead */
|
| 231 |
|
| 232 | uaccess_disable tbl
|
| 233 | get_thread_info tsk
|
| 234 |
|
| 235 | adr tbl, sys_call_table @ load syscall table pointer
|
| 236 |
|
| 237 | |
| 238 | /*
|
| 239 | * If the swi argument is zero, this is an EABI call and we do nothing.
|
| 240 | *
|
| 241 | * If this is an old ABI call, get the syscall number into scno and
|
| 242 | * get the old ABI syscall table address.
|
| 243 | */
|
| 244 | bics r10, r10, |
| 245 | strne r10, [tsk, |
| 246 | streq scno, [tsk, |
| 247 | eorne scno, r10, |
| 248 | ldrne tbl, =sys_oabi_call_table
|
| 249 | |
| 250 | bic scno, scno, |
| 251 | str scno, [tsk, |
| 252 | eor scno, scno, |
| 253 | |
| 254 | str scno, [tsk, |
| 255 | |
| 256 | /*
|
| 257 | * Reload the registers that may have been corrupted on entry to
|
| 258 | * the syscall assembly (by tracing or context tracking.)
|
| 259 | */
|
| 260 | TRACE( ldmia sp, {r0 - r3} )
|
| 261 |
|
| 262 | local_restart:
|
| 263 | ldr r10, [tsk, |
| 264 | stmdb sp!, {r4, r5} @ push fifth and sixth args
|
| 265 |
|
| 266 | tst r10, |
| 267 | bne __sys_trace
|
| 268 |
|
| 269 | invoke_syscall tbl, scno, r10, __ret_fast_syscall
|
| 270 |
|
| 271 | add r1, sp, |
| 272 | 2: cmp scno, |
| 273 | eor r0, scno, |
| 274 | bcs arm_syscall
|
| 275 | mov why, |
| 276 | b sys_ni_syscall @ not private func
|
| 277 |
|
| 278 | |
| 279 | /*
|
| 280 | * We failed to handle a fault trying to access the page
|
| 281 | * containing the swi instruction, but we're not really in a
|
| 282 | * position to return -EFAULT. Instead, return back to the
|
| 283 | * instruction and re-enter the user fault handling path trying
|
| 284 | * to page it in. This will likely result in sending SEGV to the
|
| 285 | * current task.
|
| 286 | */
|
| 287 | 9001:
|
| 288 | sub lr, saved_pc, #4
|
| 289 | str lr, [sp, #S_PC]
|
| 290 | get_thread_info tsk
|
| 291 | b ret_fast_syscall
|
| 292 | #endif
|
| 293 | ENDPROC(vector_swi)
|
| 294 | .ltorg
|
| 295 |
|
| 296 | /*
|
| 297 | * This is the really slow path. We're going to be doing
|
| 298 | * context switches, and waiting for our parent to respond.
|
| 299 | */
|
| 300 | __sys_trace:
|
| 301 | add r0, sp, |
| 302 | bl syscall_trace_enter
|
| 303 | mov scno, r0
|
| 304 | invoke_syscall tbl, scno, r10, __sys_trace_return, reload=1
|
| 305 | cmp scno, |
| 306 | bne 2b
|
| 307 | add sp, sp, |
| 308 |
|
| 309 | __sys_trace_return_nosave:
|
| 310 | enable_irq_notrace
|
| 311 | mov r0, sp
|
| 312 | bl syscall_trace_exit
|
| 313 | b ret_slow_syscall
|
| 314 |
|
| 315 | __sys_trace_return:
|
| 316 | str r0, [sp, |
| 317 | mov r0, sp
|
| 318 | bl syscall_trace_exit
|
| 319 | b ret_slow_syscall
|
| 320 |
|
| 321 | .macro syscall_table_start, sym
|
| 322 | .equ __sys_nr, 0
|
| 323 | .type \sym, |
| 324 | ENTRY(\sym)
|
| 325 | .endm
|
| 326 |
|
| 327 | .macro syscall, nr, func
|
| 328 | .ifgt __sys_nr - \nr
|
| 329 | .error "Duplicated/unorded system call entry"
|
| 330 | .endif
|
| 331 | .rept \nr - __sys_nr
|
| 332 | .long sys_ni_syscall
|
| 333 | .endr
|
| 334 | .long \func
|
| 335 | .equ __sys_nr, \nr + 1
|
| 336 | .endm
|
| 337 |
|
| 338 | .macro syscall_table_end, sym
|
| 339 | .ifgt __sys_nr - __NR_syscalls
|
| 340 | .error "System call table too big"
|
| 341 | .endif
|
| 342 | .rept __NR_syscalls - __sys_nr
|
| 343 | .long sys_ni_syscall
|
| 344 | .endr
|
| 345 | .size \sym, . - \sym
|
| 346 | .endm
|
| 347 |
|
| 348 | |
| 349 | |
| 350 |
|
| 351 | /*
|
| 352 | * This is the syscall table declaration for native ABI syscalls.
|
| 353 | * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall.
|
| 354 | */
|
| 355 | syscall_table_start sys_call_table
|
| 356 | |
| 357 | |
| 358 | |
| 359 | |
| 360 | |
| 361 | syscall_table_end sys_call_table
|
| 362 |
|
| 363 | /*============================================================================
|
| 364 | * Special system call wrappers
|
| 365 | */
|
| 366 | @ r0 = syscall number
|
| 367 | @ r8 = syscall table
|
| 368 | sys_syscall:
|
| 369 | bic scno, r0, |
| 370 | cmp scno, |
| 371 | cmpne scno, |
| 372 | |
| 373 | movhs scno, |
| 374 | csdb
|
| 375 | |
| 376 | stmialo sp, {r5, r6} @ shuffle args
|
| 377 | movlo r0, r1
|
| 378 | movlo r1, r2
|
| 379 | movlo r2, r3
|
| 380 | movlo r3, r4
|
| 381 | ldrlo pc, [tbl, scno, lsl |
| 382 | b sys_ni_syscall
|
| 383 | ENDPROC(sys_syscall)
|
| 384 |
|
| 385 | sys_sigreturn_wrapper:
|
| 386 | add r0, sp, |
| 387 | mov why, |
| 388 | b sys_sigreturn
|
| 389 | ENDPROC(sys_sigreturn_wrapper)
|
| 390 |
|
| 391 | sys_rt_sigreturn_wrapper:
|
| 392 | add r0, sp, |
| 393 | mov why, |
| 394 | b sys_rt_sigreturn
|
| 395 | ENDPROC(sys_rt_sigreturn_wrapper)
|
| 396 |
|
| 397 | sys_statfs64_wrapper:
|
| 398 | teq r1, |
| 399 | moveq r1, |
| 400 | b sys_statfs64
|
| 401 | ENDPROC(sys_statfs64_wrapper)
|
| 402 |
|
| 403 | sys_fstatfs64_wrapper:
|
| 404 | teq r1, |
| 405 | moveq r1, |
| 406 | b sys_fstatfs64
|
| 407 | ENDPROC(sys_fstatfs64_wrapper)
|
| 408 |
|
| 409 | /*
|
| 410 | * Note: off_4k (r5) is always units of 4K. If we can't do the requested
|
| 411 | * offset, we return EINVAL.
|
| 412 | */
|
| 413 | sys_mmap2:
|
| 414 | str r5, [sp, #4]
|
| 415 | b sys_mmap_pgoff
|
| 416 | ENDPROC(sys_mmap2)
|
| 417 |
|
| 418 | #ifdef CONFIG_OABI_COMPAT
|
| 419 |
|
| 420 | /*
|
| 421 | * These are syscalls with argument register differences
|
| 422 | */
|
| 423 |
|
| 424 | sys_oabi_pread64:
|
| 425 | stmia sp, {r3, r4}
|
| 426 | b sys_pread64
|
| 427 | ENDPROC(sys_oabi_pread64)
|
| 428 |
|
| 429 | sys_oabi_pwrite64:
|
| 430 | stmia sp, {r3, r4}
|
| 431 | b sys_pwrite64
|
| 432 | ENDPROC(sys_oabi_pwrite64)
|
| 433 |
|
| 434 | sys_oabi_truncate64:
|
| 435 | mov r3, r2
|
| 436 | mov r2, r1
|
| 437 | b sys_truncate64
|
| 438 | ENDPROC(sys_oabi_truncate64)
|
| 439 |
|
| 440 | sys_oabi_ftruncate64:
|
| 441 | mov r3, r2
|
| 442 | mov r2, r1
|
| 443 | b sys_ftruncate64
|
| 444 | ENDPROC(sys_oabi_ftruncate64)
|
| 445 |
|
| 446 | sys_oabi_readahead:
|
| 447 | str r3, [sp]
|
| 448 | mov r3, r2
|
| 449 | mov r2, r1
|
| 450 | b sys_readahead
|
| 451 | ENDPROC(sys_oabi_readahead)
|
| 452 |
|
| 453 | /*
|
| 454 | * Let's declare a second syscall table for old ABI binaries
|
| 455 | * using the compatibility syscall entries.
|
| 456 | */
|
| 457 | syscall_table_start sys_oabi_call_table
|
| 458 | |
| 459 | |
| 460 | |
| 461 | syscall_table_end sys_oabi_call_table
|
| 462 |
|
| 463 | |
| 464 |
|