Skip to content

Commit 232ca1e

Browse files
chleroympe
authored andcommitted
powerpc/32s: Fix DSI and ISI exceptions for CONFIG_VMAP_STACK
hash_page() needs to read page tables from kernel memory. When entire kernel memory is mapped by BATs, which is normally the case when CONFIG_STRICT_KERNEL_RWX is not set, it works even if the page hosting the page table is not referenced in the MMU hash table. However, if the page where the page table resides is not covered by a BAT, a DSI fault can be encountered from hash_page(), and it loops forever. This can happen when CONFIG_STRICT_KERNEL_RWX is selected and the alignment of the different regions is too small to allow covering the entire memory with BATs. This also happens when CONFIG_DEBUG_PAGEALLOC is selected or when booting with 'nobats' flag. Also, if the page containing the kernel stack is not present in the MMU hash table, registers cannot be saved and a recursive DSI fault is encountered. To allow hash_page() to properly do its job at all time and load the MMU hash table whenever needed, it must run with data MMU disabled. This means it must be called before re-enabling data MMU. To allow this, registers clobbered by hash_page() and create_hpte() have to be saved in the thread struct together with SRR0, SSR1, DAR and DSISR. It is also necessary to ensure that DSI prolog doesn't overwrite regs saved by prolog of the current running exception. That means: - DSI can only use SPRN_SPRG_SCRATCH0 - Exceptions must free SPRN_SPRG_SCRATCH0 before writing to the stack. This also fixes the Oops reported by Erhard when create_hpte() is called by add_hash_page(). Due to prolog size increase, a few more exceptions had to get split in two parts. Fixes: cd08f10 ("powerpc/32s: Enable CONFIG_VMAP_STACK") Reported-by: Erhard F. <[email protected]> Signed-off-by: Christophe Leroy <[email protected]> Tested-by: Erhard F. <[email protected]> Tested-by: Larry Finger <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://bugzilla.kernel.org/show_bug.cgi?id=206501 Link: https://lore.kernel.org/r/64a4aa44686e9fd4b01333401367029771d9b231.1581761633.git.christophe.leroy@c-s.fr
1 parent 2464cc4 commit 232ca1e

File tree

7 files changed

+212
-45
lines changed

7 files changed

+212
-45
lines changed

arch/powerpc/include/asm/processor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ struct thread_struct {
168168
unsigned long srr1;
169169
unsigned long dar;
170170
unsigned long dsisr;
171+
#ifdef CONFIG_PPC_BOOK3S_32
172+
unsigned long r0, r3, r4, r5, r6, r8, r9, r11;
173+
unsigned long lr, ctr;
174+
#endif
171175
#endif
172176
/* Debug Registers */
173177
struct debug_reg debug;

arch/powerpc/kernel/asm-offsets.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,18 @@ int main(void)
132132
OFFSET(SRR1, thread_struct, srr1);
133133
OFFSET(DAR, thread_struct, dar);
134134
OFFSET(DSISR, thread_struct, dsisr);
135+
#ifdef CONFIG_PPC_BOOK3S_32
136+
OFFSET(THR0, thread_struct, r0);
137+
OFFSET(THR3, thread_struct, r3);
138+
OFFSET(THR4, thread_struct, r4);
139+
OFFSET(THR5, thread_struct, r5);
140+
OFFSET(THR6, thread_struct, r6);
141+
OFFSET(THR8, thread_struct, r8);
142+
OFFSET(THR9, thread_struct, r9);
143+
OFFSET(THR11, thread_struct, r11);
144+
OFFSET(THLR, thread_struct, lr);
145+
OFFSET(THCTR, thread_struct, ctr);
146+
#endif
135147
#endif
136148
#ifdef CONFIG_SPE
137149
OFFSET(THREAD_EVR0, thread_struct, evr[0]);

arch/powerpc/kernel/head_32.S

Lines changed: 150 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,17 +290,55 @@ MachineCheck:
290290
7: EXCEPTION_PROLOG_2
291291
addi r3,r1,STACK_FRAME_OVERHEAD
292292
#ifdef CONFIG_PPC_CHRP
293-
bne cr1,1f
293+
#ifdef CONFIG_VMAP_STACK
294+
mfspr r4, SPRN_SPRG_THREAD
295+
tovirt(r4, r4)
296+
lwz r4, RTAS_SP(r4)
297+
cmpwi cr1, r4, 0
294298
#endif
295-
EXC_XFER_STD(0x200, machine_check_exception)
296-
#ifdef CONFIG_PPC_CHRP
297-
1: b machine_check_in_rtas
299+
beq cr1, machine_check_tramp
300+
b machine_check_in_rtas
301+
#else
302+
b machine_check_tramp
298303
#endif
299304

300305
/* Data access exception. */
301306
. = 0x300
302307
DO_KVM 0x300
303308
DataAccess:
309+
#ifdef CONFIG_VMAP_STACK
310+
mtspr SPRN_SPRG_SCRATCH0,r10
311+
mfspr r10, SPRN_SPRG_THREAD
312+
BEGIN_MMU_FTR_SECTION
313+
stw r11, THR11(r10)
314+
mfspr r10, SPRN_DSISR
315+
mfcr r11
316+
#ifdef CONFIG_PPC_KUAP
317+
andis. r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH | DSISR_PROTFAULT)@h
318+
#else
319+
andis. r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
320+
#endif
321+
mfspr r10, SPRN_SPRG_THREAD
322+
beq hash_page_dsi
323+
.Lhash_page_dsi_cont:
324+
mtcr r11
325+
lwz r11, THR11(r10)
326+
END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
327+
mtspr SPRN_SPRG_SCRATCH1,r11
328+
mfspr r11, SPRN_DAR
329+
stw r11, DAR(r10)
330+
mfspr r11, SPRN_DSISR
331+
stw r11, DSISR(r10)
332+
mfspr r11, SPRN_SRR0
333+
stw r11, SRR0(r10)
334+
mfspr r11, SPRN_SRR1 /* check whether user or kernel */
335+
stw r11, SRR1(r10)
336+
mfcr r10
337+
andi. r11, r11, MSR_PR
338+
339+
EXCEPTION_PROLOG_1
340+
b handle_page_fault_tramp_1
341+
#else /* CONFIG_VMAP_STACK */
304342
EXCEPTION_PROLOG handle_dar_dsisr=1
305343
get_and_save_dar_dsisr_on_stack r4, r5, r11
306344
BEGIN_MMU_FTR_SECTION
@@ -316,11 +354,32 @@ BEGIN_MMU_FTR_SECTION
316354
FTR_SECTION_ELSE
317355
b handle_page_fault_tramp_2
318356
ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
357+
#endif /* CONFIG_VMAP_STACK */
319358

320359
/* Instruction access exception. */
321360
. = 0x400
322361
DO_KVM 0x400
323362
InstructionAccess:
363+
#ifdef CONFIG_VMAP_STACK
364+
mtspr SPRN_SPRG_SCRATCH0,r10
365+
mtspr SPRN_SPRG_SCRATCH1,r11
366+
mfspr r10, SPRN_SPRG_THREAD
367+
mfspr r11, SPRN_SRR0
368+
stw r11, SRR0(r10)
369+
mfspr r11, SPRN_SRR1 /* check whether user or kernel */
370+
stw r11, SRR1(r10)
371+
mfcr r10
372+
BEGIN_MMU_FTR_SECTION
373+
andis. r11, r11, SRR1_ISI_NOPT@h /* no pte found? */
374+
bne hash_page_isi
375+
.Lhash_page_isi_cont:
376+
mfspr r11, SPRN_SRR1 /* check whether user or kernel */
377+
END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
378+
andi. r11, r11, MSR_PR
379+
380+
EXCEPTION_PROLOG_1
381+
EXCEPTION_PROLOG_2
382+
#else /* CONFIG_VMAP_STACK */
324383
EXCEPTION_PROLOG
325384
andis. r0,r9,SRR1_ISI_NOPT@h /* no pte found? */
326385
beq 1f /* if so, try to put a PTE */
@@ -329,6 +388,7 @@ InstructionAccess:
329388
BEGIN_MMU_FTR_SECTION
330389
bl hash_page
331390
END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
391+
#endif /* CONFIG_VMAP_STACK */
332392
1: mr r4,r12
333393
andis. r5,r9,DSISR_SRR1_MATCH_32S@h /* Filter relevant SRR1 bits */
334394
stw r4, _DAR(r11)
@@ -344,7 +404,7 @@ Alignment:
344404
EXCEPTION_PROLOG handle_dar_dsisr=1
345405
save_dar_dsisr_on_stack r4, r5, r11
346406
addi r3,r1,STACK_FRAME_OVERHEAD
347-
EXC_XFER_STD(0x600, alignment_exception)
407+
b alignment_exception_tramp
348408

349409
/* Program check exception */
350410
EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
@@ -645,15 +705,100 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
645705

646706
. = 0x3000
647707

708+
machine_check_tramp:
709+
EXC_XFER_STD(0x200, machine_check_exception)
710+
711+
alignment_exception_tramp:
712+
EXC_XFER_STD(0x600, alignment_exception)
713+
648714
handle_page_fault_tramp_1:
715+
#ifdef CONFIG_VMAP_STACK
716+
EXCEPTION_PROLOG_2 handle_dar_dsisr=1
717+
#endif
649718
lwz r4, _DAR(r11)
650719
lwz r5, _DSISR(r11)
651720
/* fall through */
652721
handle_page_fault_tramp_2:
653722
EXC_XFER_LITE(0x300, handle_page_fault)
654723

724+
#ifdef CONFIG_VMAP_STACK
725+
.macro save_regs_thread thread
726+
stw r0, THR0(\thread)
727+
stw r3, THR3(\thread)
728+
stw r4, THR4(\thread)
729+
stw r5, THR5(\thread)
730+
stw r6, THR6(\thread)
731+
stw r8, THR8(\thread)
732+
stw r9, THR9(\thread)
733+
mflr r0
734+
stw r0, THLR(\thread)
735+
mfctr r0
736+
stw r0, THCTR(\thread)
737+
.endm
738+
739+
.macro restore_regs_thread thread
740+
lwz r0, THLR(\thread)
741+
mtlr r0
742+
lwz r0, THCTR(\thread)
743+
mtctr r0
744+
lwz r0, THR0(\thread)
745+
lwz r3, THR3(\thread)
746+
lwz r4, THR4(\thread)
747+
lwz r5, THR5(\thread)
748+
lwz r6, THR6(\thread)
749+
lwz r8, THR8(\thread)
750+
lwz r9, THR9(\thread)
751+
.endm
752+
753+
hash_page_dsi:
754+
save_regs_thread r10
755+
mfdsisr r3
756+
mfdar r4
757+
mfsrr0 r5
758+
mfsrr1 r9
759+
rlwinm r3, r3, 32 - 15, _PAGE_RW /* DSISR_STORE -> _PAGE_RW */
760+
bl hash_page
761+
mfspr r10, SPRN_SPRG_THREAD
762+
restore_regs_thread r10
763+
b .Lhash_page_dsi_cont
764+
765+
hash_page_isi:
766+
mr r11, r10
767+
mfspr r10, SPRN_SPRG_THREAD
768+
save_regs_thread r10
769+
li r3, 0
770+
lwz r4, SRR0(r10)
771+
lwz r9, SRR1(r10)
772+
bl hash_page
773+
mfspr r10, SPRN_SPRG_THREAD
774+
restore_regs_thread r10
775+
mr r10, r11
776+
b .Lhash_page_isi_cont
777+
778+
.globl fast_hash_page_return
779+
fast_hash_page_return:
780+
andis. r10, r9, SRR1_ISI_NOPT@h /* Set on ISI, cleared on DSI */
781+
mfspr r10, SPRN_SPRG_THREAD
782+
restore_regs_thread r10
783+
bne 1f
784+
785+
/* DSI */
786+
mtcr r11
787+
lwz r11, THR11(r10)
788+
mfspr r10, SPRN_SPRG_SCRATCH0
789+
SYNC
790+
RFI
791+
792+
1: /* ISI */
793+
mtcr r11
794+
mfspr r11, SPRN_SPRG_SCRATCH1
795+
mfspr r10, SPRN_SPRG_SCRATCH0
796+
SYNC
797+
RFI
798+
655799
stack_overflow:
656800
vmap_stack_overflow_exception
801+
#endif
657802

658803
AltiVecUnavailable:
659804
EXCEPTION_PROLOG

arch/powerpc/kernel/head_32.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,25 @@
6464
.endm
6565

6666
.macro EXCEPTION_PROLOG_2 handle_dar_dsisr=0
67+
#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
68+
BEGIN_MMU_FTR_SECTION
69+
mtcr r10
70+
FTR_SECTION_ELSE
71+
stw r10, _CCR(r11)
72+
ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
73+
#else
6774
stw r10,_CCR(r11) /* save registers */
75+
#endif
76+
mfspr r10, SPRN_SPRG_SCRATCH0
6877
stw r12,GPR12(r11)
6978
stw r9,GPR9(r11)
70-
mfspr r10,SPRN_SPRG_SCRATCH0
7179
stw r10,GPR10(r11)
80+
#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
81+
BEGIN_MMU_FTR_SECTION
82+
mfcr r10
83+
stw r10, _CCR(r11)
84+
END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
85+
#endif
7286
mfspr r12,SPRN_SPRG_SCRATCH1
7387
stw r12,GPR11(r11)
7488
mflr r10
@@ -83,6 +97,11 @@
8397
stw r10, _DSISR(r11)
8498
.endif
8599
lwz r9, SRR1(r12)
100+
#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
101+
BEGIN_MMU_FTR_SECTION
102+
andi. r10, r9, MSR_PR
103+
END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
104+
#endif
86105
lwz r12, SRR0(r12)
87106
#else
88107
mfspr r12,SPRN_SRR0

0 commit comments

Comments
 (0)