fc6043a55e
[ Upstream commit daa9ada2093ed23d52b4c1fe6e13cf78f55cc85f ] Erhard reported that his G5 was crashing with v6.6-rc kernels: mpic: Setting up HT PICs workarounds for U3/U4 BUG: Unable to handle kernel data access at 0xfeffbb62ffec65fe Faulting instruction address: 0xc00000000005dc40 Oops: Kernel access of bad area, sig: 11 [#1] BE PAGE_SIZE=4K MMU=Hash SMP NR_CPUS=2 PowerMac Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Tainted: G T 6.6.0-rc3-PMacGS #1 Hardware name: PowerMac11,2 PPC970MP 0x440101 PowerMac NIP: c00000000005dc40 LR: c000000000066660 CTR: c000000000007730 REGS: c0000000022bf510 TRAP: 0380 Tainted: G T (6.6.0-rc3-PMacGS) MSR: 9000000000001032 <SF,HV,ME,IR,DR,RI> CR: 44004242 XER: 00000000 IRQMASK: 3 GPR00: 0000000000000000 c0000000022bf7b0 c0000000010c0b00 00000000000001ac GPR04: 0000000003c80000 0000000000000300 c0000000f20001ae 0000000000000300 GPR08: 0000000000000006 feffbb62ffec65ff 0000000000000001 0000000000000000 GPR12: 9000000000001032 c000000002362000 c000000000f76b80 000000000349ecd8 GPR16: 0000000002367ba8 0000000002367f08 0000000000000006 0000000000000000 GPR20: 00000000000001ac c000000000f6f920 c0000000022cd985 000000000000000c GPR24: 0000000000000300 00000003b0a3691d c0003e008030000e 0000000000000000 GPR28: c00000000000000c c0000000f20001ee feffbb62ffec65fe 00000000000001ac NIP hash_page_do_lazy_icache+0x50/0x100 LR __hash_page_4K+0x420/0x590 Call Trace: hash_page_mm+0x364/0x6f0 do_hash_fault+0x114/0x2b0 data_access_common_virt+0x198/0x1f0 --- interrupt: 300 at mpic_init+0x4bc/0x10c4 NIP: c000000002020a5c LR: c000000002020a04 CTR: 0000000000000000 REGS: c0000000022bf9f0 TRAP: 0300 Tainted: G T (6.6.0-rc3-PMacGS) MSR: 9000000000001032 <SF,HV,ME,IR,DR,RI> CR: 24004248 XER: 00000000 DAR: c0003e008030000e DSISR: 40000000 IRQMASK: 1 ... NIP mpic_init+0x4bc/0x10c4 LR mpic_init+0x464/0x10c4 --- interrupt: 300 pmac_setup_one_mpic+0x258/0x2dc pmac_pic_init+0x28c/0x3d8 init_IRQ+0x90/0x140 start_kernel+0x57c/0x78c start_here_common+0x1c/0x20 A bisect pointed to the breakage beginning with commit 9fee28baa601 ("powerpc: implement the new page table range API"). Analysis of the oops pointed to a struct page with a corrupted compound_head being loaded via page_folio() -> _compound_head() in hash_page_do_lazy_icache(). The access by the mpic code is to an MMIO address, so the expectation is that the struct page for that address would be initialised by init_unavailable_range(), as pointed out by Aneesh. Instrumentation showed that was not the case, which eventually lead to the realisation that pfn_valid() was returning false for that address, causing the struct page to not be initialised. Because the system is using FLATMEM, the version of pfn_valid() in memory_model.h is used: static inline int pfn_valid(unsigned long pfn) { ... return pfn >= pfn_offset && (pfn - pfn_offset) < max_mapnr; } Which relies on max_mapnr being initialised. Early in boot max_mapnr is zero meaning no PFNs are valid. max_mapnr is initialised in mem_init() called via: start_kernel() mm_core_init() # init/main.c:928 mem_init() But that is too late for the usage in init_unavailable_range() called via: start_kernel() setup_arch() # init/main.c:893 paging_init() free_area_init() init_unavailable_range() Although max_mapnr is currently set in mem_init(), the value is actually already available much earlier, as soon as mem_topology_setup() has completed, which is also before paging_init() is called. So move the initialisation there, which causes paging_init() to correctly initialise the struct page and fixes the bug. This bug seems to have been lurking for years, but went unnoticed because the pre-folio code was inspecting the uninitialised page->flags but not dereferencing it. Thanks to Erhard and Aneesh for help debugging. Reported-by: Erhard Furtner <erhard_f@mailbox.org> Closes: https://lore.kernel.org/all/20230929132750.3cd98452@yea/ Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20231023112500.1550208-1-mpe@ellerman.id.au Signed-off-by: Sasha Levin <sashal@kernel.org> |
||
---|---|---|
.. | ||
ptrace | ||
syscalls | ||
trace | ||
vdso32 | ||
vdso64 | ||
align.c | ||
asm-offsets.c | ||
audit.c | ||
btext.c | ||
cacheinfo.c | ||
cacheinfo.h | ||
compat_audit.c | ||
cpu_setup_6xx.S | ||
cpu_setup_44x.S | ||
cpu_setup_fsl_booke.S | ||
cpu_setup_pa6t.S | ||
cpu_setup_power.c | ||
cpu_setup_ppc970.S | ||
cputable.c | ||
crash_dump.c | ||
dawr.c | ||
dbell.c | ||
dma-iommu.c | ||
dma-mask.c | ||
dma-swiotlb.c | ||
dt_cpu_ftrs.c | ||
early_32.c | ||
eeh.c | ||
eeh_cache.c | ||
eeh_driver.c | ||
eeh_event.c | ||
eeh_pe.c | ||
eeh_sysfs.c | ||
entry_32.S | ||
entry_64.S | ||
epapr_hcalls.S | ||
epapr_paravirt.c | ||
exceptions-64e.S | ||
exceptions-64s.S | ||
fadump.c | ||
firmware.c | ||
fpu.S | ||
fsl_booke_entry_mapping.S | ||
head_8xx.S | ||
head_32.h | ||
head_40x.S | ||
head_44x.S | ||
head_64.S | ||
head_book3s_32.S | ||
head_booke.h | ||
head_fsl_booke.S | ||
hw_breakpoint.c | ||
hw_breakpoint_constraints.c | ||
idle.c | ||
idle_6xx.S | ||
idle_book3e.S | ||
idle_book3s.S | ||
idle_e500.S | ||
ima_arch.c | ||
io-workarounds.c | ||
io.c | ||
iomap.c | ||
iommu.c | ||
irq.c | ||
isa-bridge.c | ||
jump_label.c | ||
kgdb.c | ||
kprobes-ftrace.c | ||
kprobes.c | ||
kvm.c | ||
kvm_emul.S | ||
l2cr_6xx.S | ||
legacy_serial.c | ||
Makefile | ||
mce.c | ||
mce_power.c | ||
misc.S | ||
misc_32.S | ||
misc_64.S | ||
module.c | ||
module_32.c | ||
module_64.c | ||
msi.c | ||
note.S | ||
nvram_64.c | ||
of_platform.c | ||
optprobes.c | ||
optprobes_head.S | ||
paca.c | ||
pci-common.c | ||
pci-hotplug.c | ||
pci_32.c | ||
pci_64.c | ||
pci_dn.c | ||
pci_of_scan.c | ||
pmc.c | ||
ppc32.h | ||
ppc_save_regs.S | ||
proc_powerpc.c | ||
process.c | ||
prom.c | ||
prom_init.c | ||
prom_init_check.sh | ||
prom_parse.c | ||
reloc_32.S | ||
reloc_64.S | ||
rtas-proc.c | ||
rtas-rtc.c | ||
rtas.c | ||
rtas_flash.c | ||
rtas_pci.c | ||
rtasd.c | ||
secure_boot.c | ||
security.c | ||
secvar-ops.c | ||
secvar-sysfs.c | ||
setup-common.c | ||
setup.h | ||
setup_32.c | ||
setup_64.c | ||
signal.c | ||
signal.h | ||
signal_32.c | ||
signal_64.c | ||
smp-tbsync.c | ||
smp.c | ||
stacktrace.c | ||
suspend.c | ||
swsusp.c | ||
swsusp_32.S | ||
swsusp_64.c | ||
swsusp_asm64.S | ||
swsusp_booke.S | ||
sys_ppc32.c | ||
syscall_64.c | ||
syscalls.c | ||
sysfs.c | ||
systbl.S | ||
systbl_chk.sh | ||
tau_6xx.c | ||
time.c | ||
tm.S | ||
traps.c | ||
ucall.S | ||
udbg.c | ||
udbg_16550.c | ||
uprobes.c | ||
vdso.c | ||
vecemu.c | ||
vector.S | ||
vmlinux.lds.S | ||
watchdog.c |