Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xtensa: fix secondary core boot in SMP

There are multiple factors adding to the issue in different
configurations:

- commit 17290231df16eeee ("xtensa: add fixup for double exception raised
in window overflow") added function window_overflow_restore_a0_fixup to
double exception vector overlapping reset vector location of secondary
processor cores.
- on MMUv2 cores RESET_VECTOR1_VADDR may point to uncached kernel memory
making code overlapping depend on cache type and size, so that without
cache or with WT cache reset vector code overwrites double exception
code, making issue even harder to detect.
- on MMUv3 cores RESET_VECTOR1_VADDR may point to unmapped area, as
MMUv3 cores change virtual address map to match MMUv2 layout, but
reset vector virtual address is given for the original MMUv3 mapping.
- physical memory region of the secondary reset vector is not reserved
in the physical memory map, and thus may be allocated and overwritten
at arbitrary moment.

Fix it as follows:

- move window_overflow_restore_a0_fixup code to .text section.
- define RESET_VECTOR1_VADDR so that it points to reset vector in the
cacheable MMUv2 map for cores with MMU.
- reserve reset vector region in the physical memory map. Drop separate
literal section and build mxhead.S with text section literals.

Cc: <stable@vger.kernel.org>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>

+19 -16
+5 -4
arch/xtensa/include/asm/vectors.h
··· 61 61 #define LOAD_MEMORY_ADDRESS 0xD0003000 62 62 #endif 63 63 64 + #define RESET_VECTOR1_VADDR (VIRTUAL_MEMORY_ADDRESS + \ 65 + XCHAL_RESET_VECTOR1_PADDR) 66 + 64 67 #else /* !defined(CONFIG_MMU) */ 65 68 /* MMU Not being used - Virtual == Physical */ 66 69 ··· 76 73 /* Loaded just above possibly live vectors */ 77 74 #define LOAD_MEMORY_ADDRESS (PLATFORM_DEFAULT_MEM_START + 0x3000) 78 75 76 + #define RESET_VECTOR1_VADDR (XCHAL_RESET_VECTOR1_VADDR) 77 + 79 78 #endif /* CONFIG_MMU */ 80 79 81 80 #define XC_VADDR(offset) (VIRTUAL_MEMORY_ADDRESS + offset) ··· 88 83 #define RESET_VECTOR_VECOFS (XCHAL_RESET_VECTOR_VADDR - \ 89 84 VECBASE_RESET_VADDR) 90 85 #define RESET_VECTOR_VADDR XC_VADDR(RESET_VECTOR_VECOFS) 91 - 92 - #define RESET_VECTOR1_VECOFS (XCHAL_RESET_VECTOR1_VADDR - \ 93 - VECBASE_RESET_VADDR) 94 - #define RESET_VECTOR1_VADDR XC_VADDR(RESET_VECTOR1_VECOFS) 95 86 96 87 #if defined(XCHAL_HAVE_VECBASE) && XCHAL_HAVE_VECBASE 97 88
+1
arch/xtensa/kernel/Makefile
··· 16 16 obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o 17 17 18 18 AFLAGS_head.o += -mtext-section-literals 19 + AFLAGS_mxhead.o += -mtext-section-literals 19 20 20 21 # In the Xtensa architecture, assembly generates literals which must always 21 22 # precede the L32R instruction with a relative offset less than 256 kB.
+8 -1
arch/xtensa/kernel/setup.c
··· 334 334 extern char _Level6InterruptVector_text_start; 335 335 extern char _Level6InterruptVector_text_end; 336 336 #endif 337 - 337 + #ifdef CONFIG_SMP 338 + extern char _SecondaryResetVector_text_start; 339 + extern char _SecondaryResetVector_text_end; 340 + #endif 338 341 339 342 340 343 #ifdef CONFIG_S32C1I_SELFTEST ··· 509 506 __pa(&_Level6InterruptVector_text_end), 0); 510 507 #endif 511 508 509 + #ifdef CONFIG_SMP 510 + mem_reserve(__pa(&_SecondaryResetVector_text_start), 511 + __pa(&_SecondaryResetVector_text_end), 0); 512 + #endif 512 513 parse_early_param(); 513 514 bootmem_init(); 514 515
+3 -1
arch/xtensa/kernel/vectors.S
··· 478 478 479 479 ENDPROC(_DoubleExceptionVector) 480 480 481 + .end literal_prefix 482 + 483 + .text 481 484 /* 482 485 * Fixup handler for TLB miss in double exception handler for window owerflow. 483 486 * We get here with windowbase set to the window that was being spilled and ··· 590 587 591 588 ENDPROC(window_overflow_restore_a0_fixup) 592 589 593 - .end literal_prefix 594 590 /* 595 591 * Debug interrupt vector 596 592 *
+2 -10
arch/xtensa/kernel/vmlinux.lds.S
··· 166 166 RELOCATE_ENTRY(_DebugInterruptVector_text, 167 167 .DebugInterruptVector.text); 168 168 #if defined(CONFIG_SMP) 169 - RELOCATE_ENTRY(_SecondaryResetVector_literal, 170 - .SecondaryResetVector.literal); 171 169 RELOCATE_ENTRY(_SecondaryResetVector_text, 172 170 .SecondaryResetVector.text); 173 171 #endif ··· 280 282 281 283 #if defined(CONFIG_SMP) 282 284 283 - SECTION_VECTOR (_SecondaryResetVector_literal, 284 - .SecondaryResetVector.literal, 285 - RESET_VECTOR1_VADDR - 4, 286 - SIZEOF(.DoubleExceptionVector.text), 287 - .DoubleExceptionVector.text) 288 - 289 285 SECTION_VECTOR (_SecondaryResetVector_text, 290 286 .SecondaryResetVector.text, 291 287 RESET_VECTOR1_VADDR, 292 - 4, 293 - .SecondaryResetVector.literal) 288 + SIZEOF(.DoubleExceptionVector.text), 289 + .DoubleExceptionVector.text) 294 290 295 291 . = LOADADDR(.SecondaryResetVector.text)+SIZEOF(.SecondaryResetVector.text); 296 292