Skip to content

xtensa: build: add support for build with upstream llvm clang with binutils backend#108765

Draft
lgirdwood wants to merge 43 commits into
zephyrproject-rtos:mainfrom
lgirdwood:clang-dev
Draft

xtensa: build: add support for build with upstream llvm clang with binutils backend#108765
lgirdwood wants to merge 43 commits into
zephyrproject-rtos:mainfrom
lgirdwood:clang-dev

Conversation

@lgirdwood

Copy link
Copy Markdown

Still very much early WIP that requires more testing and development but Zephyr and SOF now booting on qemu ACE 30 simulator and ztests passing. Will stay draft atm, but a heads up for any other xtensa users interested in llvm clang.

This PR does need more effort, but end result could be that Zephyr SDK only requires 1 xtensa compiler as clang can support different xtensa configs on the command line.

This work currently uses GNU binutils for assembly and linking as binutils is already fully ISA configured for each xtensa target based on the Cadence GPL overlay patches, i.e. its ready to go for testing a working front end. Subsequent work can help complete llvm linker/assembler support so that binutils no longer required.

This uses the LLVM patches here: llvm/llvm-project@main...lgirdwood:llvm-project:upstream/dev

@cgturner1 fyi - I will try and keep this ticking along, but its best effort atm.

@lgirdwood

Copy link
Copy Markdown
Author

SOF PR for anyone interested: thesofproject/sof#10759

@sonarqubecloud

Copy link
Copy Markdown

@lgirdwood

lgirdwood commented Jun 14, 2026

Copy link
Copy Markdown
Author

@cgturner1 @dcpleung fyi - now builds working SOF for multiple platforms using single compiler but still uses SDK binutils today.
Rust working too, we can build and link a template audio module in rust that passes ztests.
Hifi3/4 intrinsics & FLIX working contributed by @hliao8

lrgirdwo and others added 23 commits July 12, 2026 21:00
…mpatibility

Configure compiler options for Clang:
- Set Clang-specific Link-Time Optimization (LTO) flags (-flto=thin
  for parallel and -flto=full for single-threaded optimization) instead
  of the GCC-specific -flto=auto and -flto=1 formats.
- Restrict the -mno-global-merge warning option to ARM/ARM64 targets
  to prevent unused argument diagnostic warnings on other architectures.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Add LLVM compiler and LLD linker configurations under cmake/toolchain/llvm
to support native, zero-SDK LLVM builds:
- Map Zephyr SDK board target names (e.g. intel_ace30_ptl) to their
  respective upstream LLVM processor names (e.g. -mcpu=intel_ace30_adsp).
- Enable the integrated assembler (-fintegrated-as) and force DWARFv4
  debug symbols (-gdwarf-4) for offline kernel object scanner compatibility.
- Override compiler_set_linker_properties to search LLVM's internal paths
  and link against libclang_rt.builtins instead of GCC's libgcc.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…verrides

Configure linker execution templates:
- Use CMAKE_C_COMPILER and CMAKE_CXX_COMPILER directly as linker drivers,
  unless an external XTENSA_GCC compiler override is set.
- Cleans up formatting and whitespace inside the LLD target macros.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…for ARM

Configure LLEXT compilation options and stripping flags for ARM architectures:
- Add LLEXT compiler options (LLEXT_REMOVE_FLAGS / LLEXT_APPEND_FLAGS) to
  cmake/compiler/clang/target_arm.cmake for Clang ARM builds.
- Configure add_llext_target to strip .ARM.exidx* and .ARM.extab* exception
  handling and unwind table sections from the relocatable LLEXT module ELF file.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When compiling Zephyr with Clang/LLVM for Xtensa, the GNU 'ld.bfd'
linker fails because it cannot natively ingest LLVM bitcode or certain
LLVM-generated objects seamlessly in this configuration. We remove the
forced '-fuse-ld=bfd' flag and explicitly add '-fuse-ld=lld' for
Xtensa LLVM LLEXT targets to allow the build to complete using the
integrated LLD linker.
…TARGET

The linker path was hardcoded to the ace15 SDK toolchain, breaking all
non-ace15 Xtensa LLVM builds.  Derive the ld binary path from
XTENSA_TOOLCHAIN_TARGET so tgl (intel_tgl_adsp), ace15 and any future
core each use their matching SDK ld.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… offsets

Configure compiler include directories and vector layout generator offsets
for native toolchain target mapping:
- Change include directories in arch/xtensa/core/CMakeLists.txt from
  CONFIG_SOC to CONFIG_SOC_TOOLCHAIN_NAME to map correctly under native
  LLVM unified architecture builds.
- Rewrite vector generator absolute offset assignments in gen_vectors.py
  from absolute offsets (". = 0xYYY") to be relative to the base symbol
  (". = z_xtensa_vecbase + 0xYYY") to prevent LLD location counter errors.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Enforce auto-litpools configuration in the reset vector:
- Wrap reset_vector.S assembly with ".begin auto-litpools" and
  ".end auto-litpools" when compiling under Clang.
- Unlike GAS which arranges literal pools automatically, Clang's
  Integrated Assembler (IAS) has no default layout strategy for assembly
  literal placement, throwing "literal pool empty" errors unless directed.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Adapt syscall ID validation branches:
- In userspace.S, replace a long conditional branch (bgeu) targeting
  distant labels with a short negated branch (bltu) over an absolute jump (j).
- Unlike GAS which automatically relaxes long branches under the hood, IAS
  does not relax conditional branches with long offsets, throwing compilation
  operand range exceptions.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- CMake: Pass -mtext-section-literals to ensure strings are stored correctly in text sections.
- Assembly: Add .literal_position to crt1.S to satisfy LLVM IAS requirements.
- Assembly: Replace custom rsr.eps/epc macro instructions with standard rsr instructions for IAS compatibility.
- Memory: Clean up ptables.c unused variables.
…atable

Configure section flags for the ADSP boot entry points:
- In both IMR and primary ADSP boot.c inline assembly, change the section
  attribute declaration flags from "x" (executable) to "ax" (allocatable
  + executable).
- Unlike GCC/GAS where the assembler automatically infers allocatable
  status for code sections, Clang/IAS does not automatically apply
  SHF_ALLOC to executable sections. If the boot section is not allocatable,
  the target linker excludes it from final memory image generation, failing
  to boot.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…r LLD

Configure linker region layout macros for simulator builds:
- In xtensa-dc233c.ld, replace generic location-counter-relative macros
  (SEGSTART_CACHED/SEGSTART_UNCACHED) with symbol-explicit region mapping
  macros (ADDR_CACHED/ADDR_UNCACHED).
- Under LLVM/LLD, assigning different memory alias addresses using the
  location counter '.' triggers section overlap or counter inconsistency
  warnings. Explicitly mapping section addresses via symbols avoids this
  linking constraint.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… notes

Configure Intel ADSP linker scripts for LLVM/LLD compatibility:
- Replaces generic SEGSTART_CACHED/SEGSTART_UNCACHED macros with symbol-explicit
  ADDR_CACHED(sym)/ADDR_UNCACHED(sym) mapping macros.
- Separates literal (*.literal, *.literal.*) and text (*.text, *.text.*) section
  wildcards to ensure LLD groups literals consistently ahead of text sections,
  preserving Xtensa L32R reach requirements.
- Explicitly discards stack executability notes (*.note.GNU-stack) generated by
  Clang to prevent orphan section compiler warnings on older target linkers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Configure the IMR boot loader stack mapping in the MMU page table:
- In both mmu_ace30.c and mmu_ace40.c, add the XTENSA_MMU_MAP_SHARED
  attribute to the IMR boot stack region mapping.
- This maps the boot stack in Ring 3 (shared ASID 4) instead of Ring 0
  (ASID 1).
- This ensures that register window exception handlers (which execute
  spills/fills using s32e/l32e with Ring 1 privilege) can successfully
  match the TLB entries for the stack, resolving early boot LoadStoreTLBMiss
  exceptions and preventing triple faults when the L2 page table page is
  not mapped in the TLB.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Remove '(!ari)' custom memory region attributes, which are GNU ld specific and crash LLD.
- Explicitly place .literal sections alongside .text across Intel, AMD, NXP, and Cadence DSP linkers.
- Ensure correct placement of .struct and .symtab internal sections.
- Provide the 'soc_cpus_active' array even when CONFIG_MP_MAX_NUM_CPUS == 1 to fix undefined reference errors during linking.
- Explicitly add .literal matching for .imr regions on Intel platforms.
- Remove remaining '(!ari)' attributes from NXP i.MX linker scripts.
LLVM organizes sections differently from GCC, sometimes placing initialization code or structures into the Bootloader Isolated Memory Regions (IMR).
Without these mappings, LLVM-compiled firmware triggers MMU faults (Instruction Fetch or Load/Store exceptions) during early boot.

This patch adds explicit XTENSA_MMU_PERM_X and XTENSA_MMU_PERM_W mappings for IMR_BOOT_LDR_LIT_BASE, IMR_BOOT_LDR_TEXT_BASE, and IMR_BOOT_LDR_DATA_BASE on ACE30 and ACE40 SOCs.
The commit c3c8402 ('soc: intel_adsp: Configure cached/uncached mappings and discard stack notes') replaced generic SEGSTART_CACHED/SEGSTART_UNCACHED macros with ADDR_CACHED(sym)/ADDR_UNCACHED(sym) mapping macros. However, it used the static 'z_mapped_end' or '__bss_end' symbols instead of mapping the current location counter '.' after moving it to the end of SRAM. Under LLD (and under specific alignment configurations), this resets the location counter back to the end of the firmware image, resulting in a heap size of 0. When heap allocation occurs, subtracting the shared buffer size underflows, causing memory corruption (allocations overlap with the code segment).

Fix this by mapping the current location counter '.' to cached/uncached memory when defining the heap end, heap sentry, and image RAM end markers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Initialize CPENABLE in _start before any C code runs so that all
coprocessor units are enabled from the first instruction fetch. Without
this, Clang-generated code that uses coprocessor registers (FPU, HiFi)
before the Zephyr kernel enables them causes an illegal-instruction
exception at boot.

When CONFIG_XTENSA_LAZY_HIFI_SHARING is enabled only the non-AudioEngine
coprocessors are enabled here; the AudioEngine CP is managed by the lazy
sharing framework.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Clang's Windowed ABI codegen stores the thread switch_handle at a
different offset within the thread struct than GCC expects in the
assembly context switch path.

- xtensa_asm2_util.S: add the ___thread_t_switch_handle_OFFSET to a3
  before storing a1 so the saved stack pointer lands in switch_handle
  rather than at the base of the thread struct.

- kernel/include/kswap.h: pass the thread pointer directly to
  arch_switch() as the switch_from argument under CONFIG_XTENSA (the
  assembly side derives switch_handle via the offset above). Other
  architectures continue to pass &old_thread->switch_handle. Also add
  compiler barriers to prevent Clang from eliding the old/new thread
  pointer loads across the asm boundary.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When building LLEXT shared libraries with Clang/LLD two problems arise:

1. The Xtensa LLD linker rejects relocations into read-only sections
   (.rodata, _log_const, .module, .exported_sym) with "dangerous
   relocation in read-only section". Worked around by making those
   sections writable via objcopy before linking.

2. l32r literals must appear before their use in the .text section.
   The default section order places .rodata after .text, violating
   this. A linker script overlay (llext_shared.ld) places .rodata
   before .text and merges all .literal.* into .text.

Add llext-link-wrapper.sh to orchestrate: mark sections writable,
link with GCC -mtext-section-literals + linker script, then strip
the X flag from .rodata in the output so llext_link_helper.py does
not misclassify it as executable.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
lrgirdwo and others added 20 commits July 12, 2026 21:02
Clang auto-vectorizes the inner loops in memcpy() and memset() using
Xtensa SIMD (BB, BBQ) instructions. These are not available on all
Xtensa cores that SOF targets and produce an illegal-instruction
exception when executed on cores without the vector engine.

Add '#pragma clang loop vectorize(disable)' before each loop in
memcpy() and memset() to prevent auto-vectorization. This has no
effect on GCC builds.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
debug_window.c: lazily initialize the ADSP debug window on first use.
When the debug window descriptor array starts with 0xffffffff (uncleared
by the ROM), clear the entire window before any slot is allocated. This
prevents stale ROM data from being misinterpreted as valid slot headers
on cold boot.

soc_util.h (bmemcpy/bbzero): use 32-bit word-aligned copies in the boot
loader memory routines instead of byte-at-a-time loops. Clang strict
aliasing analysis rejects the previous uint8_t pointer casts on aligned
buffers, and the word copy is faster for the large IMR-to-DRAM firmware
image copies performed at boot.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…register

The GPDMA ownership register is a 16-bit MMIO register. Using
sys_write32() triggers a load/store width exception under LLVM strict
alignment checking. Replace with sys_write16() to match the actual
register width.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Replace arch_num_cpus() with CONFIG_MP_MAX_NUM_CPUS in dw_ace_irq_enable
and dw_ace_irq_disable loops.

On platforms with CONFIG_SOC_HAS_RUNTIME_NUM_CPUS=y, arch_num_cpus()
evaluates to the dynamic global variable soc_num_cpus.
When compiling this loop with GCC 14.3.0 for Xtensa, the compiler
generates a buggy loop trip count calculation that evaluates to 0
iterations at runtime. Consequently, Designware interrupts (such as
Host IPC and HDA/DMA) are never enabled.

Using the static compile-time constant CONFIG_MP_MAX_NUM_CPUS (5)
prevents the compiler bug, enabling interrupts to be correctly delivered.
Select XTENSA_CPU_HAS_HIFI3 for the CAVS 2.5 (TGL) SOC series so that
the XTENSA_HIFI_SHARING infrastructure knows the coprocessor is present.
Without this the HiFi AE register file is never saved/restored across
context switches, corrupting the state of any thread that uses HiFi
instructions.

Also fix the heap sentry calculation in the linker script: the L2 SRAM
boundary was not being applied to the uncached address alias, placing
_heap_sentry in the wrong region for the cavs2.5 memory map.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
The existing xchal_cp1_load/store GAS macros in xtensa_hifi.S cannot be
assembled by LLVM clang for intel_tgl_adsp: the tie-asm.h included by the
cavs2.5 SDK uses an older macro form (RG-2017.8) whose xchal_sa_start /
xchal_sa_align pseudo-ops are not recognised by the LLVM integrated
assembler.  Every instruction after them cascades as an unknown mnemonic.

Provide a separate HiFi3 code path (guarded by CONFIG_XTENSA_CPU_HAS_HIFI3)
that uses explicit ae_s64.i / ae_l64.i for aed0-aed15 and rur/wur for the
six scalar AE state registers (AE_OVF_SAR, AE_BITHEAD, AE_TS_FTS_BU_BP,
AE_CW_SD_NO, AE_CBEGIN0, AE_CEND0).  The u0-u3 alignment scratch registers
(ae_salign64.i / ae_lalign64.i) are omitted: LLVM-compiled SOF code uses
only aligned ae_s64.i / ae_l64.i, so u0-u3 never carry live state across a
context switch.  Additionally, ae_lalign64.i and ae_salign64.i are FLIX
bundles whose 8-byte encodings are absent from the clang TGL encoder table,
so skipping them avoids a further assembler issue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When building with LLVM clang, several SOF source files (copier_dai.c,
channel_map.c) and Zephyr core (bitarray.c) emit calls to __popcountsi2.
The precompiled libgcc.a version places its literal pool in a separate
.literal section; on large Xtensa images (>~700 KB text) the l32r
relocation from the code to that section exceeds the ±512 KB l32r range,
causing a fatal link error.

Add a popcount.c to the xtensa/core library, which is already compiled
with -mtext-section-literals (see CMakeLists.txt).  Text-section literals
are interleaved with code, guaranteeing they are always within l32r reach.
This definition is linked before libgcc is searched, so the problematic
libgcc object is never pulled in.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…d sections

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…addr=0

For relocatable ELFs (ET_REL), all loadable sections have sh_addr=0
because no base address is assigned at link time. The previous code
took the sh_addr < 0x08000000 branch and called llext_peek(ldr,
shdr->sh_offset), which returns a pointer into the file image at the
section's file offset.

On Intel ACE30 (PTL) where the LLEXT is loaded from IMR, llext_peek()
returns a physical IMR address such as 0x001D003C — the raw file offset
of the target section. This IMR address is then used as the relocation
target for R_XTENSA_32, writing the pre-relocation file offset into the
GOT/data instead of the runtime DRAM address where the section was
actually loaded. On ACE30 (MMU enabled) this causes an ExcVaddr fault;
on ACE15 (no MMU) the bad address silently corrupts all relocations.

Fix:
- Always check sect_map first. If the section has been loaded into DRAM
  (mem_idx != LLEXT_MEM_COUNT), return the runtime DRAM address from
  ext->mem[mem_idx] + offset.
- Only fall back to llext_peek() for sections with a valid non-zero
  sh_addr >= 0x08000000 (pre-located ROM/IMR sections). ET_REL sections
  (sh_addr=0) return NULL from this path.

The >= 0x08000000 threshold correctly matches the comment and intended
semantics; the original code had the condition inverted (< 0x08000000),
causing all ET_REL sections not in sect_map to return an IMR file-offset
pointer instead of NULL.

Fixes crash seen as win0[0]=0x01009B01, win0[1]=0x001D003C on PTL/ACE30.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
On Intel ADSP targets there is frequently no usable console or mtrace
output when the firmware takes a fatal exception very early or inside a
crash loop, which makes the faulting PC effectively invisible. The host
SOF driver, however, prints HP-SRAM window0[0] as "Firmware state" and
window0[1] as "status/error code" on an IPC timeout.

Add CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB (default n, depends on
SOC_FAMILY_INTEL_ADSP) which, when enabled, records the faulting PC,
exception cause, faulting virtual address and the faulting instruction
word into window0 via its uncached alias from xtensa_excint1_c().
Only the first fatal exception is latched so the original
fault survives a crash loop, and window0[3] counts exceptions.

Query the window0 base address and uncached region via Device Tree macros
(HP_SRAM_WIN0_BASE and CONFIG_INTEL_ADSP_UNCACHED_REGION) to prevent using
hardcoded magic pointers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When a double exception escalates to a triple fault (escaping the CPU),
record the EPC1, double-exception EXCCAUSE, and DEPC into HP-SRAM
window0 via its uncached alias. This is a lightweight tracing aid that
can be enabled in production builds to diagnose fatal CPU locks and
double faults.

Add CONFIG_XTENSA_ADSP_TRIPLE_FAULT_BREADCRUMB (default y, depends on
SOC_FAMILY_INTEL_ADSP) to govern this feature independently of general
fatal exception breadcrumbs.

Construct the window0 uncached base address and the 0xdb1e0000 marker
via bit shifts and additions in assembly rather than movi/l32r literals,
to ensure LLVM IAS emits no out-of-range l32r relocations in the
triple-fault handler (where literals pools may be unreachable).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Add a Kconfig choice (XTENSA_ADSP_FATAL_BREADCRUMB_DATA) to select which diagnostic information is written to window0[1] (which is printed in dmesg as the 'status/error code' on IPC timeout):
- Exception cause (default)
- Faulting virtual address (excvaddr)
- Caller return address (a0)

Also fix compilation under Clang by:
- Including <adsp_memory.h> in vector_handlers.c to define L2_SRAM_BASE.
- Constructing the uncached memory window base (0x40024000/0x5e024000) and signature dynamically using bit shifts and additions in assembly (xtensa_asm2_util.S) to avoid literal generation under Clang's Integrated Assembler.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
The breadcrumb code in xtensa_excint1_c() reads the faulting instruction
word via: win0[4] = *(volatile uint32_t *)(bsa->pc & ~3)

This is unsafe when the exception was caused by a bad function pointer
or corrupted GOT entry — in that case bsa->pc itself is unmapped, so
dereferencing it triggers a double exception inside the exception handler
producing the 0xdb1e001d triple fault signature.

Guard the read with a range check against the DSP SRAM window
[0xa0000000, 0xa2000000). PCs outside this range are skipped; win0[0]
already contains the faulting PC so no diagnostic information is lost.

This makes the breadcrumb infrastructure safe on both ACE15 (no MMU,
bad PC silently accesses wrong memory) and ACE30 (MMU, bad PC faults).

Fixes: 98cafd9 (xtensa: adsp: record fatal exception breadcrumbs in HP-SRAM window0)
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ption

Root cause analysis of the 0xdb1e001d triple fault on ACE15/ARL-S:

1. CONFIG_XTENSA_LAZY_HIFI_SHARING clears the HiFi4 AudioEngineLX CP bit
   from CPENABLE on every thread context switch (xtensa_asm2_util.S:317).

2. LLVM generates HiFi4 ae_* instructions (ae_slaa32, ae_mulf32r etc.)
   in print_fatal_exception and its LOG/printk callees when compiling for
   the xtensa-intel_ace15_mtpm target. This happens at all optimisation
   levels, including -O0, as the Xtensa backend uses HiFi4 for scalar
   arithmetic on this core.

3. When the exception handler reaches print_fatal_exception with the HiFi4
   CP bit cleared, the first ae_* instruction triggers EXCCAUSE_CP_DISABLED.
   Since PS.EXCM is set in the exception handler, this becomes a double
   exception -> triple fault, writing 0xdb1e001d to HP-SRAM window0.

The CROSS_STACK_CALL assembly fix (wsr.cpenable before callx4) helps for
fresh exceptions, but if the scheduler ran lazy HiFi sharing between the
original fault and print_fatal_exception being reached, CPENABLE may be
cleared again by an intermediate code path.

Fix: explicitly set CPENABLE to all-ones immediately before the call to
print_fatal_exception in xtensa_excint1_c. Use XCHAL_CP_NUM to compute
the correct bitmask for this core (all CP bits enabled) rather than
hardcoding 0xFF. Guard with XCHAL_HAVE_CP to keep pure-scalar cores clean.

Also: retain wsr.cpenable in CROSS_STACK_CALL as defense-in-depth and
revert the debug EPC1/DEPC breadcrumb changes to their original state.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…dler

LLVM auto-vectorizes C code using HiFi4 ae_* instructions (coprocessor
CP1) throughout the exception handler (xtensa_excint1_c, print_fatal_
exception, and LOG calls). If CPENABLE doesn't have CP1 set when an
exception fires — for example on a secondary CPU core before its CPENABLE
is initialized, or after a context switch cleared it — the first HiFi4
ae_* instruction causes EXCCAUSE_CP_DISABLED(1) (exccause=29) as a double
exception. This escalates to a triple fault, producing the 0xdb1e001d
status visible in HP-SRAM window0.

A runtime wsr.cpenable inside xtensa_excint1_c() itself is insufficient
because LLVM places HiFi4 instructions in the function prologue before the
first C statement executes.

Fix: add movi+wsr.cpenable+rsync in pure assembly just before the callx4
into the C handler in the CROSS_STACK_CALL macro in xtensa_asm2.inc.S.
At this point we are still in safe scalar assembly with no HiFi register
usage, so the wsr.cpenable reliably fires before any C code runs.
Guard with XCHAL_HAVE_CP to keep configurations without coprocessors
unchanged.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…0] < 0xa0000000

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… if TRIPLE_FAULT_BREADCRUMB is enabled

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… of CONFIG_MP_MAX_NUM_CPUS

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants