Skip to content

Commit 04946fb

Browse files
author
Russell King
committed
ARM: fix oops when using older ARMv4T CPUs
Alexander Shiyan reports that CLPS711x fails at boot time in the data exception handler due to a NULL pointer dereference. This is caused by the late-v4t abort handler overwriting R9 (which becomes zero). Fix this by making the abort handler save and restore R9. Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = c3b58000 [00000008] *pgd=800000000, *pte=00000000, *ppte=feff4140 Internal error: Oops: 63c11817 [#1] PREEMPT ARM CPU: 0 PID: 448 Comm: ash Not tainted 4.8.1+ #1 Hardware name: Cirrus Logic CLPS711X (Device Tree Support) task: c39e03a0 ti: c3b4e000 task.ti: c3b4e000 PC is at __dabt_svc+0x4c/0x60 LR is at do_page_fault+0x144/0x2ac pc : [<c000d3ac>] lr : [<c000fcec>] psr: 60000093 sp : c3b4fe6c ip : 00000001 fp : b6f1bf88 r10: c387a5a0 r9 : 00000000 r8 : e4e0e001 r7 : bee3ef83 r6 : 00100000 r5 : 80000013 r4 : c022fcf8 r3 : 00000000 r2 : 00000008 r1 : bf000000 r0 : 00000000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 0000217f Table: c3b58055 DAC: 00000055 Process ash (pid: 448, stack limit = 0xc3b4e190) Stack: (0xc3b4fe6c to 0xc3b50000) fe60: bee3ef83 c05168d1 ffffffff 00000000 c3adfe80 fe80: c3a03300 00000000 c3b4fed0 c3a03400 bee3ef83 c387a5a0 b6f1bf88 00000001 fea0: c3b4febc 00000076 c022fcf8 80000013 ffffffff 0000003f bf000000 bee3ef83 fec0: 00000004 00000000 c3adfe80 c00e432c 00000812 00000005 00000001 00000006 fee0: b6f1b000 00000000 00010000 0003c944 0004d000 0004d439 00010000 b6f1b000 ff00: 00000005 00000000 00015ecc c3b4fed0 0000000a 00000000 00000000 c00a1dc0 ff20: befff000 c3a03300 c3b4e000 c0507cd c0508024 fffffff8 c3a03300 00000000 ff40: c0516a58 c00a35bc c39e03a0 000001c0 bea84ce8 0004e008 c3b3a000 c00a3ac0 ff60: c3b40374 c3b3a000 bea84d11 00000000 c0500188 bea84d11 bea84ce8 00000001 ff80: 0000000b c000a304 c3b4e000 00000000 bea84ce4 c00a3cd0 00000000 bea84d11 ffa0: bea84ce8 c000a160 bea84d11 bea84ce8 bea84d11 bea84ce8 0004e008 0004d450 ffc0: bea84d11 bea84ce8 00000001 0000000b b6f45ee4 00000000 b6f5ff70 bea84ce4 ffe0: b6f2f130 bea84cb0 b6f2f194 b6ef29f4 a0000010 bea84d11 02c7cffa 02c7cffd [<c000d3ac>] (__dabt_svc) from [<c022fcf8>] (__copy_to_user_std+0xf8/0x330) [<c022fcf8>] (__copy_to_user_std) from [<c00e432c>] +(load_elf_binary+0x920/0x107c) [<c00e432c>] (load_elf_binary) from [<c00a35bc>] +(search_binary_handler+0x80/0x16c) [<c00a35bc>] (search_binary_handler) from [<c00a3ac0>] +(do_execveat_common+0x418/0x600) [<c00a3ac0>] (do_execveat_common) from [<c00a3cd0>] (do_execve+0x28/0x30) [<c00a3cd0>] (do_execve) from [<c000a160>] (ret_fast_syscall+0x0/0x30) Code: e1a0200d eb00136b e321f093 e59d104c (e5891008) ---[ end trace 4b4f8086ebef98c5 ]--- Fixes: e6978e4 ("ARM: save and reset the address limit when entering an exception") Reported-by: Alexander Shiyan <shc_work@mail.ru> Tested-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
1 parent 1001354 commit 04946fb

1 file changed

Lines changed: 24 additions & 10 deletions

File tree

arch/arm/mm/abort-lv4t.S

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* : r4 = aborted context pc
88
* : r5 = aborted context psr
99
*
10-
* Returns : r4-r5, r10-r11, r13 preserved
10+
* Returns : r4-r5, r9-r11, r13 preserved
1111
*
1212
* Purpose : obtain information about current aborted instruction.
1313
* Note: we read user space. This means we might cause a data
@@ -48,7 +48,10 @@ ENTRY(v4t_late_abort)
4848
/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
4949
/* d */ b do_DataAbort @ ldc rd, [rn, #m]
5050
/* e */ b .data_unknown
51-
/* f */
51+
/* f */ b .data_unknown
52+
53+
.data_unknown_r9:
54+
ldr r9, [sp], #4
5255
.data_unknown: @ Part of jumptable
5356
mov r0, r4
5457
mov r1, r8
@@ -57,6 +60,7 @@ ENTRY(v4t_late_abort)
5760
.data_arm_ldmstm:
5861
tst r8, #1 << 21 @ check writeback bit
5962
beq do_DataAbort @ no writeback -> no fixup
63+
str r9, [sp, #-4]!
6064
mov r7, #0x11
6165
orr r7, r7, #0x1100
6266
and r6, r8, r7
@@ -75,12 +79,14 @@ ENTRY(v4t_late_abort)
7579
subne r7, r7, r6, lsl #2 @ Undo increment
7680
addeq r7, r7, r6, lsl #2 @ Undo decrement
7781
str r7, [r2, r9, lsr #14] @ Put register 'Rn'
82+
ldr r9, [sp], #4
7883
b do_DataAbort
7984

8085
.data_arm_lateldrhpre:
8186
tst r8, #1 << 21 @ Check writeback bit
8287
beq do_DataAbort @ No writeback -> no fixup
8388
.data_arm_lateldrhpost:
89+
str r9, [sp, #-4]!
8490
and r9, r8, #0x00f @ get Rm / low nibble of immediate value
8591
tst r8, #1 << 22 @ if (immediate offset)
8692
andne r6, r8, #0xf00 @ { immediate high nibble
@@ -93,6 +99,7 @@ ENTRY(v4t_late_abort)
9399
subne r7, r7, r6 @ Undo incrmenet
94100
addeq r7, r7, r6 @ Undo decrement
95101
str r7, [r2, r9, lsr #14] @ Put register 'Rn'
102+
ldr r9, [sp], #4
96103
b do_DataAbort
97104

98105
.data_arm_lateldrpreconst:
@@ -101,12 +108,14 @@ ENTRY(v4t_late_abort)
101108
.data_arm_lateldrpostconst:
102109
movs r6, r8, lsl #20 @ Get offset
103110
beq do_DataAbort @ zero -> no fixup
111+
str r9, [sp, #-4]!
104112
and r9, r8, #15 << 16 @ Extract 'n' from instruction
105113
ldr r7, [r2, r9, lsr #14] @ Get register 'Rn'
106114
tst r8, #1 << 23 @ Check U bit
107115
subne r7, r7, r6, lsr #20 @ Undo increment
108116
addeq r7, r7, r6, lsr #20 @ Undo decrement
109117
str r7, [r2, r9, lsr #14] @ Put register 'Rn'
118+
ldr r9, [sp], #4
110119
b do_DataAbort
111120

112121
.data_arm_lateldrprereg:
@@ -115,6 +124,7 @@ ENTRY(v4t_late_abort)
115124
.data_arm_lateldrpostreg:
116125
and r7, r8, #15 @ Extract 'm' from instruction
117126
ldr r6, [r2, r7, lsl #2] @ Get register 'Rm'
127+
str r9, [sp, #-4]!
118128
mov r9, r8, lsr #7 @ get shift count
119129
ands r9, r9, #31
120130
and r7, r8, #0x70 @ get shift type
@@ -126,33 +136,33 @@ ENTRY(v4t_late_abort)
126136
b .data_arm_apply_r6_and_rn
127137
b .data_arm_apply_r6_and_rn @ 1: LSL #0
128138
nop
129-
b .data_unknown @ 2: MUL?
139+
b .data_unknown_r9 @ 2: MUL?
130140
nop
131-
b .data_unknown @ 3: MUL?
141+
b .data_unknown_r9 @ 3: MUL?
132142
nop
133143
mov r6, r6, lsr r9 @ 4: LSR #!0
134144
b .data_arm_apply_r6_and_rn
135145
mov r6, r6, lsr #32 @ 5: LSR #32
136146
b .data_arm_apply_r6_and_rn
137-
b .data_unknown @ 6: MUL?
147+
b .data_unknown_r9 @ 6: MUL?
138148
nop
139-
b .data_unknown @ 7: MUL?
149+
b .data_unknown_r9 @ 7: MUL?
140150
nop
141151
mov r6, r6, asr r9 @ 8: ASR #!0
142152
b .data_arm_apply_r6_and_rn
143153
mov r6, r6, asr #32 @ 9: ASR #32
144154
b .data_arm_apply_r6_and_rn
145-
b .data_unknown @ A: MUL?
155+
b .data_unknown_r9 @ A: MUL?
146156
nop
147-
b .data_unknown @ B: MUL?
157+
b .data_unknown_r9 @ B: MUL?
148158
nop
149159
mov r6, r6, ror r9 @ C: ROR #!0
150160
b .data_arm_apply_r6_and_rn
151161
mov r6, r6, rrx @ D: RRX
152162
b .data_arm_apply_r6_and_rn
153-
b .data_unknown @ E: MUL?
163+
b .data_unknown_r9 @ E: MUL?
154164
nop
155-
b .data_unknown @ F: MUL?
165+
b .data_unknown_r9 @ F: MUL?
156166

157167
.data_thumb_abort:
158168
ldrh r8, [r4] @ read instruction
@@ -190,6 +200,7 @@ ENTRY(v4t_late_abort)
190200
.data_thumb_pushpop:
191201
tst r8, #1 << 10
192202
beq .data_unknown
203+
str r9, [sp, #-4]!
193204
and r6, r8, #0x55 @ hweight8(r8) + R bit
194205
and r9, r8, #0xaa
195206
add r6, r6, r9, lsr #1
@@ -204,9 +215,11 @@ ENTRY(v4t_late_abort)
204215
addeq r7, r7, r6, lsl #2 @ increment SP if PUSH
205216
subne r7, r7, r6, lsl #2 @ decrement SP if POP
206217
str r7, [r2, #13 << 2]
218+
ldr r9, [sp], #4
207219
b do_DataAbort
208220

209221
.data_thumb_ldmstm:
222+
str r9, [sp, #-4]!
210223
and r6, r8, #0x55 @ hweight8(r8)
211224
and r9, r8, #0xaa
212225
add r6, r6, r9, lsr #1
@@ -219,4 +232,5 @@ ENTRY(v4t_late_abort)
219232
and r6, r6, #15 @ number of regs to transfer
220233
sub r7, r7, r6, lsl #2 @ always decrement
221234
str r7, [r2, r9, lsr #6]
235+
ldr r9, [sp], #4
222236
b do_DataAbort

0 commit comments

Comments
 (0)