Skip to content

Commit fa1827d

Browse files
committed
Merge tag 'powerpc-5.2-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc fixes from Michael Ellerman: "One fix for a regression introduced by our 32-bit KASAN support, which broke booting on machines with "bootx" early debugging enabled. A fix for a bug which broke kexec on 32-bit, introduced by changes to the 32-bit STRICT_KERNEL_RWX support in v5.1. Finally two fixes going to stable for our THP split/collapse handling, discovered by Nick. The first fixes random crashes and/or corruption in guests under sufficient load. Thanks to: Nicholas Piggin, Christophe Leroy, Aaro Koskinen, Mathieu Malaterre" * tag 'powerpc-5.2-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: powerpc/32s: fix booting with CONFIG_PPC_EARLY_DEBUG_BOOTX powerpc/64s: __find_linux_pte() synchronization vs pmdp_invalidate() powerpc/64s: Fix THP PMD collapse serialisation powerpc: Fix kexec failure on book3s/32
2 parents 6a71398 + c21f5a9 commit fa1827d

File tree

8 files changed

+59
-4
lines changed

8 files changed

+59
-4
lines changed

arch/powerpc/include/asm/book3s/64/pgtable.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,23 @@ static inline int pmd_present(pmd_t pmd)
876876
return false;
877877
}
878878

879+
static inline int pmd_is_serializing(pmd_t pmd)
880+
{
881+
/*
882+
* If the pmd is undergoing a split, the _PAGE_PRESENT bit is clear
883+
* and _PAGE_INVALID is set (see pmd_present, pmdp_invalidate).
884+
*
885+
* This condition may also occur when flushing a pmd while flushing
886+
* it (see ptep_modify_prot_start), so callers must ensure this
887+
* case is fine as well.
888+
*/
889+
if ((pmd_raw(pmd) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID)) ==
890+
cpu_to_be64(_PAGE_INVALID))
891+
return true;
892+
893+
return false;
894+
}
895+
879896
static inline int pmd_bad(pmd_t pmd)
880897
{
881898
if (radix_enabled())
@@ -1092,6 +1109,19 @@ static inline int pmd_protnone(pmd_t pmd)
10921109
#define pmd_access_permitted pmd_access_permitted
10931110
static inline bool pmd_access_permitted(pmd_t pmd, bool write)
10941111
{
1112+
/*
1113+
* pmdp_invalidate sets this combination (which is not caught by
1114+
* !pte_present() check in pte_access_permitted), to prevent
1115+
* lock-free lookups, as part of the serialize_against_pte_lookup()
1116+
* synchronisation.
1117+
*
1118+
* This also catches the case where the PTE's hardware PRESENT bit is
1119+
* cleared while TLB is flushed, which is suboptimal but should not
1120+
* be frequent.
1121+
*/
1122+
if (pmd_is_serializing(pmd))
1123+
return false;
1124+
10951125
return pte_access_permitted(pmd_pte(pmd), write);
10961126
}
10971127

arch/powerpc/include/asm/btext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ extern void btext_update_display(unsigned long phys, int width, int height,
1313
int depth, int pitch);
1414
extern void btext_setup_display(int width, int height, int depth, int pitch,
1515
unsigned long address);
16+
#ifdef CONFIG_PPC32
1617
extern void btext_prepare_BAT(void);
18+
#else
19+
static inline void btext_prepare_BAT(void) { }
20+
#endif
1721
extern void btext_map(void);
1822
extern void btext_unmap(void);
1923

arch/powerpc/include/asm/kexec.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ static inline bool kdump_in_progress(void)
9494
return crashing_cpu >= 0;
9595
}
9696

97+
void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_code_buffer,
98+
unsigned long start_address) __noreturn;
99+
97100
#ifdef CONFIG_KEXEC_FILE
98101
extern const struct kexec_file_ops kexec_elf64_ops;
99102

arch/powerpc/kernel/machine_kexec_32.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ typedef void (*relocate_new_kernel_t)(
3030
*/
3131
void default_machine_kexec(struct kimage *image)
3232
{
33-
extern const unsigned char relocate_new_kernel[];
3433
extern const unsigned int relocate_new_kernel_size;
3534
unsigned long page_list;
3635
unsigned long reboot_code_buffer, reboot_code_buffer_phys;
@@ -58,6 +57,9 @@ void default_machine_kexec(struct kimage *image)
5857
reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
5958
printk(KERN_INFO "Bye!\n");
6059

60+
if (!IS_ENABLED(CONFIG_FSL_BOOKE) && !IS_ENABLED(CONFIG_44x))
61+
relocate_new_kernel(page_list, reboot_code_buffer_phys, image->start);
62+
6163
/* now call it */
6264
rnk = (relocate_new_kernel_t) reboot_code_buffer;
6365
(*rnk)(page_list, reboot_code_buffer_phys, image->start);

arch/powerpc/kernel/prom_init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,6 +2336,7 @@ static void __init prom_check_displays(void)
23362336
prom_printf("W=%d H=%d LB=%d addr=0x%x\n",
23372337
width, height, pitch, addr);
23382338
btext_setup_display(width, height, 8, pitch, addr);
2339+
btext_prepare_BAT();
23392340
}
23402341
#endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */
23412342
}

arch/powerpc/kernel/prom_init_check.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fi
2424
WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
2525
_end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
2626
__secondary_hold_acknowledge __secondary_hold_spinloop __start
27-
logo_linux_clut224
27+
logo_linux_clut224 btext_prepare_BAT
2828
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
2929
__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."
3030

arch/powerpc/mm/book3s64/pgtable.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
112112
/*
113113
* This ensures that generic code that rely on IRQ disabling
114114
* to prevent a parallel THP split work as expected.
115+
*
116+
* Marking the entry with _PAGE_INVALID && ~_PAGE_PRESENT requires
117+
* a special case check in pmd_access_permitted.
115118
*/
116119
serialize_against_pte_lookup(vma->vm_mm);
117120
return __pmd(old_pmd);

arch/powerpc/mm/pgtable.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,25 @@ pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
368368
pdshift = PMD_SHIFT;
369369
pmdp = pmd_offset(&pud, ea);
370370
pmd = READ_ONCE(*pmdp);
371+
371372
/*
372-
* A hugepage collapse is captured by pmd_none, because
373-
* it mark the pmd none and do a hpte invalidate.
373+
* A hugepage collapse is captured by this condition, see
374+
* pmdp_collapse_flush.
374375
*/
375376
if (pmd_none(pmd))
376377
return NULL;
377378

379+
#ifdef CONFIG_PPC_BOOK3S_64
380+
/*
381+
* A hugepage split is captured by this condition, see
382+
* pmdp_invalidate.
383+
*
384+
* Huge page modification can be caught here too.
385+
*/
386+
if (pmd_is_serializing(pmd))
387+
return NULL;
388+
#endif
389+
378390
if (pmd_trans_huge(pmd) || pmd_devmap(pmd)) {
379391
if (is_thp)
380392
*is_thp = true;

0 commit comments

Comments
 (0)