ronnie
2022-10-14 1504bb53e29d3d46222c0b3ea994fc494b48e153
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
/*
 *  linux/arch/arm/kernel/entry-common.S
 *
 *  Copyright (C) 2000 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
 
#include <asm/assembler.h>
#include <asm/unistd.h>
#include <asm/ftrace.h>
#include <asm/unwind.h>
#include <asm/memory.h>
 
#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"
 
 
   .align    5
#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING))
/*
 * 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 and context tracking 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
   tst    r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK
   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 or context tracking
 * 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
   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
   tst    r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK
   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:
   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]
   tst    r1, #_TIF_WORK_MASK
   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)
 
/*
 * 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)
 
   .equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
 
/*
 * Ensure that the system call table is equal to __NR_syscalls,
 * which is the value the rest of the system sees
 */
.ifne NR_syscalls - __NR_syscalls
.error "__NR_syscalls is not equal to the size of the syscall table"
.endif
 
#undef CALL
#define CALL(x) .long x
 
/*=============================================================================
 * SWI handler
 *-----------------------------------------------------------------------------
 */
 
   .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
 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    r8, spsr            @ called from non-FIQ mode, so ok.
   str    lr, [sp, #S_PC]            @ Save calling PC
   str    r8, [sp, #S_PSR]        @ Save CPSR
   str    r0, [sp, #S_OLD_R0]        @ Save OLD_R0
#endif
   zero_fp
   alignment_trap r10, ip, __cr_alignment
   enable_irq
   ct_user_exit
   get_thread_info tsk
 
   /*
    * 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    r8, #PSR_T_BIT
   movne    r10, #0                @ no thumb OABI emulation
 USER(    ldreq    r10, [lr, #-4]        )    @ get SWI instruction
#else
 USER(    ldr    r10, [lr, #-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    r8, #PSR_T_BIT            @ this is SPSR from save_user_regs
   addne    scno, r7, #__NR_SYSCALL_BASE    @ put OS number in
 USER(    ldreq    scno, [lr, #-4]        )
 
#else
   /* Legacy ABI only. */
 USER(    ldr    scno, [lr, #-4]        )    @ get SWI instruction
#endif
 
   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
 
local_restart:
   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, lr, #4
   str    lr, [sp, #S_PC]
   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
   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
 
__sys_trace_return_nosave:
   enable_irq_notrace
   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
 
/*
 * This is the syscall table declaration for native ABI syscalls.
 * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall.
 */
#define ABI(native, compat) native
#ifdef CONFIG_AEABI
#define OBSOLETE(syscall) sys_ni_syscall
#else
#define OBSOLETE(syscall) syscall
#endif
 
   .type    sys_call_table, #object
ENTRY(sys_call_table)
#include "calls.S"
#undef ABI
#undef OBSOLETE
 
/*============================================================================
 * 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
       stmloia    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:
#if PAGE_SHIFT > 12
       tst    r5, #PGOFF_MASK
       moveq    r5, r5, lsr #PAGE_SHIFT - 12
       streq    r5, [sp, #4]
       beq    sys_mmap_pgoff
       mov    r0, #-EINVAL
       ret    lr
#else
       str    r5, [sp, #4]
       b    sys_mmap_pgoff
#endif
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.
 */
#define ABI(native, compat) compat
#define OBSOLETE(syscall) syscall
 
   .type    sys_oabi_call_table, #object
ENTRY(sys_oabi_call_table)
#include "calls.S"
#undef ABI
#undef OBSOLETE
 
#endif