Skip to content

Commit d92da7d

Browse files
Russell Kingksacilotto
authored andcommitted
ARM: kexec: fix oops after TLB are invalidated
BugLink: https://bugs.launchpad.net/bugs/1918167 [ Upstream commit 4d62e81 ] Giancarlo Ferrari reports the following oops while trying to use kexec: Unable to handle kernel paging request at virtual address 80112f38 pgd = fd7ef03e [80112f38] *pgd=0001141e(bad) Internal error: Oops: 80d [#1] PREEMPT SMP ARM ... This is caused by machine_kexec() trying to set the kernel text to be read/write, so it can poke values into the relocation code before copying it - and an interrupt occuring which changes the page tables. The subsequent writes then hit read-only sections that trigger a data abort resulting in the above oops. Fix this by copying the relocation code, and then writing the variables into the destination, thereby avoiding the need to make the kernel text read/write. Reported-by: Giancarlo Ferrari <[email protected]> Tested-by: Giancarlo Ferrari <[email protected]> Signed-off-by: Russell King <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Kelsey Skunberg <[email protected]>
1 parent 047ac80 commit d92da7d

File tree

4 files changed

+36
-39
lines changed

4 files changed

+36
-39
lines changed

arch/arm/include/asm/kexec-internal.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ARM_KEXEC_INTERNAL_H
3+
#define _ARM_KEXEC_INTERNAL_H
4+
5+
struct kexec_relocate_data {
6+
unsigned long kexec_start_address;
7+
unsigned long kexec_indirection_page;
8+
unsigned long kexec_mach_type;
9+
unsigned long kexec_r2;
10+
};
11+
12+
#endif

arch/arm/kernel/asm-offsets.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/kvm_host.h>
1616
#endif
1717
#include <asm/cacheflush.h>
18+
#include <asm/kexec-internal.h>
1819
#include <asm/glue-df.h>
1920
#include <asm/glue-pf.h>
2021
#include <asm/mach/arch.h>
@@ -190,5 +191,9 @@ int main(void)
190191
DEFINE(MPU_RGN_PRBAR, offsetof(struct mpu_rgn, prbar));
191192
DEFINE(MPU_RGN_PRLAR, offsetof(struct mpu_rgn, prlar));
192193
#endif
194+
DEFINE(KEXEC_START_ADDR, offsetof(struct kexec_relocate_data, kexec_start_address));
195+
DEFINE(KEXEC_INDIR_PAGE, offsetof(struct kexec_relocate_data, kexec_indirection_page));
196+
DEFINE(KEXEC_MACH_TYPE, offsetof(struct kexec_relocate_data, kexec_mach_type));
197+
DEFINE(KEXEC_R2, offsetof(struct kexec_relocate_data, kexec_r2));
193198
return 0;
194199
}

arch/arm/kernel/machine_kexec.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <asm/pgalloc.h>
1616
#include <asm/mmu_context.h>
1717
#include <asm/cacheflush.h>
18+
#include <asm/kexec-internal.h>
1819
#include <asm/fncpy.h>
1920
#include <asm/mach-types.h>
2021
#include <asm/smp_plat.h>
@@ -24,11 +25,6 @@
2425
extern void relocate_new_kernel(void);
2526
extern const unsigned int relocate_new_kernel_size;
2627

27-
extern unsigned long kexec_start_address;
28-
extern unsigned long kexec_indirection_page;
29-
extern unsigned long kexec_mach_type;
30-
extern unsigned long kexec_boot_atags;
31-
3228
static atomic_t waiting_for_crash_ipi;
3329

3430
/*
@@ -161,6 +157,7 @@ void (*kexec_reinit)(void);
161157
void machine_kexec(struct kimage *image)
162158
{
163159
unsigned long page_list, reboot_entry_phys;
160+
struct kexec_relocate_data *data;
164161
void (*reboot_entry)(void);
165162
void *reboot_code_buffer;
166163

@@ -176,18 +173,17 @@ void machine_kexec(struct kimage *image)
176173

177174
reboot_code_buffer = page_address(image->control_code_page);
178175

179-
/* Prepare parameters for reboot_code_buffer*/
180-
set_kernel_text_rw();
181-
kexec_start_address = image->start;
182-
kexec_indirection_page = page_list;
183-
kexec_mach_type = machine_arch_type;
184-
kexec_boot_atags = image->arch.kernel_r2;
185-
186176
/* copy our kernel relocation code to the control code page */
187177
reboot_entry = fncpy(reboot_code_buffer,
188178
&relocate_new_kernel,
189179
relocate_new_kernel_size);
190180

181+
data = reboot_code_buffer + relocate_new_kernel_size;
182+
data->kexec_start_address = image->start;
183+
data->kexec_indirection_page = page_list;
184+
data->kexec_mach_type = machine_arch_type;
185+
data->kexec_r2 = image->arch.kernel_r2;
186+
191187
/* get the identity mapping physical address for the reboot code */
192188
reboot_entry_phys = virt_to_idmap(reboot_entry);
193189

arch/arm/kernel/relocate_kernel.S

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
#include <linux/linkage.h>
77
#include <asm/assembler.h>
8+
#include <asm/asm-offsets.h>
89
#include <asm/kexec.h>
910

1011
.align 3 /* not needed for this code, but keeps fncpy() happy */
1112

1213
ENTRY(relocate_new_kernel)
1314

14-
ldr r0,kexec_indirection_page
15-
ldr r1,kexec_start_address
15+
adr r7, relocate_new_kernel_end
16+
ldr r0, [r7, #KEXEC_INDIR_PAGE]
17+
ldr r1, [r7, #KEXEC_START_ADDR]
1618

1719
/*
1820
* If there is no indirection page (we are doing crashdumps)
@@ -57,34 +59,16 @@ ENTRY(relocate_new_kernel)
5759

5860
2:
5961
/* Jump to relocated kernel */
60-
mov lr,r1
61-
mov r0,#0
62-
ldr r1,kexec_mach_type
63-
ldr r2,kexec_boot_atags
64-
ARM( ret lr )
65-
THUMB( bx lr )
66-
67-
.align
68-
69-
.globl kexec_start_address
70-
kexec_start_address:
71-
.long 0x0
72-
73-
.globl kexec_indirection_page
74-
kexec_indirection_page:
75-
.long 0x0
76-
77-
.globl kexec_mach_type
78-
kexec_mach_type:
79-
.long 0x0
80-
81-
/* phy addr of the atags for the new kernel */
82-
.globl kexec_boot_atags
83-
kexec_boot_atags:
84-
.long 0x0
62+
mov lr, r1
63+
mov r0, #0
64+
ldr r1, [r7, #KEXEC_MACH_TYPE]
65+
ldr r2, [r7, #KEXEC_R2]
66+
ARM( ret lr )
67+
THUMB( bx lr )
8568

8669
ENDPROC(relocate_new_kernel)
8770

71+
.align 3
8872
relocate_new_kernel_end:
8973

9074
.globl relocate_new_kernel_size

0 commit comments

Comments
 (0)