Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
7991d9e
cmake: compiler: Configure Clang compiler optimization and warning co…
lrgirdwo Jun 20, 2026
1ed1670
cmake: toolchain: Add native LLVM and LLD compiler and linker targets
lrgirdwo Jun 20, 2026
69ef05f
cmake: linker: Adapt linker executables for LLVM/LLD and GCC driver o…
lrgirdwo Jun 20, 2026
b17bd0a
cmake: modules: Configure LLEXT compiler and package stripping flags …
lrgirdwo Jun 20, 2026
f77bf09
cmake: linker: Remove forced bfd and use lld for Xtensa LLVM builds
lrgirdwo Jun 28, 2026
af23ee4
cmake: toolchain: llvm: Disable FLIX when CONFIG_COMPILER_CODEGEN_VLI…
lrgirdwo Jul 3, 2026
6e02563
cmake: toolchain: llvm: derive per-core SDK ld from XTENSA_TOOLCHAIN_…
lrgirdwo Jul 10, 2026
df7555c
arch: xtensa: toolchain: Configure include paths and vector generator…
lrgirdwo Jun 20, 2026
29d374f
arch: xtensa: asm: Enable auto-litpools assembly directive under Clang
lrgirdwo Jun 20, 2026
0ca47fe
arch: xtensa: asm: Avoid long conditional branches for IAS compatibility
lrgirdwo Jun 20, 2026
82ea80d
arch: xtensa: core LLVM and Integrated Assembler support
lrgirdwo Jun 24, 2026
31db1cd
soc: intel_adsp: boot: Explicitly mark boot assembly section as alloc…
lrgirdwo Jun 20, 2026
460351b
soc: cdns: dc233c: Configure linker cached/uncached macro mappings fo…
lrgirdwo Jun 20, 2026
e70fa3e
soc: intel_adsp: Configure cached/uncached mappings and discard stack…
lrgirdwo Jun 20, 2026
d26e3c4
soc: intel_adsp: Map IMR boot loader stack as shared region
lrgirdwo Jun 22, 2026
9e6fb34
soc: xtensa: Update linker scripts for LLD compatibility
lrgirdwo Jun 24, 2026
0e9ed31
soc: intel_adsp: Fix missing active cpus array on UP configurations
lrgirdwo Jun 24, 2026
449fb05
soc: xtensa: Finalize LLD linker script fixes for Intel and NXP
lrgirdwo Jun 24, 2026
16adcb2
soc: intel_adsp: ace: Add MMU mappings for bootloader IMR regions
lrgirdwo Jun 27, 2026
cd48f18
soc: intel_adsp: Fix heap boundary calculation in linker scripts
lrgirdwo Jul 9, 2026
2cbd54a
arch: xtensa: crt1: enable CPENABLE at early boot for all coprocessors
lrgirdwo Jul 12, 2026
31d4012
arch: xtensa: fix context switch stack offset for Clang windowed ABI
lrgirdwo Jul 12, 2026
79e1bef
cmake: toolchain: llvm: add LLEXT link wrapper and shared linker script
lrgirdwo Jul 12, 2026
3932cf7
lib: libc: minimal: disable Clang loop vectorization in memcpy/memset
lrgirdwo Jul 12, 2026
b98c1ca
soc: intel_adsp: lazy debug window init and word-aligned boot memcpy
lrgirdwo Jul 12, 2026
03dae3e
drivers: dma: intel_adsp_gpdma: use sys_write16 for 16-bit ownership …
lrgirdwo Jun 25, 2026
71b4880
boards: mediatek: Update ADSP devicetree and DMA bindings for Clang c…
lrgirdwo Jun 24, 2026
22a812f
drivers: interrupt_controller: intc_dw_ace: Fix compiler bug in irq loop
lrgirdwo Jul 9, 2026
38ccaf1
soc: intel: adsp: cavs: add HiFi3 capability and fix heap boundary
lrgirdwo Jul 10, 2026
f86b968
arch: xtensa: hifi: macro-free HiFi3 save/restore for cavs2.5 (TGL)
lrgirdwo Jul 10, 2026
d7b2dcd
arch: xtensa: provide __popcountsi2 with text-section-literals
lrgirdwo Jul 10, 2026
23a1d2d
subsys: llext: Fix Xtensa relocations for relocatable ELF and detache…
lrgirdwo Jul 10, 2026
bdb827f
subsys: llext: fix llext_loaded_sect_ptr for ET_REL sections with sh_…
lrgirdwo Jul 12, 2026
b06d900
xtensa: adsp: record fatal exception breadcrumbs in HP-SRAM window0
lrgirdwo Jul 9, 2026
d561215
xtensa: adsp: record triple fault breadcrumbs in HP-SRAM window0
lrgirdwo Jul 12, 2026
82f1185
xtensa: adsp: Support selecting diagnostic data in fatal breadcrumbs
lrgirdwo Jul 9, 2026
4bebf31
xtensa: adsp: breadcrumb: Guard instruction fetch against unmapped PC
lrgirdwo Jul 12, 2026
d77326f
arch: xtensa: vector_handlers: Enable all CPs before print_fatal_exce…
lrgirdwo Jul 12, 2026
3d54167
arch: xtensa: asm2: Enable all CPs in assembly before C exception han…
lrgirdwo Jul 12, 2026
0cd3f6f
arch: xtensa: debug: move double exception breadcrumbs to win0[4-6]
lrgirdwo Jul 12, 2026
1866cdd
arch: xtensa: debug: overwrite ROM boot status with crash PC if win0[…
lrgirdwo Jul 12, 2026
2859ce4
arch: xtensa: Kconfig: enable XTENSA_ADSP_FATAL_BREADCRUMB by default…
lrgirdwo Jul 12, 2026
46bfe2e
drivers: interrupt_controller: intc_dw_ace: use arch_num_cpus instead…
lrgirdwo Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions arch/xtensa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,60 @@ config XTENSA_EXCEPTION_ENTER_GDB
When an exception like invalid address access or division by zero is
hit, enter the GDB stub.

config XTENSA_ADSP_FATAL_BREADCRUMB
bool "Record fatal exception breadcrumbs in HP-SRAM window0"
depends on SOC_FAMILY_INTEL_ADSP
default y if XTENSA_ADSP_TRIPLE_FAULT_BREADCRUMB
help
When a fatal exception is taken, record the faulting PC, exception
cause, faulting virtual address and the faulting instruction word
into HP-SRAM window0 via its uncached alias. The host SOF driver
prints window0[0] as "Firmware state" and window0[1] as "status/error
code" on an IPC timeout, so the crash information becomes visible
in the host dmesg even when no console or mtrace output is available.
Only the first fatal exception is latched so the original fault is
preserved across a crash loop. This is a debug aid and should be
left disabled in production builds.

if XTENSA_ADSP_FATAL_BREADCRUMB

choice XTENSA_ADSP_FATAL_BREADCRUMB_DATA
prompt "Fatal breadcrumb data selection"
default XTENSA_ADSP_FATAL_BREADCRUMB_DATA_CAUSE
help
Select which exception diagnostic data to write into window0[1], which
is printed as the "status/error code" in the host dmesg log.

config XTENSA_ADSP_FATAL_BREADCRUMB_DATA_CAUSE
bool "Exception cause"
help
Record the exception cause in window0[1].

config XTENSA_ADSP_FATAL_BREADCRUMB_DATA_VADDR
bool "Faulting virtual address (excvaddr)"
help
Record the faulting virtual address (excvaddr) in window0[1].

config XTENSA_ADSP_FATAL_BREADCRUMB_DATA_A0
bool "Caller return address (a0)"
help
Record the calling function's return address (a0) in window0[1].

endchoice

endif # XTENSA_ADSP_FATAL_BREADCRUMB

config XTENSA_ADSP_TRIPLE_FAULT_BREADCRUMB
bool "Record triple fault breadcrumbs in HP-SRAM window0"
depends on SOC_FAMILY_INTEL_ADSP
default y
help
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.

menu "Xtensa HiFi Options"

config XTENSA_CPU_HAS_HIFI
Expand Down
12 changes: 9 additions & 3 deletions arch/xtensa/core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_cc_option(-mlongcalls)
zephyr_cc_option(-mtext-section-literals)

zephyr_library()

Expand All @@ -13,6 +14,7 @@ zephyr_library_sources(
thread.c
vector_handlers.c
prep_c.c
popcount.c
)

zephyr_library_sources_ifdef(CONFIG_XTENSA_USE_CORE_CRT1 crt1.S)
Expand Down Expand Up @@ -41,9 +43,13 @@ if(CONFIG_SOC_FAMILY_ESPRESSIF_ESP32)
-I${ZEPHYR_HAL_ESPRESSIF_MODULE_DIR}/components/xtensa/${CONFIG_SOC}/include
)
else()
set(XTENSA_CONFIG_HAL_INCLUDE_DIR
-I${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC}
)
set(XTENSA_CONFIG_HAL_INCLUDE_DIR)
if(EXISTS ${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC_TOOLCHAIN_NAME})
list(APPEND XTENSA_CONFIG_HAL_INCLUDE_DIR -I${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC_TOOLCHAIN_NAME})
endif()
if(EXISTS ${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC})
list(APPEND XTENSA_CONFIG_HAL_INCLUDE_DIR -I${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC})
endif()
endif()

add_subdirectory(startup)
Expand Down
11 changes: 11 additions & 0 deletions arch/xtensa/core/crt1.S
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,19 @@

.text
.align 4
.literal_position

_start:
#if XCHAL_HAVE_CP
#ifdef CONFIG_XTENSA_LAZY_HIFI_SHARING
movi a2, 0xFF & ~(1 << XCHAL_CP_ID_AUDIOENGINELX)
#else
movi a2, 0xFF
#endif
wsr a2, CPENABLE
rsync
#endif

/*
* _start is typically NOT at the beginning of the text segment --
* it is always called from either the reset vector (__start) or other
Expand Down
71 changes: 45 additions & 26 deletions arch/xtensa/core/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#define R_XTENSA_ASM_EXPAND 11
#define R_XTENSA_SLOT0_OP 20

static int xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,

Check failure on line 35 in arch/xtensa/core/elf.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 39 to the 25 allowed.

See more on https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&issues=AZ9X9rHiemFbw1K70veo&open=AZ9X9rHiemFbw1K70veo&pullRequest=108765
const elf_rela_t *rel, uintptr_t addr,
uint8_t *loc, int type, uint32_t stb,
const struct llext_load_param *ldr_parm)
Expand Down Expand Up @@ -78,26 +78,34 @@
case R_XTENSA_SLOT0_OP:
/* Apparently only actionable with LOCAL bindings */
;
elf_sym_t rsym;
int ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset +
ELF_R_SYM(rel->r_info) * sizeof(elf_sym_t));
uintptr_t link_addr;

if (!ret) {
ret = llext_read(ldr, &rsym, sizeof(elf_sym_t));
}
if (ret) {
LOG_ERR("Failed to read a symbol table entry, LLEXT linking might fail.");
return ret;
}
if (stb == STB_GLOBAL) {
link_addr = addr;
} else {
elf_sym_t rsym;
int ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset +
ELF_R_SYM(rel->r_info) * sizeof(elf_sym_t));

/*
* So far in all observed use-cases
* llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx) was already
* available as the "addr" argument of this function, supplied
* by arch_elf_relocate_local() from its non-STT_SECTION branch.
*/
uintptr_t link_addr = (uintptr_t)llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx) +
rsym.st_value + rel->r_addend;
if (!ret) {
ret = llext_read(ldr, &rsym, sizeof(elf_sym_t));
}
if (ret) {
LOG_ERR("Failed to read a symbol table entry, LLEXT linking might fail.");
return ret;
}

uintptr_t sec_addr;
if (rsym.st_shndx != SHN_UNDEF && rsym.st_shndx < ext->sect_cnt) {
elf_shdr_t *shdr = ext->sect_hdrs + rsym.st_shndx;
sec_addr = shdr->sh_addr &&
(!ldr_parm || !ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ?
shdr->sh_addr : (uintptr_t)llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx);
} else {
sec_addr = 0;
}
link_addr = sec_addr + rsym.st_value + rel->r_addend;
}
ssize_t value = (link_addr - (((uintptr_t)got_entry + 3) & ~3)) >> 2;

/* Check the opcode */
Expand Down Expand Up @@ -143,15 +151,26 @@
int type = ELF32_R_TYPE(rel->r_info);
uintptr_t sh_addr;

if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
elf_shdr_t *shdr = ext->sect_hdrs + sym->st_shndx;

/* shdr->sh_addr is NULL when not built for a specific address */
sh_addr = shdr->sh_addr &&
(!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ?
shdr->sh_addr : (uintptr_t)llext_loaded_sect_ptr(ldr, ext, sym->st_shndx);
if (ldr->hdr.e_type == ET_REL) {
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < ext->sect_cnt) {
elf_shdr_t *shdr = ext->sect_hdrs + sym->st_shndx;
uintptr_t sec_addr = shdr->sh_addr &&
(!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ?
shdr->sh_addr : (uintptr_t)llext_loaded_sect_ptr(ldr, ext, sym->st_shndx);
sh_addr = sec_addr + sym->st_value;
} else {
sh_addr = sym->st_value;
}
} else {
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
elf_shdr_t *shdr = ext->sect_hdrs + sym->st_shndx;

sh_addr = shdr->sh_addr &&
(!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ?
shdr->sh_addr : (uintptr_t)llext_loaded_sect_ptr(ldr, ext, sym->st_shndx);
} else {
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
}
}

return xtensa_elf_relocate(ldr, ext, rel, sh_addr, rel_addr, type,
Expand Down
2 changes: 1 addition & 1 deletion arch/xtensa/core/gen_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,6 @@
print(" KEEP(*(.WindowVectors.text));")
for s in sects:
print(f" KEEP(*(.{s}Vector.literal));")
print(f" . = 0x{offsets[s]:x};")
print(f" . = z_xtensa_vecbase + 0x{offsets[s]:x};")
print(f" KEEP(*(.{s}Vector.text));")
print(" }")
17 changes: 17 additions & 0 deletions arch/xtensa/core/popcount.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2024 Intel Corporation
*
* __popcountsi2 — compiled with -mtext-section-literals (see CMakeLists.txt)
* so that all literal-pool entries are interleaved with the code and remain
* within l32r reach. This overrides the precompiled libgcc version, whose
* separate .literal section can fall out of range when the image is large.
*/

int __popcountsi2(unsigned int x)
{
x = x - ((x >> 1) & 0x55555555u);
x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
x = (x + (x >> 4)) & 0x0f0f0f0fu;
return (int)((x * 0x01010101u) >> 24);
}
8 changes: 7 additions & 1 deletion arch/xtensa/core/ptables.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ static inline uint32_t *alloc_l2_table(void)
* @param[in] attrs Page table attributes for the memory region.
* @param[in] options Options for the memory region.
*/


static void map_memory_range(const uint32_t start, const uint32_t end,
const uint32_t attrs, const uint32_t options)
{
Expand Down Expand Up @@ -465,6 +467,8 @@ static void map_memory_range(const uint32_t start, const uint32_t end,

init_page_table(l2_table, L2_PAGE_TABLE_NUM_ENTRIES, PTE_L2_ILLEGAL);



xtensa_kernel_ptables[l1_pos] =
PTE((uint32_t)l2_table, RING_KERNEL, XTENSA_MMU_PAGE_TABLE_ATTR);
}
Expand All @@ -476,7 +480,7 @@ static void map_memory_range(const uint32_t start, const uint32_t end,

static void xtensa_init_page_tables(void)
{
volatile uint8_t entry;
uint32_t entry;
static bool already_inited;

if (already_inited) {
Expand Down Expand Up @@ -527,6 +531,8 @@ void xtensa_mmu_init(void)
{
xtensa_init_page_tables();



xtensa_mmu_init_paging();

/*
Expand Down
6 changes: 6 additions & 0 deletions arch/xtensa/core/startup/reset_vector.S
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ _ResetHandler:
* section is in place (which is sometimes only after unpacking).
*/
.begin no-absolute-literals
#ifdef __clang__
.begin auto-litpools
#endif

/*
* If we have dynamic cache way support, init the caches as soon
Expand Down Expand Up @@ -708,6 +711,9 @@ unpackdone:
.size __start, . - __start
#endif

#ifdef __clang__
.end auto-litpools
#endif
.text
.global xthals_hw_configid0, xthals_hw_configid1
.global xthals_release_major, xthals_release_minor
Expand Down
3 changes: 2 additions & 1 deletion arch/xtensa/core/userspace.S
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ _not_checking_user_context:
l32i a2, a1, 0
l32i a2, a2, ___xtensa_irq_bsa_t_a2_OFFSET
movi a0, K_SYSCALL_LIMIT
bgeu a2, a0, _bad_syscall
bltu a2, a0, _id_ok
j _bad_syscall

_id_ok:
/* Find the function handler for the given syscall id. */
Expand Down
55 changes: 55 additions & 0 deletions arch/xtensa/core/vector_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
#include <xtensa_internal.h>
#include <xtensa_stack.h>

#if defined(CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB)
#include <adsp_memory.h>
#include <mem_window.h>
#include <zephyr/cache.h>
#endif

LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);

extern char xtensa_arch_except_epc[];
Expand Down Expand Up @@ -564,6 +570,42 @@ void *xtensa_excint1_c(void *esf)

cause = bsa->exccause;

#if defined(CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB)
/* DEBUG breadcrumb: when no console/mtrace is available, record the
* faulting PC/cause/vaddr into HP-SRAM window0 via its uncached alias.
* The host SOF driver prints window0[0] as "Firmware state" and
* window0[1] as "status/error code" on IPC timeout, so the crash PC
* becomes visible in dmesg. Latch only the FIRST fatal exception so we
* see the original fault, not the last in a crash loop. Skip level-1
* interrupts which are not faults. win0[3] counts all exceptions.
*/
if (cause != EXCCAUSE_LEVEL1_INTERRUPT) {
volatile uint32_t *win0 = (volatile uint32_t *)sys_cache_uncached_ptr_get((void *)HP_SRAM_WIN0_BASE);

if (win0[0] < 0xa0000000U) {
win0[0] = (uint32_t)bsa->pc;
#if defined(CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB_DATA_VADDR)
win0[1] = (uint32_t)bsa->excvaddr;
#elif defined(CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB_DATA_A0)
win0[1] = (uint32_t)bsa->a0;
#else
win0[1] = 0xe0000000U | ((uint32_t)cause & 0xffU);
#endif
win0[2] = (uint32_t)bsa->excvaddr;
/* Only read the faulting instruction if the PC is within
* the DSP SRAM range to avoid a double exception when the
* exception was caused by a bad/unmapped function pointer.
*/
uint32_t fault_pc = (uint32_t)bsa->pc & ~3U;

if (fault_pc >= 0xa0000000U && fault_pc < 0xa2000000U) {
win0[4] = *(volatile uint32_t *)fault_pc;
}
}
win0[3]++;
}
#endif

switch (cause) {
case EXCCAUSE_LEVEL1_INTERRUPT:
#ifdef CONFIG_XTENSA_MMU
Expand Down Expand Up @@ -709,6 +751,19 @@ void *xtensa_excint1_c(void *esf)

skip_checks:
if (reason != K_ERR_KERNEL_OOPS) {
#if XCHAL_HAVE_CP
/* Enable all coprocessors before printing. LLVM generates
* HiFi4 ae_* instructions in print_fatal_exception and
* its callees (printk/LOG_ERR). If CPENABLE has the HiFi4
* CP bit cleared (e.g. via lazy HiFi sharing on context
* switch), those instructions trigger EXCCAUSE_CP_DISABLED
* which becomes a double exception -> triple fault because
* PS.EXCM is set inside the exception handler.
*/
unsigned int cp_all = (1U << XCHAL_CP_NUM) - 1U;

__asm__ volatile("wsr.cpenable %0\n\trsync" :: "r"(cp_all));
#endif
print_fatal_exception(print_stack, is_dblexc, depc);
}
#ifdef CONFIG_XTENSA_EXCEPTION_ENTER_GDB
Expand Down
Loading