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