Commit ab45fb14 authored by Max Filippov's avatar Max Filippov

xtensa: fix secondary core boot in SMP

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

- commit 17290231 ("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: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent a9df9338
...@@ -61,6 +61,9 @@ static inline unsigned long xtensa_get_kio_paddr(void) ...@@ -61,6 +61,9 @@ static inline unsigned long xtensa_get_kio_paddr(void)
#define LOAD_MEMORY_ADDRESS 0xD0003000 #define LOAD_MEMORY_ADDRESS 0xD0003000
#endif #endif
#define RESET_VECTOR1_VADDR (VIRTUAL_MEMORY_ADDRESS + \
XCHAL_RESET_VECTOR1_PADDR)
#else /* !defined(CONFIG_MMU) */ #else /* !defined(CONFIG_MMU) */
/* MMU Not being used - Virtual == Physical */ /* MMU Not being used - Virtual == Physical */
...@@ -73,6 +76,8 @@ static inline unsigned long xtensa_get_kio_paddr(void) ...@@ -73,6 +76,8 @@ static inline unsigned long xtensa_get_kio_paddr(void)
/* Loaded just above possibly live vectors */ /* Loaded just above possibly live vectors */
#define LOAD_MEMORY_ADDRESS (PLATFORM_DEFAULT_MEM_START + 0x3000) #define LOAD_MEMORY_ADDRESS (PLATFORM_DEFAULT_MEM_START + 0x3000)
#define RESET_VECTOR1_VADDR (XCHAL_RESET_VECTOR1_VADDR)
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
#define XC_VADDR(offset) (VIRTUAL_MEMORY_ADDRESS + offset) #define XC_VADDR(offset) (VIRTUAL_MEMORY_ADDRESS + offset)
...@@ -84,10 +89,6 @@ static inline unsigned long xtensa_get_kio_paddr(void) ...@@ -84,10 +89,6 @@ static inline unsigned long xtensa_get_kio_paddr(void)
VECBASE_RESET_VADDR) VECBASE_RESET_VADDR)
#define RESET_VECTOR_VADDR XC_VADDR(RESET_VECTOR_VECOFS) #define RESET_VECTOR_VADDR XC_VADDR(RESET_VECTOR_VECOFS)
#define RESET_VECTOR1_VECOFS (XCHAL_RESET_VECTOR1_VADDR - \
VECBASE_RESET_VADDR)
#define RESET_VECTOR1_VADDR XC_VADDR(RESET_VECTOR1_VECOFS)
#if defined(XCHAL_HAVE_VECBASE) && XCHAL_HAVE_VECBASE #if defined(XCHAL_HAVE_VECBASE) && XCHAL_HAVE_VECBASE
#define USER_VECTOR_VADDR XC_VADDR(XCHAL_USER_VECOFS) #define USER_VECTOR_VADDR XC_VADDR(XCHAL_USER_VECOFS)
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_SMP) += smp.o mxhead.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_SMP) += smp.o mxhead.o
obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
AFLAGS_head.o += -mtext-section-literals AFLAGS_head.o += -mtext-section-literals
AFLAGS_mxhead.o += -mtext-section-literals
# In the Xtensa architecture, assembly generates literals which must always # In the Xtensa architecture, assembly generates literals which must always
# precede the L32R instruction with a relative offset less than 256 kB. # precede the L32R instruction with a relative offset less than 256 kB.
......
...@@ -334,7 +334,10 @@ extern char _Level5InterruptVector_text_end; ...@@ -334,7 +334,10 @@ extern char _Level5InterruptVector_text_end;
extern char _Level6InterruptVector_text_start; extern char _Level6InterruptVector_text_start;
extern char _Level6InterruptVector_text_end; extern char _Level6InterruptVector_text_end;
#endif #endif
#ifdef CONFIG_SMP
extern char _SecondaryResetVector_text_start;
extern char _SecondaryResetVector_text_end;
#endif
#ifdef CONFIG_S32C1I_SELFTEST #ifdef CONFIG_S32C1I_SELFTEST
...@@ -506,6 +509,10 @@ void __init setup_arch(char **cmdline_p) ...@@ -506,6 +509,10 @@ void __init setup_arch(char **cmdline_p)
__pa(&_Level6InterruptVector_text_end), 0); __pa(&_Level6InterruptVector_text_end), 0);
#endif #endif
#ifdef CONFIG_SMP
mem_reserve(__pa(&_SecondaryResetVector_text_start),
__pa(&_SecondaryResetVector_text_end), 0);
#endif
parse_early_param(); parse_early_param();
bootmem_init(); bootmem_init();
......
...@@ -478,6 +478,9 @@ _DoubleExceptionVector_handle_exception: ...@@ -478,6 +478,9 @@ _DoubleExceptionVector_handle_exception:
ENDPROC(_DoubleExceptionVector) ENDPROC(_DoubleExceptionVector)
.end literal_prefix
.text
/* /*
* Fixup handler for TLB miss in double exception handler for window owerflow. * Fixup handler for TLB miss in double exception handler for window owerflow.
* We get here with windowbase set to the window that was being spilled and * We get here with windowbase set to the window that was being spilled and
...@@ -587,7 +590,6 @@ ENTRY(window_overflow_restore_a0_fixup) ...@@ -587,7 +590,6 @@ ENTRY(window_overflow_restore_a0_fixup)
ENDPROC(window_overflow_restore_a0_fixup) ENDPROC(window_overflow_restore_a0_fixup)
.end literal_prefix
/* /*
* Debug interrupt vector * Debug interrupt vector
* *
......
...@@ -166,8 +166,6 @@ SECTIONS ...@@ -166,8 +166,6 @@ SECTIONS
RELOCATE_ENTRY(_DebugInterruptVector_text, RELOCATE_ENTRY(_DebugInterruptVector_text,
.DebugInterruptVector.text); .DebugInterruptVector.text);
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
RELOCATE_ENTRY(_SecondaryResetVector_literal,
.SecondaryResetVector.literal);
RELOCATE_ENTRY(_SecondaryResetVector_text, RELOCATE_ENTRY(_SecondaryResetVector_text,
.SecondaryResetVector.text); .SecondaryResetVector.text);
#endif #endif
...@@ -282,17 +280,11 @@ SECTIONS ...@@ -282,17 +280,11 @@ SECTIONS
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
SECTION_VECTOR (_SecondaryResetVector_literal,
.SecondaryResetVector.literal,
RESET_VECTOR1_VADDR - 4,
SIZEOF(.DoubleExceptionVector.text),
.DoubleExceptionVector.text)
SECTION_VECTOR (_SecondaryResetVector_text, SECTION_VECTOR (_SecondaryResetVector_text,
.SecondaryResetVector.text, .SecondaryResetVector.text,
RESET_VECTOR1_VADDR, RESET_VECTOR1_VADDR,
4, SIZEOF(.DoubleExceptionVector.text),
.SecondaryResetVector.literal) .DoubleExceptionVector.text)
. = LOADADDR(.SecondaryResetVector.text)+SIZEOF(.SecondaryResetVector.text); . = LOADADDR(.SecondaryResetVector.text)+SIZEOF(.SecondaryResetVector.text);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment