Skip to content

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

Draft
lgirdwood wants to merge 47 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 47 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

@lgirdwood
lgirdwood force-pushed the clang-dev branch 2 times, most recently from 13da555 to 46bfe2e Compare July 12, 2026 20:04
lrgirdwo and others added 22 commits July 18, 2026 22:05
Configure the target triple and -mcpu for Xtensa LLVM builds:
- Resolve XTENSA_TOOLCHAIN_TARGET from CONFIG_SOC_TOOLCHAIN_NAME or
  the XTENSA_TOOLCHAIN_TARGET environment variable.
- Map SDK toolchain target names to upstream LLVM -mcpu names via a
  small table (intel_ace15_mtpm -> intel_ace15_adsp, etc.).
- Set triple to xtensa-<target>_zephyr-elf, select LLD linker and
  llvm bintools, and configure CROSS_COMPILE_TARGET accordingly.
- Append core Clang flags: -mcpu, -D__XCC__, -D__XCC_CLANG__,
  -fintegrated-as, -gdwarf-4.

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

For Xtensa LLVM builds, override compiler_set_linker_properties() to
link against LLVM's compiler-rt builtins (libclang_rt.builtins) instead
of libgcc. The compiler-rt builtins ship with the LLVM toolchain and
cover all Xtensa intrinsics needed by Zephyr and SOF.

Also derive the per-core SDK linker binary (XTENSA_SDK_LD) from
XTENSA_TOOLCHAIN_TARGET so that tgl, ace15, ace30 and future cores each
use their matching SDK ld binary rather than a hardcoded ace15 path.

Configure CMAKE_REQUIRED_FLAGS, CMAKE_EXE_LINKER_FLAGS and
CMAKE_ASM_FLAGS for the Xtensa compile-test and assembly steps.

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>
… default

When building Zephyr with Clang/LLVM for Xtensa, ld.bfd cannot natively
ingest LLVM-generated objects. Disable the forced -fuse-ld=bfd flag in
cmake/linker/ld/target.cmake so LLD is used instead.

Also disable FLIX VLIW bundling in the LLVM toolchain target when
CONFIG_COMPILER_CODEGEN_VLIW_DISABLED is set. The LLVM FLIX packetizer
generates invalid instruction pairs because the hardware slot constraints
are not yet fully modelled; FLIX can be re-enabled per-build by adding
'-Xclang -target-feature -Xclang +flix' to CMAKE_C_FLAGS.

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>
Configure CMAKE_C/CXX_CREATE_SHARED_LIBRARY and _MODULE to use the
llext-link-wrapper.sh script for Xtensa LLVM LLEXT shared-library
builds. The wrapper addresses two LLD issues:

  1. Xtensa LLD rejects relocations into read-only sections (.rodata,
     _log_const, .module, .exported_sym) with 'dangerous relocation in
     read-only section'. The wrapper uses objcopy to mark those sections
     writable before linking.

  2. l32r literals must appear before their use in .text. The default
     section order places .rodata after .text, violating this constraint.
     The wrapper links with -mtext-section-literals so literals are
     interleaved with code, and strips the X flag from .rodata afterwards
     to prevent llext_link_helper.py from misclassifying it as executable.

Pass -fuse-ld=lld so the GCC wrapper driver uses LLD for the final link.
Disable ccache for link steps as it cannot cache the wrapper output.

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>
When building with Clang/LLVM, all l32r literal loads must be within
+/-512 KB of the instruction that references them. With large Xtensa
images the literals placed in a separate .literal section by the GAS
default can exceed this range, causing link-time relocation errors.

-mtext-section-literals instructs the compiler to interleave literal
pools with code in the .text section, guaranteeing they are always
within l32r reach regardless of image size.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Under native LLVM builds the HAL module dir is keyed by
CONFIG_SOC_TOOLCHAIN_NAME (e.g. intel_ace30_ptl), which can differ
from CONFIG_SOC. Replace the single fixed include path with a two-pass
existence check that appends CONFIG_SOC_TOOLCHAIN_NAME first and then
CONFIG_SOC, so both naming conventions are supported without requiring
every board to align them.

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

Clang's Integrated Assembler (IAS) does not support the Xtensa GAS
pseudo-op form 'rsr.epsN'/'rsr.epcN'; it requires the canonical two-
operand form 'rsr <dst>, epsN'.  Replace all occurrences in
xtensa_asm2.inc.S.

Also add '.literal_position' immediately after the '.text' directive in
crt1.S to satisfy IAS requirements for literal pool placement at the
start of the text section.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Cadence-generated core-isa.h headers for some SoCs (NXP, MediaTek)
contain '#error xcc should not use this header' when __XCC__ is defined.
This guard was intended to prevent Xtensa's proprietary XCC compiler
from using the generic fallback header instead of the SoC-specific one,
but it also blocks our LLVM Clang when we define __XCC__ to enable the
HiFi intrinsic paths in SOF.

Add a thin wrapper at arch/xtensa/include/xtensa/config/core-isa.h that:
- When both __XCC__ and __XCC_CLANG__ are defined (LLVM Clang path),
  temporarily undefines __XCC__ before including_next, then restores it.
- Otherwise falls through to include_next unconditionally.

This allows Clang to traverse the SoC-specific core-isa.h without
tripping the guard while retaining __XCC__ visibility everywhere else.

Also fix xtensa_init_page_tables() in ptables.c: the 'entry' variable
is used to store page table entries (32-bit values) but was declared as
'volatile uint8_t'. Change to uint32_t to match the actual use and
silence Clang's -Wconversion warning.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Clang's Integrated Assembler (IAS) differs from GAS in two ways that
require source changes:

1. Long conditional branches: IAS does not automatically relax
   conditional branches with offsets that exceed the instruction's
   range (unlike GAS which relaxes them silently). In userspace.S,
   replace the long 'bgeu' targeting a distant label with a short
   'bltu' over an unconditional 'j' to stay within range.

2. Literal pool placement: IAS has no default strategy for placing
   Xtensa literal pools in hand-written assembly; it throws 'literal
   pool empty' errors unless explicitly directed. Wrap reset_vector.S
   with '.begin auto-litpools' / '.end auto-litpools' under Clang so
   IAS inserts literal pool boundaries automatically.

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

LLD rejects absolute location counter assignments ('.\ = 0xYYY') in
generated linker scripts when the section VMA does not match. Rewrite
the Xtensa vector-offset assignments in gen_vectors.py to be relative
to the z_xtensa_vecbase symbol ('.\ = z_xtensa_vecbase + 0xYYY') so
LLD resolves them correctly at link time.

Note: the HAL include directory was already updated to prefer
CONFIG_SOC_TOOLCHAIN_NAME in a prior commit.

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 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>
…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 went
directly to the sect_map path, which returns the runtime DRAM address.
However this misses the bounds check and the pre-located ROM/IMR section
case.

Fix:
- Add an explicit sh_ndx bounds check before accessing sect_hdrs.
- For sections with sh_addr >= 0x08000000 (pre-located ROM/IMR), return
  llext_peek() at the section file offset.
- ET_REL sections (sh_addr=0) fall through to the sect_map path which
  returns the correct DRAM address loaded by llext_map_sections().

Without this fix, on Intel ACE30 (PTL) where LLEXT is loaded from IMR,
R_XTENSA_32 relocations receive a raw IMR file offset instead of the
runtime DRAM address, causing ExcVaddr faults (seen as
win0[0]=0x01009B01, win0[1]=0x001D003C on PTL/ACE30).

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

In llext_link_plt(), the relocation target address for relocatable ELFs
(ET_REL) was computed as:

  rel_addr = ext->mem[LLEXT_MEM_TEXT] - sects[LLEXT_MEM_TEXT].sh_offset
             + rela.r_offset + tgt->sh_offset

This arithmetic uses the file offset of the target section rather than
its runtime load address, producing a wrong relocation target when the
LLEXT is loaded from IMR into DRAM.

Fix: when 'tgt' is set (relocatable ELF path), compute the section
index from the section header pointer and call llext_loaded_sect_ptr()
to obtain the correct runtime address, then add rela.r_offset directly.

The shared/dynamic ELF path is unchanged.

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

Two fixes in llext_load.c for relocatable ELF (ET_REL) support:

1. llext_copy_symbols(): split the ET_REL and non-ET_REL code paths.
   For ET_REL, resolve the symbol address directly via
   llext_loaded_sect_ptr() + st_value; the previous code mixed both
   paths with a conditional subtraction of section_addr that produced
   wrong results for relocatable objects.

2. llext_map_sections(): the REGIONS_OVERLAP_ON() check on sh_offset
   is only meaningful for shared ELFs where sections have distinct file
   offsets. ET_REL sections all start at offset 0 (relative addressing),
   so the overlap check always fires and aborts loading. Guard it with
   'ldr->hdr.e_type != ET_REL'.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Two fixes in arch/xtensa/core/elf.c for Xtensa LLEXT relocation:

1. arch_elf_relocate_local(): the existing code only handled the
   STT_SECTION case for non-ET_REL ELFs. For ET_REL, symbol addresses
   must be resolved through llext_loaded_sect_ptr() using the symbol's
   st_shndx, since sh_addr=0 for all sections. Add an ET_REL branch that
   computes sh_addr = loaded_section_base + sym->st_value.

2. xtensa_elf_relocate() / R_XTENSA_SLOT0_OP: global symbols (STB_GLOBAL)
   already have their final runtime address in the 'addr' argument passed
   by the generic LLEXT relocation engine; use it directly instead of
   reading the symbol table entry again. Local symbols continue to go
   through the symbol table path with llext_loaded_sect_ptr().

Also handle SHN_UNDEF and out-of-range st_shndx gracefully by setting
sec_addr to 0 in the local-symbol path.

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>
…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>
…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>
lrgirdwo and others added 24 commits July 18, 2026 22:05
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>
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>
…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>
… 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>
- 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>
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>
… of CONFIG_MP_MAX_NUM_CPUS

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>
- 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.
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>
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>
…teral_position for IAS"

This reverts commit 264b8f5.

The modern upstream LLVM/Clang toolchain (version 23.0.0git) natively
supports compiling the rsr.epsN/rsr.epcN instruction forms using the
integrated assembler (-fintegrated-as). Additionally, .literal_position
is not required for crt1.S compilation under the current toolchain.

Testing confirms that removing this commit introduces no compilation
failures for tgl, mtl, or ptl SOF targets.

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