2019-06-04 11:11:33 +03:00
/* SPDX-License-Identifier: GPL-2.0-only */
2005-04-17 02:20:36 +04:00
/ *
* linux/ a r c h / a r m / k e r n e l / e n t r y - c o m m o n . S
*
* Copyright ( C ) 2 0 0 0 R u s s e l l K i n g
* /
2014-06-30 19:29:12 +04:00
# include < a s m / a s s e m b l e r . h >
2005-04-17 02:20:36 +04:00
# include < a s m / u n i s t d . h >
2008-06-21 22:17:27 +04:00
# include < a s m / f t r a c e . h >
2009-02-16 13:42:09 +03:00
# include < a s m / u n w i n d . h >
2017-09-07 18:30:46 +03:00
# include < a s m / m e m o r y . h >
2016-10-18 21:57:01 +03:00
# ifdef C O N F I G _ A E A B I
# include < a s m / u n i s t d - o a b i . h >
# endif
.equ NR_ s y s c a l l s , _ _ N R _ s y s c a l l s
2005-04-17 02:20:36 +04:00
2012-02-07 19:28:22 +04:00
# ifdef C O N F I G _ N E E D _ R E T _ T O _ U S E R
# include < m a c h / e n t r y - m a c r o . S >
# else
.macro arch_ r e t _ t o _ u s e r , t m p1 , t m p2
.endm
# endif
2005-04-17 02:20:36 +04:00
# include " e n t r y - h e a d e r . S "
2017-03-24 19:15:45 +03:00
saved_ p s r . r e q r8
2017-03-24 19:22:10 +03:00
# if d e f i n e d ( C O N F I G _ T R A C E _ I R Q F L A G S ) | | d e f i n e d ( C O N F I G _ C O N T E X T _ T R A C K I N G )
saved_ p c . r e q r9
# define T R A C E ( x . . . ) x
# else
2017-03-24 19:15:45 +03:00
saved_ p c . r e q l r
2017-03-24 19:22:10 +03:00
# define T R A C E ( x . . . )
# endif
2005-04-17 02:20:36 +04:00
2017-11-25 02:54:22 +03:00
.section .entry .text , " ax" ,% p r o g b i t s
2005-04-17 02:20:36 +04:00
.align 5
2018-06-02 15:43:56 +03:00
# if ! ( I S _ E N A B L E D ( C O N F I G _ T R A C E _ I R Q F L A G S ) | | I S _ E N A B L E D ( C O N F I G _ C O N T E X T _ T R A C K I N G ) | | \
IS_ E N A B L E D ( C O N F I G _ D E B U G _ R S E Q ) )
2005-04-17 02:20:36 +04:00
/ *
2015-08-20 18:13:37 +03:00
* This i s t h e f a s t s y s c a l l r e t u r n p a t h . W e d o a s l i t t l e a s p o s s i b l e h e r e ,
* such a s a v o i d i n g w r i t i n g r0 t o t h e s t a c k . W e o n l y u s e t h i s p a t h i f w e
2018-06-02 15:43:56 +03:00
* have t r a c i n g , c o n t e x t t r a c k i n g a n d r s e q d e b u g d i s a b l e d - t h e o v e r h e a d s
* from t h o s e f e a t u r e s m a k e t h i s p a t h t o o i n e f f i c i e n t .
2005-04-17 02:20:36 +04:00
* /
ret_fast_syscall :
ARM: 8781/1: Fix Thumb-2 syscall return for binutils 2.29+
When building the kernel as Thumb-2 with binutils 2.29 or newer, if the
assembler has seen the .type directive (via ENDPROC()) for a symbol, it
automatically handles the setting of the lowest bit when the symbol is
used with ADR. The badr macro on the other hand handles this lowest bit
manually. This leads to a jump to a wrong address in the wrong state
in the syscall return path:
Internal error: Oops - undefined instruction: 0 [#2] SMP THUMB2
Modules linked in:
CPU: 0 PID: 652 Comm: modprobe Tainted: G D 4.18.0-rc3+ #8
PC is at ret_fast_syscall+0x4/0x62
LR is at sys_brk+0x109/0x128
pc : [<80101004>] lr : [<801c8a35>] psr: 60000013
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
Control: 50c5387d Table: 9e82006a DAC: 00000051
Process modprobe (pid: 652, stack limit = 0x(ptrval))
80101000 <ret_fast_syscall>:
80101000: b672 cpsid i
80101002: f8d9 2008 ldr.w r2, [r9, #8]
80101006: f1b2 4ffe cmp.w r2, #2130706432 ; 0x7f000000
80101184 <local_restart>:
80101184: f8d9 a000 ldr.w sl, [r9]
80101188: e92d 0030 stmdb sp!, {r4, r5}
8010118c: f01a 0ff0 tst.w sl, #240 ; 0xf0
80101190: d117 bne.n 801011c2 <__sys_trace>
80101192: 46ba mov sl, r7
80101194: f5ba 7fc8 cmp.w sl, #400 ; 0x190
80101198: bf28 it cs
8010119a: f04f 0a00 movcs.w sl, #0
8010119e: f3af 8014 nop.w {20}
801011a2: f2af 1ea2 subw lr, pc, #418 ; 0x1a2
To fix this, add a new symbol name which doesn't have ENDPROC used on it
and use that with badr. We can't remove the badr usage since that would
would cause breakage with older binutils.
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
2018-07-13 13:12:22 +03:00
__ret_fast_syscall :
2009-02-16 13:42:09 +03:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
2015-08-20 18:13:37 +03:00
disable_ i r q _ n o t r a c e @ disable interrupts
2017-09-07 18:30:46 +03:00
ldr r2 , [ t s k , #T I _ A D D R _ L I M I T ]
cmp r2 , #T A S K _ S I Z E
blne a d d r _ l i m i t _ c h e c k _ f a i l e d
2015-05-15 13:02:23 +03:00
ldr r1 , [ t s k , #T I _ F L A G S ] @ r e - c h e c k f o r s y s c a l l t r a c i n g
2017-09-07 18:30:45 +03:00
tst r1 , #_ T I F _ S Y S C A L L _ W O R K | _ T I F _ W O R K _ M A S K
2005-04-17 02:20:36 +04:00
bne f a s t _ w o r k _ p e n d i n g
2005-04-26 18:20:34 +04:00
2017-09-07 18:30:46 +03:00
2007-02-17 00:16:32 +03:00
/* perform architecture specific actions before user return */
arch_ r e t _ t o _ u s e r r1 , l r
2009-07-24 15:32:54 +04:00
restore_ u s e r _ r e g s f a s t = 1 , o f f s e t = S _ O F F
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2015-08-20 18:13:37 +03:00
ENDPROC( r e t _ f a s t _ s y s c a l l )
2005-04-17 02:20:36 +04:00
2015-08-20 18:13:37 +03:00
/* Ok, we need to do extra processing, enter the slow path. */
2005-04-17 02:20:36 +04:00
fast_work_pending :
str r0 , [ s p , #S _ R 0 + S _ O F F ] ! @ returned r0
2015-08-20 18:13:37 +03:00
/* fall through to work_pending */
# else
/ *
2018-06-02 15:43:56 +03:00
* The " r e p l a c e m e n t " r e t _ f a s t _ s y s c a l l f o r w h e n t r a c i n g , c o n t e x t t r a c k i n g ,
* or r s e q d e b u g i s e n a b l e d . A s w e w i l l n e e d t o c a l l o u t t o s o m e C f u n c t i o n s ,
* we s a v e r0 f i r s t t o a v o i d n e e d i n g t o s a v e r e g i s t e r s a r o u n d e a c h C f u n c t i o n
* call.
2015-08-20 18:13:37 +03:00
* /
ret_fast_syscall :
ARM: 8781/1: Fix Thumb-2 syscall return for binutils 2.29+
When building the kernel as Thumb-2 with binutils 2.29 or newer, if the
assembler has seen the .type directive (via ENDPROC()) for a symbol, it
automatically handles the setting of the lowest bit when the symbol is
used with ADR. The badr macro on the other hand handles this lowest bit
manually. This leads to a jump to a wrong address in the wrong state
in the syscall return path:
Internal error: Oops - undefined instruction: 0 [#2] SMP THUMB2
Modules linked in:
CPU: 0 PID: 652 Comm: modprobe Tainted: G D 4.18.0-rc3+ #8
PC is at ret_fast_syscall+0x4/0x62
LR is at sys_brk+0x109/0x128
pc : [<80101004>] lr : [<801c8a35>] psr: 60000013
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
Control: 50c5387d Table: 9e82006a DAC: 00000051
Process modprobe (pid: 652, stack limit = 0x(ptrval))
80101000 <ret_fast_syscall>:
80101000: b672 cpsid i
80101002: f8d9 2008 ldr.w r2, [r9, #8]
80101006: f1b2 4ffe cmp.w r2, #2130706432 ; 0x7f000000
80101184 <local_restart>:
80101184: f8d9 a000 ldr.w sl, [r9]
80101188: e92d 0030 stmdb sp!, {r4, r5}
8010118c: f01a 0ff0 tst.w sl, #240 ; 0xf0
80101190: d117 bne.n 801011c2 <__sys_trace>
80101192: 46ba mov sl, r7
80101194: f5ba 7fc8 cmp.w sl, #400 ; 0x190
80101198: bf28 it cs
8010119a: f04f 0a00 movcs.w sl, #0
8010119e: f3af 8014 nop.w {20}
801011a2: f2af 1ea2 subw lr, pc, #418 ; 0x1a2
To fix this, add a new symbol name which doesn't have ENDPROC used on it
and use that with badr. We can't remove the badr usage since that would
would cause breakage with older binutils.
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
2018-07-13 13:12:22 +03:00
__ret_fast_syscall :
2015-08-20 18:13:37 +03:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
str r0 , [ s p , #S _ R 0 + S _ O F F ] ! @ save returned r0
2018-06-02 15:43:56 +03:00
# if I S _ E N A B L E D ( C O N F I G _ D E B U G _ R S E Q )
/* do_rseq_syscall needs interrupts enabled. */
mov r0 , s p @ 'regs'
bl d o _ r s e q _ s y s c a l l
# endif
2015-08-20 18:13:37 +03:00
disable_ i r q _ n o t r a c e @ disable interrupts
2017-09-07 18:30:46 +03:00
ldr r2 , [ t s k , #T I _ A D D R _ L I M I T ]
cmp r2 , #T A S K _ S I Z E
blne a d d r _ l i m i t _ c h e c k _ f a i l e d
2015-08-20 18:13:37 +03:00
ldr r1 , [ t s k , #T I _ F L A G S ] @ r e - c h e c k f o r s y s c a l l t r a c i n g
2017-09-07 18:30:45 +03:00
tst r1 , #_ T I F _ S Y S C A L L _ W O R K | _ T I F _ W O R K _ M A S K
2015-08-20 18:13:37 +03:00
beq n o _ w o r k _ p e n d i n g
UNWIND( . f n e n d )
ENDPROC( r e t _ f a s t _ s y s c a l l )
/* Slower path - fall through to work_pending */
# endif
tst r1 , #_ T I F _ S Y S C A L L _ W O R K
bne _ _ s y s _ t r a c e _ r e t u r n _ n o s a v e
slow_work_pending :
2005-04-17 02:20:36 +04:00
mov r0 , s p @ 'regs'
mov r2 , w h y @ 'syscall'
2012-07-19 20:47:55 +04:00
bl d o _ w o r k _ p e n d i n g
2012-07-19 20:48:50 +04:00
cmp r0 , #0
2012-07-19 20:48:21 +04:00
beq n o _ w o r k _ p e n d i n g
2012-07-19 20:48:50 +04:00
movlt s c n o , #( _ _ N R _ r e s t a r t _ s y s c a l l - _ _ N R _ S Y S C A L L _ B A S E )
2012-07-19 20:48:21 +04:00
ldmia s p , { r0 - r6 } @ have to reload r0 - r6
b l o c a l _ r e s t a r t @ ... and off we go
2015-08-06 20:50:27 +03:00
ENDPROC( r e t _ f a s t _ s y s c a l l )
2012-07-19 20:48:21 +04:00
2005-04-17 02:20:36 +04:00
/ *
* " slow" s y s c a l l r e t u r n p a t h . " w h y " t e l l s u s i f t h i s w a s a r e a l s y s c a l l .
2015-08-20 18:13:37 +03:00
* IRQs m a y b e e n a b l e d h e r e , s o a l w a y s d i s a b l e t h e m . N o t e t h a t w e u s e t h e
* " notrace" v e r s i o n t o a v o i d c a l l i n g i n t o t h e t r a c i n g c o d e u n n e c e s s a r i l y .
* do_ w o r k _ p e n d i n g ( ) w i l l u p d a t e t h i s s t a t e i f n e c e s s a r y .
2005-04-17 02:20:36 +04:00
* /
ENTRY( r e t _ t o _ u s e r )
ret_slow_syscall :
2018-06-02 15:43:56 +03:00
# if I S _ E N A B L E D ( C O N F I G _ D E B U G _ R S E Q )
/* do_rseq_syscall needs interrupts enabled. */
enable_ i r q _ n o t r a c e @ enable interrupts
mov r0 , s p @ 'regs'
bl d o _ r s e q _ s y s c a l l
# endif
2015-08-20 18:13:37 +03:00
disable_ i r q _ n o t r a c e @ disable interrupts
2011-06-05 05:24:58 +04:00
ENTRY( r e t _ t o _ u s e r _ f r o m _ i r q )
2017-09-07 18:30:46 +03:00
ldr r2 , [ t s k , #T I _ A D D R _ L I M I T ]
cmp r2 , #T A S K _ S I Z E
blne a d d r _ l i m i t _ c h e c k _ f a i l e d
2005-04-17 02:20:36 +04:00
ldr r1 , [ t s k , #T I _ F L A G S ]
tst r1 , #_ T I F _ W O R K _ M A S K
2015-08-20 18:13:37 +03:00
bne s l o w _ w o r k _ p e n d i n g
2005-04-17 02:20:36 +04:00
no_work_pending :
2015-08-20 18:13:37 +03:00
asm_ t r a c e _ h a r d i r q s _ o n s a v e = 0
2013-03-28 15:44:25 +04:00
2007-02-17 00:16:32 +03:00
/* perform architecture specific actions before user return */
arch_ r e t _ t o _ u s e r r1 , l r
2013-03-29 01:54:40 +04:00
ct_ u s e r _ e n t e r s a v e = 0
2007-02-17 00:16:32 +03:00
2009-07-24 15:32:54 +04:00
restore_ u s e r _ r e g s f a s t = 0 , o f f s e t = 0
2011-06-05 05:24:58 +04:00
ENDPROC( r e t _ t o _ u s e r _ f r o m _ i r q )
2008-08-28 14:22:32 +04:00
ENDPROC( r e t _ t o _ u s e r )
2005-04-17 02:20:36 +04:00
/ *
* This i s h o w w e r e t u r n f r o m a f o r k .
* /
ENTRY( r e t _ f r o m _ f o r k )
bl s c h e d u l e _ t a i l
2012-10-11 06:23:29 +04:00
cmp r5 , #0
movne r0 , r4
2015-04-21 16:17:25 +03:00
badrne l r , 1 f
2014-06-30 19:29:12 +04:00
retne r5
ARM: fix oops on initial entry to userspace with Thumb2 kernels
Daniel Mack reports an oops at boot with the latest kernels:
Internal error: Oops - undefined instruction: 0 [#1] SMP THUMB2
Modules linked in:
CPU: 0 Not tainted (3.6.0-11057-g584df1d #145)
PC is at cpsw_probe+0x45a/0x9ac
LR is at trace_hardirqs_on_caller+0x8f/0xfc
pc : [<c03493de>] lr : [<c005e81f>] psr: 60000113
sp : cf055fb0 ip : 00000000 fp : 00000000
r10: 00000000 r9 : 00000000 r8 : 00000000
r7 : 00000000 r6 : 00000000 r5 : c0344555 r4 : 00000000
r3 : cf057a40 r2 : 00000000 r1 : 00000001 r0 : 00000000
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 50c5387d Table: 8f3f4019 DAC: 00000015
Process init (pid: 1, stack limit = 0xcf054240)
Stack: (0xcf055fb0 to 0xcf056000)
5fa0: 00000001 00000000 00000000 00000000
5fc0: cf055fb0 c000d1a8 00000000 00000000 00000000 00000000 00000000 00000000
5fe0: 00000000 be9b3f10 00000000 b6f6add0 00000010 00000000 aaaabfaf a8babbaa
The analysis of this is as follows. In init/main.c, we issue:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
This creates a new thread, which falls through to the ret_from_fork
assembly, with r4 set NULL and r5 set to kernel_init. You can see
this in your oops dump register set - r5 is 0xc0344555, which is the
address of kernel_init plus 1 which marks the function as Thumb code.
Now, let's look at this code a little closer - this is what the
disassembly looks like:
c000d180 <ret_from_fork>:
c000d180: f03a fe08 bl c0047d94 <schedule_tail>
c000d184: 2d00 cmp r5, #0
c000d186: bf1e ittt ne
c000d188: 4620 movne r0, r4
c000d18a: 46fe movne lr, pc <-- XXXXXXX
c000d18c: 46af movne pc, r5
c000d18e: 46e9 mov r9, sp
c000d190: ea4f 3959 mov.w r9, r9, lsr #13
c000d194: ea4f 3949 mov.w r9, r9, lsl #13
c000d198: e7c8 b.n c000d12c <ret_to_user>
c000d19a: bf00 nop
c000d19c: f3af 8000 nop.w
This code was introduced in 9fff2fa0db911 (arm: switch to saner
kernel_execve() semantics). I have marked one instruction, and it's
the significant one - I'll come back to that later.
Eventually, having had a successful call to kernel_execve(), kernel_init()
returns zero.
In returning, it uses the value in 'lr' which was set by the instruction
I marked above. Unfortunately, this causes lr to contain 0xc000d18e -
an even address. This switches the ISA to ARM on return but with a non
word aligned PC value.
So, what do we end up executing? Well, not the instructions above - yes
the opcodes, but they don't mean the same thing in ARM mode. In ARM mode,
it looks like this instead:
c000d18c: 46e946af strbtmi r4, [r9], pc, lsr #13
c000d190: 3959ea4f ldmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
c000d194: 3949ea4f stmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
c000d198: bf00e7c8 svclt 0x0000e7c8
c000d19c: 8000f3af andhi pc, r0, pc, lsr #7
c000d1a0: e88db092 stm sp, {r1, r4, r7, ip, sp, pc}
c000d1a4: 46e81fff ; <UNDEFINED> instruction: 0x46e81fff
c000d1a8: 8a00f3ef bhi 0xc004a16c
c000d1ac: 0a0cf08a beq 0xc03493dc
I have included more above, because it's relevant. The PSR flags which
we can see in the oops dump are nZCv, so Z and C are set.
All the above ARM instructions are not executed, except for two.
c000d1a0, which has no writeback, and writes below the current stack
pointer (and that data is lost when we take the next exception.) The
other instruction which is executed is c000d1ac, which takes us to...
0xc03493dc. However, remember that bit 1 of the PC got set. So that
makes the PC value 0xc03493de.
And that value is the value we find in the oops dump for PC. What is
the instruction here when interpreted in ARM mode?
0: f71e150c ; <UNDEFINED> instruction: 0xf71e150c
and there we have our undefined instruction (remember that the 'never'
condition code, 0xf, has been deprecated and is now always executed as
it is now being used for additional instructions.)
This path also nicely explains the state of the stack we see in the oops
dump too.
The above is a consistent and sane story for how we got to the oops
dump, which all stems from the instruction at 0xc000d18a being wrong.
Reported-by: Daniel Mack <zonque@gmail.com>
Tested-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-10-15 03:16:49 +04:00
1 : get_ t h r e a d _ i n f o t s k
2005-04-17 02:20:36 +04:00
b r e t _ s l o w _ s y s c a l l
2008-08-28 14:22:32 +04:00
ENDPROC( r e t _ f r o m _ f o r k )
2005-04-17 02:20:36 +04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* SWI h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
.align 5
ENTRY( v e c t o r _ s w i )
2010-05-21 21:06:42 +04:00
# ifdef C O N F I G _ C P U _ V 7 M
v7 m _ e x c e p t i o n _ e n t r y
# else
2016-05-10 18:34:27 +03:00
sub s p , s p , #P T _ R E G S _ S I Z E
2005-04-26 18:20:34 +04:00
stmia s p , { r0 - r12 } @ Calling r0 - r12
2009-07-24 15:32:54 +04:00
ARM( a d d r8 , s p , #S _ P C )
ARM( s t m d b r8 , { s p , l r } ^ ) @ Calling sp, lr
THUMB( m o v r8 , s p )
THUMB( s t o r e _ u s e r _ s p _ l r r8 , r10 , S _ S P ) @ calling sp, lr
2017-03-24 19:15:45 +03:00
mrs s a v e d _ p s r , s p s r @ called from non-FIQ mode, so ok.
2017-03-24 19:22:10 +03:00
TRACE( m o v s a v e d _ p c , l r )
2017-03-24 19:15:45 +03:00
str s a v e d _ p c , [ s p , #S _ P C ] @ S a v e c a l l i n g P C
str s a v e d _ p s r , [ s p , #S _ P S R ] @ S a v e C P S R
2005-04-26 18:20:34 +04:00
str r0 , [ s p , #S _ O L D _ R 0 ] @ Save OLD_R0
2010-05-21 21:06:42 +04:00
# endif
2005-04-17 02:20:36 +04:00
zero_ f p
2014-08-28 16:08:14 +04:00
alignment_ t r a p r10 , i p , _ _ c r _ a l i g n m e n t
2017-03-24 19:23:25 +03:00
asm_ t r a c e _ h a r d i r q s _ o n s a v e =0
enable_ i r q _ n o t r a c e
ct_ u s e r _ e x i t s a v e =0
2013-06-05 14:25:13 +04:00
2005-04-26 18:19:24 +04:00
/ *
* Get t h e s y s t e m c a l l n u m b e r .
* /
2006-01-14 19:31:29 +03:00
2006-01-14 19:36:12 +03:00
# if d e f i n e d ( C O N F I G _ O A B I _ C O M P A T )
2006-01-14 19:31:29 +03:00
2006-01-14 19:36:12 +03:00
/ *
* If w e h a v e C O N F I G _ O A B I _ C O M P A T t h e n w e n e e d t o l o o k a t t h e s w i
* value t o d e t e r m i n e i f i t i s a n E A B I o r a n o l d A B I c a l l .
* /
# ifdef C O N F I G _ A R M _ T H U M B
2017-03-24 19:15:45 +03:00
tst s a v e d _ p s r , #P S R _ T _ B I T
2006-01-14 19:36:12 +03:00
movne r10 , #0 @ no thumb OABI emulation
2017-03-24 19:15:45 +03:00
USER( l d r e q r10 , [ s a v e d _ p c , #- 4 ] ) @ get SWI instruction
2006-01-14 19:36:12 +03:00
# else
2017-03-24 19:15:45 +03:00
USER( l d r r10 , [ s a v e d _ p c , #- 4 ] ) @ get SWI instruction
2006-01-14 19:36:12 +03:00
# endif
2013-02-12 22:59:57 +04:00
ARM_ B E 8 ( r e v r10 , r10 ) @ little endian instruction
2006-01-14 19:36:12 +03:00
# elif d e f i n e d ( C O N F I G _ A E A B I )
/ *
* Pure E A B I u s e r s p a c e a l w a y s p u t s y s c a l l n u m b e r i n t o s c n o ( r7 ) .
* /
2006-01-14 19:31:29 +03:00
# elif d e f i n e d ( C O N F I G _ A R M _ T H U M B )
2006-01-14 19:36:12 +03:00
/* Legacy ABI only, possibly thumb mode. */
2017-03-24 19:15:45 +03:00
tst s a v e d _ p s r , #P S R _ T _ B I T @ t h i s i s S P S R f r o m s a v e _ u s e r _ r e g s
2005-04-26 18:19:24 +04:00
addne s c n o , r7 , #_ _ N R _ S Y S C A L L _ B A S E @ p u t O S n u m b e r i n
2017-03-24 19:15:45 +03:00
USER( l d r e q s c n o , [ s a v e d _ p c , #- 4 ] )
2006-01-14 19:36:12 +03:00
2005-04-26 18:19:24 +04:00
# else
2006-01-14 19:36:12 +03:00
/* Legacy ABI only. */
2017-03-24 19:15:45 +03:00
USER( l d r s c n o , [ s a v e d _ p c , #- 4 ] ) @ get SWI instruction
2005-04-26 18:19:24 +04:00
# endif
2005-04-17 02:20:36 +04:00
2017-03-24 19:15:45 +03:00
/* saved_psr and saved_pc are now dead */
2015-08-20 12:32:02 +03:00
uaccess_ d i s a b l e t b l
2006-01-14 19:36:12 +03:00
adr t b l , s y s _ c a l l _ t a b l e @ load syscall table pointer
# if d e f i n e d ( C O N F I G _ O A B I _ C O M P A T )
/ *
* If t h e s w i a r g u m e n t i s z e r o , t h i s i s a n E A B I c a l l a n d w e d o n o t h i n g .
*
* If t h i s i s a n o l d A B I c a l l , g e t t h e s y s c a l l n u m b e r i n t o s c n o a n d
* get t h e o l d A B I s y s c a l l t a b l e a d d r e s s .
* /
bics r10 , r10 , #0xff000000
eorne s c n o , r10 , #_ _ N R _ O A B I _ S Y S C A L L _ B A S E
ldrne t b l , =sys_oabi_call_table
# elif ! d e f i n e d ( C O N F I G _ A E A B I )
2005-04-17 02:20:36 +04:00
bic s c n o , s c n o , #0xff000000 @ mask off SWI op-code
2005-04-26 18:19:24 +04:00
eor s c n o , s c n o , #_ _ N R _ S Y S C A L L _ B A S E @ c h e c k O S n u m b e r
2006-01-14 19:31:29 +03:00
# endif
2017-03-24 19:19:12 +03:00
get_ t h r e a d _ i n f o t s k
2017-03-24 19:23:25 +03:00
/ *
* Reload t h e r e g i s t e r s t h a t m a y h a v e b e e n c o r r u p t e d o n e n t r y t o
* the s y s c a l l a s s e m b l y ( b y t r a c i n g o r c o n t e x t t r a c k i n g . )
* /
TRACE( l d m i a s p , { r0 - r3 } )
2006-01-14 19:36:12 +03:00
2012-07-19 20:48:21 +04:00
local_restart :
2010-08-27 02:08:35 +04:00
ldr r10 , [ t s k , #T I _ F L A G S ] @ c h e c k f o r s y s c a l l t r a c i n g
2006-01-14 19:31:29 +03:00
stmdb s p ! , { r4 , r5 } @ push fifth and sixth args
2010-08-27 02:08:35 +04:00
2012-01-03 23:23:09 +04:00
tst r10 , #_ T I F _ S Y S C A L L _ W O R K @ a r e w e t r a c i n g s y s c a l l s ?
2005-04-17 02:20:36 +04:00
bne _ _ s y s _ t r a c e
ARM: 8781/1: Fix Thumb-2 syscall return for binutils 2.29+
When building the kernel as Thumb-2 with binutils 2.29 or newer, if the
assembler has seen the .type directive (via ENDPROC()) for a symbol, it
automatically handles the setting of the lowest bit when the symbol is
used with ADR. The badr macro on the other hand handles this lowest bit
manually. This leads to a jump to a wrong address in the wrong state
in the syscall return path:
Internal error: Oops - undefined instruction: 0 [#2] SMP THUMB2
Modules linked in:
CPU: 0 PID: 652 Comm: modprobe Tainted: G D 4.18.0-rc3+ #8
PC is at ret_fast_syscall+0x4/0x62
LR is at sys_brk+0x109/0x128
pc : [<80101004>] lr : [<801c8a35>] psr: 60000013
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
Control: 50c5387d Table: 9e82006a DAC: 00000051
Process modprobe (pid: 652, stack limit = 0x(ptrval))
80101000 <ret_fast_syscall>:
80101000: b672 cpsid i
80101002: f8d9 2008 ldr.w r2, [r9, #8]
80101006: f1b2 4ffe cmp.w r2, #2130706432 ; 0x7f000000
80101184 <local_restart>:
80101184: f8d9 a000 ldr.w sl, [r9]
80101188: e92d 0030 stmdb sp!, {r4, r5}
8010118c: f01a 0ff0 tst.w sl, #240 ; 0xf0
80101190: d117 bne.n 801011c2 <__sys_trace>
80101192: 46ba mov sl, r7
80101194: f5ba 7fc8 cmp.w sl, #400 ; 0x190
80101198: bf28 it cs
8010119a: f04f 0a00 movcs.w sl, #0
8010119e: f3af 8014 nop.w {20}
801011a2: f2af 1ea2 subw lr, pc, #418 ; 0x1a2
To fix this, add a new symbol name which doesn't have ENDPROC used on it
and use that with badr. We can't remove the badr usage since that would
would cause breakage with older binutils.
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
2018-07-13 13:12:22 +03:00
invoke_ s y s c a l l t b l , s c n o , r10 , _ _ r e t _ f a s t _ s y s c a l l
2005-04-17 02:20:36 +04:00
add r1 , s p , #S _ O F F
2013-09-19 13:32:20 +04:00
2 : cmp s c n o , #( _ _ A R M _ N R _ B A S E - _ _ N R _ S Y S C A L L _ B A S E )
2005-04-26 18:19:24 +04:00
eor r0 , s c n o , #_ _ N R _ S Y S C A L L _ B A S E @ p u t O S n u m b e r b a c k
2013-05-13 22:16:34 +04:00
bcs a r m _ s y s c a l l
2013-09-19 13:32:20 +04:00
mov w h y , #0 @ no longer a real syscall
2005-04-17 02:20:36 +04:00
b s y s _ n i _ s y s c a l l @ not private func
2013-06-05 14:25:13 +04:00
# if d e f i n e d ( C O N F I G _ O A B I _ C O M P A T ) | | ! d e f i n e d ( C O N F I G _ A E A B I )
/ *
* We f a i l e d t o h a n d l e a f a u l t t r y i n g t o a c c e s s t h e p a g e
* containing t h e s w i i n s t r u c t i o n , b u t w e ' r e n o t r e a l l y i n a
* position t o r e t u r n - E F A U L T . I n s t e a d , r e t u r n b a c k t o t h e
* instruction a n d r e - e n t e r t h e u s e r f a u l t h a n d l i n g p a t h t r y i n g
* to p a g e i t i n . T h i s w i l l l i k e l y r e s u l t i n s e n d i n g S E G V t o t h e
* current t a s k .
* /
9001 :
2017-03-24 19:15:45 +03:00
sub l r , s a v e d _ p c , #4
2013-06-05 14:25:13 +04:00
str l r , [ s p , #S _ P C ]
2017-03-24 19:19:12 +03:00
get_ t h r e a d _ i n f o t s k
2013-06-05 14:25:13 +04:00
b r e t _ f a s t _ s y s c a l l
# endif
2008-08-28 14:22:32 +04:00
ENDPROC( v e c t o r _ s w i )
2005-04-17 02:20:36 +04:00
/ *
* This i s t h e r e a l l y s l o w p a t h . W e ' r e g o i n g t o b e d o i n g
* context s w i t c h e s , a n d w a i t i n g f o r o u r p a r e n t t o r e s p o n d .
* /
__sys_trace :
2012-07-06 18:50:14 +04:00
mov r1 , s c n o
add r0 , s p , #S _ O F F
bl s y s c a l l _ t r a c e _ e n t e r
2018-05-11 13:16:22 +03:00
mov s c n o , r0
invoke_ s y s c a l l t b l , s c n o , r10 , _ _ s y s _ t r a c e _ r e t u r n , r e l o a d =1
2012-11-16 01:12:17 +04:00
cmp s c n o , #- 1 @ skip the syscall?
bne 2 b
add s p , s p , #S _ O F F @ r e s t o r e s t a c k
2005-04-17 02:20:36 +04:00
2018-10-08 21:26:48 +03:00
__sys_trace_return_nosave :
enable_ i r q _ n o t r a c e
2012-07-06 18:50:14 +04:00
mov r0 , s p
bl s y s c a l l _ t r a c e _ e x i t
2005-04-17 02:20:36 +04:00
b r e t _ s l o w _ s y s c a l l
2018-10-08 21:26:48 +03:00
__sys_trace_return :
str r0 , [ s p , #S _ R 0 + S _ O F F ] ! @ save returned r0
2015-08-20 18:13:37 +03:00
mov r0 , s p
bl s y s c a l l _ t r a c e _ e x i t
b r e t _ s l o w _ s y s c a l l
2005-04-17 02:20:36 +04:00
.align 5
# ifdef C O N F I G _ A L I G N M E N T _ T R A P
.type _ _ cr_ a l i g n m e n t , #o b j e c t
__cr_alignment :
.word cr_alignment
2006-01-14 19:36:12 +03:00
# endif
.ltorg
2016-10-18 21:57:01 +03:00
.macro syscall_ t a b l e _ s t a r t , s y m
.equ _ _ sys_ n r , 0
.type \ sym, #o b j e c t
ENTRY( \ s y m )
.endm
.macro syscall, n r , f u n c
.ifgt __sys_nr - \ nr
.error " Duplicated/ u n o r d e d s y s t e m c a l l e n t r y "
.endif
.rept \ nr - _ _ s y s _ n r
.long sys_ni_syscall
.endr
.long \ func
.equ _ _ sys_ n r , \ n r + 1
.endm
.macro syscall_ t a b l e _ e n d , s y m
.ifgt __sys_nr - _ _ NR_ s y s c a l l s
.error " System c a l l t a b l e t o o b i g "
.endif
.rept __NR_syscalls - _ _ sys_ n r
.long sys_ni_syscall
.endr
.size \ sym, . - \ s y m
.endm
# define N A T I V E ( n r , f u n c ) s y s c a l l n r , f u n c
2006-01-14 19:36:12 +03:00
/ *
* This i s t h e s y s c a l l t a b l e d e c l a r a t i o n f o r n a t i v e A B I s y s c a l l s .
* With E A B I a c o u p l e s y s c a l l s a r e o b s o l e t e a n d d e f i n e d a s s y s _ n i _ s y s c a l l .
* /
2016-10-18 21:57:01 +03:00
syscall_ t a b l e _ s t a r t s y s _ c a l l _ t a b l e
# define C O M P A T ( n r , n a t i v e , c o m p a t ) s y s c a l l n r , n a t i v e
2006-01-14 19:36:12 +03:00
# ifdef C O N F I G _ A E A B I
2016-10-18 21:57:01 +03:00
# include < c a l l s - e a b i . S >
2006-01-14 19:36:12 +03:00
# else
2016-10-18 21:57:01 +03:00
# include < c a l l s - o a b i . S >
2005-04-17 02:20:36 +04:00
# endif
2016-10-18 21:57:01 +03:00
# undef C O M P A T
syscall_ t a b l e _ e n d s y s _ c a l l _ t a b l e
2005-04-17 02:20:36 +04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Special s y s t e m c a l l w r a p p e r s
* /
@ r0 = syscall number
2005-12-17 18:25:42 +03:00
@ r8 = syscall table
2005-04-17 02:20:36 +04:00
sys_syscall :
2006-05-16 17:25:55 +04:00
bic s c n o , r0 , #_ _ N R _ O A B I _ S Y S C A L L _ B A S E
2005-04-17 02:20:36 +04:00
cmp s c n o , #_ _ N R _ s y s c a l l - _ _ N R _ S Y S C A L L _ B A S E
cmpne s c n o , #N R _ s y s c a l l s @ c h e c k r a n g e
2018-05-11 13:16:22 +03:00
# ifdef C O N F I G _ C P U _ S P E C T R E
movhs s c n o , #0
csdb
# endif
2019-02-18 02:57:38 +03:00
stmialo s p , { r5 , r6 } @ shuffle args
2005-04-17 02:20:36 +04:00
movlo r0 , r1
movlo r1 , r2
movlo r2 , r3
movlo r3 , r4
ldrlo p c , [ t b l , s c n o , l s l #2 ]
b s y s _ n i _ s y s c a l l
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ s y s c a l l )
2005-04-17 02:20:36 +04:00
sys_sigreturn_wrapper :
add r0 , s p , #S _ O F F
arm: fix really nasty sigreturn bug
If a signal hits us outside of a syscall and another gets delivered
when we are in sigreturn (e.g. because it had been in sa_mask for
the first one and got sent to us while we'd been in the first handler),
we have a chance of returning from the second handler to location one
insn prior to where we ought to return. If r0 happens to contain -513
(-ERESTARTNOINTR), sigreturn will get confused into doing restart
syscall song and dance.
Incredible joy to debug, since it manifests as random, infrequent and
very hard to reproduce double execution of instructions in userland
code...
The fix is simple - mark it "don't bother with restarts" in wrapper,
i.e. set r8 to 0 in sys_sigreturn and sys_rt_sigreturn wrappers,
suppressing the syscall restart handling on return from these guys.
They can't legitimately return a restart-worthy error anyway.
Testcase:
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
void f(int n)
{
__asm__ __volatile__(
"ldr r0, [%0]\n"
"b 1f\n"
"b 2f\n"
"1:b .\n"
"2:\n" : : "r"(&n));
}
void handler1(int sig) { }
void handler2(int sig) { raise(1); }
void handler3(int sig) { exit(0); }
main()
{
struct sigaction s = {.sa_handler = handler2};
struct itimerval t1 = { .it_value = {1} };
struct itimerval t2 = { .it_value = {2} };
signal(1, handler1);
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, 1);
sigaction(SIGALRM, &s, NULL);
signal(SIGVTALRM, handler3);
setitimer(ITIMER_REAL, &t1, NULL);
setitimer(ITIMER_VIRTUAL, &t2, NULL);
f(-513); /* -ERESTARTNOINTR */
write(1, "buggered\n", 9);
return 1;
}
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-09-17 17:34:39 +04:00
mov w h y , #0 @ prevent syscall restart handling
2005-04-17 02:20:36 +04:00
b s y s _ s i g r e t u r n
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ s i g r e t u r n _ w r a p p e r )
2005-04-17 02:20:36 +04:00
sys_rt_sigreturn_wrapper :
add r0 , s p , #S _ O F F
arm: fix really nasty sigreturn bug
If a signal hits us outside of a syscall and another gets delivered
when we are in sigreturn (e.g. because it had been in sa_mask for
the first one and got sent to us while we'd been in the first handler),
we have a chance of returning from the second handler to location one
insn prior to where we ought to return. If r0 happens to contain -513
(-ERESTARTNOINTR), sigreturn will get confused into doing restart
syscall song and dance.
Incredible joy to debug, since it manifests as random, infrequent and
very hard to reproduce double execution of instructions in userland
code...
The fix is simple - mark it "don't bother with restarts" in wrapper,
i.e. set r8 to 0 in sys_sigreturn and sys_rt_sigreturn wrappers,
suppressing the syscall restart handling on return from these guys.
They can't legitimately return a restart-worthy error anyway.
Testcase:
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
void f(int n)
{
__asm__ __volatile__(
"ldr r0, [%0]\n"
"b 1f\n"
"b 2f\n"
"1:b .\n"
"2:\n" : : "r"(&n));
}
void handler1(int sig) { }
void handler2(int sig) { raise(1); }
void handler3(int sig) { exit(0); }
main()
{
struct sigaction s = {.sa_handler = handler2};
struct itimerval t1 = { .it_value = {1} };
struct itimerval t2 = { .it_value = {2} };
signal(1, handler1);
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, 1);
sigaction(SIGALRM, &s, NULL);
signal(SIGVTALRM, handler3);
setitimer(ITIMER_REAL, &t1, NULL);
setitimer(ITIMER_VIRTUAL, &t2, NULL);
f(-513); /* -ERESTARTNOINTR */
write(1, "buggered\n", 9);
return 1;
}
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-09-17 17:34:39 +04:00
mov w h y , #0 @ prevent syscall restart handling
2005-04-17 02:20:36 +04:00
b s y s _ r t _ s i g r e t u r n
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ r t _ s i g r e t u r n _ w r a p p e r )
2005-04-17 02:20:36 +04:00
2006-01-14 19:35:03 +03:00
sys_statfs64_wrapper :
teq r1 , #88
moveq r1 , #84
b s y s _ s t a t f s64
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ s t a t f s64 _ w r a p p e r )
2006-01-14 19:35:03 +03:00
sys_fstatfs64_wrapper :
teq r1 , #88
moveq r1 , #84
b s y s _ f s t a t f s64
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ f s t a t f s64 _ w r a p p e r )
2006-01-14 19:35:03 +03:00
2005-04-17 02:20:36 +04:00
/ *
* Note : off_ 4 k ( r5 ) i s a l w a y s u n i t s o f 4 K . I f w e c a n ' t d o t h e r e q u e s t e d
* offset, w e r e t u r n E I N V A L .
* /
sys_mmap2 :
str r5 , [ s p , #4 ]
2009-12-01 01:37:04 +03:00
b s y s _ m m a p _ p g o f f
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ m m a p2 )
2006-01-14 19:35:31 +03:00
# ifdef C O N F I G _ O A B I _ C O M P A T
2006-01-14 19:36:12 +03:00
2006-01-14 19:35:31 +03:00
/ *
* These a r e s y s c a l l s w i t h a r g u m e n t r e g i s t e r d i f f e r e n c e s
* /
sys_oabi_pread64 :
stmia s p , { r3 , r4 }
b s y s _ p r e a d64
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ o a b i _ p r e a d64 )
2006-01-14 19:35:31 +03:00
sys_oabi_pwrite64 :
stmia s p , { r3 , r4 }
b s y s _ p w r i t e 6 4
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ o a b i _ p w r i t e 6 4 )
2006-01-14 19:35:31 +03:00
sys_oabi_truncate64 :
mov r3 , r2
mov r2 , r1
b s y s _ t r u n c a t e 6 4
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ o a b i _ t r u n c a t e 6 4 )
2006-01-14 19:35:31 +03:00
sys_oabi_ftruncate64 :
mov r3 , r2
mov r2 , r1
b s y s _ f t r u n c a t e 6 4
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ o a b i _ f t r u n c a t e 6 4 )
2006-01-14 19:35:31 +03:00
sys_oabi_readahead :
str r3 , [ s p ]
mov r3 , r2
mov r2 , r1
b s y s _ r e a d a h e a d
2008-08-28 14:22:32 +04:00
ENDPROC( s y s _ o a b i _ r e a d a h e a d )
2006-01-14 19:35:31 +03:00
2006-01-14 19:36:12 +03:00
/ *
* Let' s d e c l a r e a s e c o n d s y s c a l l t a b l e f o r o l d A B I b i n a r i e s
* using t h e c o m p a t i b i l i t y s y s c a l l e n t r i e s .
* /
2016-10-18 21:57:01 +03:00
syscall_ t a b l e _ s t a r t s y s _ o a b i _ c a l l _ t a b l e
# define C O M P A T ( n r , n a t i v e , c o m p a t ) s y s c a l l n r , c o m p a t
# include < c a l l s - o a b i . S >
syscall_ t a b l e _ e n d s y s _ o a b i _ c a l l _ t a b l e
2006-01-14 19:36:12 +03:00
2006-01-14 19:35:31 +03:00
# endif