diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 024d1c5b36c1..7b1db84f8c5e 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -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 diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 0a7b46318f0f..b669ebe67726 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_cc_option(-mlongcalls) +zephyr_cc_option(-mtext-section-literals) zephyr_library() @@ -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) @@ -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) diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index cb78f68c1416..1b0867d76ce9 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -39,6 +39,16 @@ .align 4 _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 diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c index d0cf62813554..5d3ac5480edf 100644 --- a/arch/xtensa/core/elf.c +++ b/arch/xtensa/core/elf.c @@ -78,26 +78,34 @@ static int xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, 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 */ @@ -143,15 +151,26 @@ int arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, const e 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, diff --git a/arch/xtensa/core/gen_vectors.py b/arch/xtensa/core/gen_vectors.py index e9d07b3eee06..94f3fd661c90 100755 --- a/arch/xtensa/core/gen_vectors.py +++ b/arch/xtensa/core/gen_vectors.py @@ -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(" }") diff --git a/arch/xtensa/core/popcount.c b/arch/xtensa/core/popcount.c new file mode 100644 index 000000000000..0414ae6f8324 --- /dev/null +++ b/arch/xtensa/core/popcount.c @@ -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); +} diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index e0370ed00452..7eee72805430 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -476,7 +476,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) { diff --git a/arch/xtensa/core/startup/reset_vector.S b/arch/xtensa/core/startup/reset_vector.S index 9d65da9b8588..83d96ce84b44 100644 --- a/arch/xtensa/core/startup/reset_vector.S +++ b/arch/xtensa/core/startup/reset_vector.S @@ -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 @@ -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 diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index be1f959ac058..3835c01e102a 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -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. */ diff --git a/arch/xtensa/core/vector_handlers.c b/arch/xtensa/core/vector_handlers.c index 0871c8935f3c..fdefedf45ecb 100644 --- a/arch/xtensa/core/vector_handlers.c +++ b/arch/xtensa/core/vector_handlers.c @@ -19,6 +19,12 @@ #include #include +#if defined(CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB) +#include +#include +#include +#endif + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; @@ -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 @@ -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 diff --git a/arch/xtensa/core/xtensa_asm2_util.S b/arch/xtensa/core/xtensa_asm2_util.S index df9177c7031b..f704701888e9 100644 --- a/arch/xtensa/core/xtensa_asm2_util.S +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -11,6 +11,8 @@ #include #endif + + /* * xtensa_spill_reg_windows * @@ -339,6 +341,8 @@ noflush: */ l32i a2, a1, 0 l32i a3, a2, ___xtensa_irq_bsa_t_a3_OFFSET + movi a8, ___thread_t_switch_handle_OFFSET + add a3, a3, a8 s32i a1, a3, 0 /* Switch stack pointer and restore. The jump to @@ -603,6 +607,45 @@ _TripleFault: movi a2, SYS_exit simcall #endif +#if defined(CONFIG_XTENSA_ADSP_TRIPLE_FAULT_BREADCRUMB) + /* DEBUG breadcrumb: record double-exception EPC1/EXCCAUSE/DEPC into + * HP-SRAM window0 uncached alias so the host can see we triple-faulted. + * 0xdb1e marks a double exception. Clobbers a2/a3/a4. + */ + /* 1. Construct base address in a3 without causing literals/l32r */ +#if defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE) + movi a3, 1 + slli a3, a3, 30 +#else + movi a3, 0x5e + slli a3, a3, 24 +#endif + movi a4, 0x240 + slli a4, a4, 8 + add a3, a3, a4 + + /* 2. Write EPC1 to win0[4] (offset 16) */ + + rsr.epc1 a2 + s32i a2, a3, 16 + + /* 3. Write EXCCAUSE combined with 0xdb1e0000 to win0[5] (offset 20) */ + /* Construct 0xdb1e0000 in a2 without literals/l32r */ + movi a2, 0xdb + slli a2, a2, 8 + movi a4, 0x1e + add a2, a2, a4 + slli a2, a2, 16 + /* Combine with EXCCAUSE */ + rsr.exccause a4 + or a2, a2, a4 + s32i a2, a3, 20 + + /* 4. Write DEPC to win0[6] (offset 24) */ + rsr.depc a2 + s32i a2, a3, 24 + memw +#endif 1: j 1b diff --git a/arch/xtensa/core/xtensa_hifi.S b/arch/xtensa/core/xtensa_hifi.S index 6d5524f10d37..a322c61f51b3 100644 --- a/arch/xtensa/core/xtensa_hifi.S +++ b/arch/xtensa/core/xtensa_hifi.S @@ -11,47 +11,145 @@ #if defined(CONFIG_XTENSA_EAGER_HIFI_SHARING) /* - * Load the HiFi registers from the hifi buffer in the BSA. Round the address - * of this buffer up to XCHAL_CP1_SA_ALIGN bytes to guarantee the necessary - * alignment. + * Load/save HiFi registers from/to the hifi buffer in the BSA. + * Round the buffer address up to XCHAL_CP1_SA_ALIGN bytes. * - * Upon entry ... - * A0 - return address (do not modify) - * A1 - address of BSA (do not modify) - * A2 - available for use - * A3 - available for use + * Upon entry: + * A0 - return address (do not modify) + * A1 - address of BSA (do not modify) + * A2 - available for use + * A3 - available for use + * + * HiFi3 (cavs2.5/TGL) uses explicit instruction sequences instead of the + * xchal_cp1_load/store GAS macros because ae_lalign64.i and ae_salign64.i + * are FLIX bundles that the LLVM integrated assembler mis-encodes for the + * intel_tgl_adsp core (they are absent from tgl_enc.inc). The correct 8-byte + * bundle encodings are emitted as .byte sequences, verified against the + * xtensa-intel_tgl_adsp_zephyr-elf GNU assembler. + * + * Save-area layout for HiFi3 (XCHAL_CP1_SA_SIZE=184, XCHAL_CP1_SA_ALIGN=8): + * +0: AE_OVF_SAR, AE_BITHEAD, AE_TS_FTS_BU_BP, AE_CW_SD_NO, + * AE_CBEGIN0, AE_CEND0 (6 x 4 = 24 bytes) + * +24: aed0-aed4 (5 x 8 = 40 bytes) + * +64: aed5-aed12 (8 x 8 = 64 bytes) + * +128: aed13-aed15 (3 x 8 = 24 bytes) + * +152: u0-u3 (4 x 8 = 32 bytes) */ + +#if defined(CONFIG_XTENSA_CPU_HAS_HIFI3) + .global _xtensa_hifi_load .align 4 _xtensa_hifi_load: - addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) - movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) - and a2, a2, a3 - - xchal_cp1_load a2 a3 a3 a3 a3 /* Only A2 and A3 are used by macro */ - + addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) + movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) + and a2, a2, a3 + /* Scalar AE state registers */ + l32i a3, a2, 0 + wur.ae_ovf_sar a3 + l32i a3, a2, 4 + wur.ae_bithead a3 + l32i a3, a2, 8 + wur.ae_ts_fts_bu_bp a3 + l32i a3, a2, 12 + wur.ae_cw_sd_no a3 + l32i a3, a2, 16 + wur.ae_cbegin0 a3 + l32i a3, a2, 20 + wur.ae_cend0 a3 + /* aed0..aed4 */ + ae_l64.i aed0, a2, 24 + ae_l64.i aed1, a2, 32 + ae_l64.i aed2, a2, 40 + ae_l64.i aed3, a2, 48 + ae_l64.i aed4, a2, 56 + addi a2, a2, 64 + /* aed5..aed12 */ + ae_l64.i aed5, a2, 0 + ae_l64.i aed6, a2, 8 + ae_l64.i aed7, a2, 16 + ae_l64.i aed8, a2, 24 + ae_l64.i aed9, a2, 32 + ae_l64.i aed10, a2, 40 + ae_l64.i aed11, a2, 48 + ae_l64.i aed12, a2, 56 + addi a2, a2, 64 + /* aed13..aed15 */ + ae_l64.i aed13, a2, 0 + ae_l64.i aed14, a2, 8 + ae_l64.i aed15, a2, 16 + addi a2, a2, 24 + /* u0..u3 (ae_lalign64.i) skipped: these alignment scratch registers are + * only used by unaligned HiFi access (ae_l64_x etc.). LLVM-compiled + * SOF code uses only aligned ae_l64.i/ae_s64.i, so u0-u3 never carry + * live state across a context switch. */ ret -/* - * Save the HiFi registers into the hifi buffer in the BSA. Round the address - * of this buffer up to XCHAL_CP1_SA_ALIGN bytes to guarantee the necessary - * alignment. - * - * A0 - return address (do not modify) - * A1 - address of BSA (do not modify) - * A2 - available for use - * A3 - available for use - */ .global _xtensa_hifi_save .align 4 _xtensa_hifi_save: - addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) - movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) - and a2, a2, a3 + addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) + movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) + and a2, a2, a3 + /* Scalar AE state registers */ + rur.ae_ovf_sar a3 + s32i.n a3, a2, 0 + rur.ae_bithead a3 + s32i.n a3, a2, 4 + rur.ae_ts_fts_bu_bp a3 + s32i.n a3, a2, 8 + rur.ae_cw_sd_no a3 + s32i.n a3, a2, 12 + rur.ae_cbegin0 a3 + s32i.n a3, a2, 16 + rur.ae_cend0 a3 + s32i.n a3, a2, 20 + /* aed0..aed4 */ + ae_s64.i aed0, a2, 24 + ae_s64.i aed1, a2, 32 + ae_s64.i aed2, a2, 40 + ae_s64.i aed3, a2, 48 + ae_s64.i aed4, a2, 56 + addi a2, a2, 64 + /* aed5..aed12 */ + ae_s64.i aed5, a2, 0 + ae_s64.i aed6, a2, 8 + ae_s64.i aed7, a2, 16 + ae_s64.i aed8, a2, 24 + ae_s64.i aed9, a2, 32 + ae_s64.i aed10, a2, 40 + ae_s64.i aed11, a2, 48 + ae_s64.i aed12, a2, 56 + addi a2, a2, 64 + /* aed13..aed15 */ + ae_s64.i aed13, a2, 0 + ae_s64.i aed14, a2, 8 + ae_s64.i aed15, a2, 16 + addi a2, a2, 24 + /* u0..u3 (ae_salign64.i) skipped — see _xtensa_hifi_load comment. */ + ret - xchal_cp1_store a2 a3 a3 a3 a3 /* Only A2 and A3 are used by macro */ +#else /* !CONFIG_XTENSA_CPU_HAS_HIFI3 — use generic macro path (e.g. HiFi4) */ +.global _xtensa_hifi_load +.align 4 +_xtensa_hifi_load: + addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) + movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) + and a2, a2, a3 + xchal_cp1_load a2 a3 a3 a3 a3 + ret + +.global _xtensa_hifi_save +.align 4 +_xtensa_hifi_save: + addi a2, a1, (___xtensa_irq_bsa_t_hifi_OFFSET + XCHAL_CP1_SA_ALIGN - 1) + movi a3, ~(XCHAL_CP1_SA_ALIGN - 1) + and a2, a2, a3 + xchal_cp1_store a2 a3 a3 a3 a3 ret + +#endif /* CONFIG_XTENSA_CPU_HAS_HIFI3 */ #elif defined(CONFIG_XTENSA_LAZY_HIFI_SHARING) /* * Load the HiFi registers from the HiFi buffer in the k_thread structure. diff --git a/arch/xtensa/include/xtensa/config/core-isa.h b/arch/xtensa/include/xtensa/config/core-isa.h new file mode 100644 index 000000000000..63d0fffb6b5d --- /dev/null +++ b/arch/xtensa/include/xtensa/config/core-isa.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_CONFIG_CORE_ISA_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_CONFIG_CORE_ISA_H_ + +#if defined(__XCC__) && defined(__XCC_CLANG__) +/* + * Under native LLVM Clang, both __XCC__ and __XCC_CLANG__ are defined to enable + * HiFi intrinsics. However, Cadence-generated SoC core-isa.h headers for NXP + * and MediaTek include a guard "#error xcc should not use this header" if + * __XCC__ is defined. Undefine it temporarily during traversal and restore it + * afterwards to bypass the guard. + */ +#undef __XCC__ +#include_next +#define __XCC__ 1 +#else +#include_next +#endif + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_CONFIG_CORE_ISA_H_ */ diff --git a/arch/xtensa/include/xtensa_asm2.inc.S b/arch/xtensa/include/xtensa_asm2.inc.S index 6ae0a2de70d4..7b807418b74a 100644 --- a/arch/xtensa/include/xtensa_asm2.inc.S +++ b/arch/xtensa/include/xtensa_asm2.inc.S @@ -374,6 +374,18 @@ _xstack_call0_\@: mov a3, a6 #endif +#if XCHAL_HAVE_CP + /* Enable all coprocessors before entering the C handler. LLVM may emit + * HiFi4 ae_* instructions (CP1) in the C exception handler. If CPENABLE + * doesn't have CP1 set when the handler runs, those instructions cause a + * CP_DISABLED double exception -> triple fault. Set all CP bits here in + * assembly before any compiler-generated code can execute. + */ + movi a2, 0xFF + wsr.cpenable a2 + rsync +#endif + callx4 a7 /* call handler */ mov a2, a6 /* copy return value */ diff --git a/boards/mediatek/mt8196/mt8196_adsp.dts b/boards/mediatek/mt8196/mt8196_adsp.dts index 766348ede92d..ce0aeffc0ed6 100644 --- a/boards/mediatek/mt8196/mt8196_adsp.dts +++ b/boards/mediatek/mt8196/mt8196_adsp.dts @@ -9,6 +9,12 @@ #address-cells = <1>; #size-cells = <1>; + host_dma: dma { + compatible = "mediatek,sof-host-dma"; + dma-channels = <32>; + #dma-cells = <0>; + }; + sram0: memory@4e100000 { device_type = "memory"; compatible = "mmio-sram"; diff --git a/cmake/compiler/clang/compiler_flags.cmake b/cmake/compiler/clang/compiler_flags.cmake index 190415546ea8..9cd88c0ba622 100644 --- a/cmake/compiler/clang/compiler_flags.cmake +++ b/cmake/compiler/clang/compiler_flags.cmake @@ -22,6 +22,11 @@ set_property(TARGET compiler-cpp PROPERTY dialect_cpp23 "-std=c++23" set_compiler_property(PROPERTY optimization_fast -O3 -ffast-math) +# Clang uses -flto=thin (parallel) and -flto=full (single-threaded) instead +# of the GCC-specific -flto=auto and -flto=1 forms. +set_compiler_property(PROPERTY optimization_lto -flto=thin) +set_compiler_property(PROPERTY optimization_lto_st -flto=full) + ####################################################### # This section covers flags related to warning levels # ####################################################### @@ -149,6 +154,13 @@ set_compiler_property(PROPERTY diagnostic -fcolor-diagnostics) # clang flag to disable macro backtrace in diagnostics (can't fully disable it, so limit to 1) set_compiler_property(PROPERTY no_track_macro_expansion "-fmacro-backtrace-limit=1") -set_compiler_property(PROPERTY no_global_merge "-mno-global-merge") +# -mno-global-merge is only supported by Clang on ARM targets. +# On other architectures (e.g. Xtensa) it triggers: +# warning: argument unused during compilation: '-mno-global-merge' +if("${ARCH}" STREQUAL "arm" OR "${ARCH}" STREQUAL "arm64") + set_compiler_property(PROPERTY no_global_merge "-mno-global-merge") +else() + set_compiler_property(PROPERTY no_global_merge "") +endif() set_compiler_property(PROPERTY specs) diff --git a/cmake/compiler/clang/target.cmake b/cmake/compiler/clang/target.cmake index f7d448731523..96374da03167 100644 --- a/cmake/compiler/clang/target.cmake +++ b/cmake/compiler/clang/target.cmake @@ -102,6 +102,7 @@ if(NOT "${ARCH}" STREQUAL "posix") endif() # Override the default implementation in target_template.cmake. +if(NOT COMMAND compiler_set_linker_properties) function(compiler_set_linker_properties) compiler_simple_options(simple_options) @@ -136,3 +137,4 @@ function(compiler_set_linker_properties) set_linker_property(PROPERTY rt_library "-l${library_name}") endfunction() +endif() diff --git a/cmake/compiler/clang/target_arm.cmake b/cmake/compiler/clang/target_arm.cmake index 5c6e27294a87..6c621fc0d576 100644 --- a/cmake/compiler/clang/target_arm.cmake +++ b/cmake/compiler/clang/target_arm.cmake @@ -42,3 +42,20 @@ if(CONFIG_FP16) endif() list(APPEND TOOLCHAIN_C_FLAGS ${ARM_C_FLAGS}) list(APPEND TOOLCHAIN_GROUPED_LD_FLAGS ARM_C_FLAGS) + +# Flags not supported by llext linker +# (regexps are supported and match whole word) +set(LLEXT_REMOVE_FLAGS + -fno-pic + -fno-pie + -ffunction-sections + -fdata-sections + -Os +) + +# Flags to be added to llext code compilation +set(LLEXT_APPEND_FLAGS + -mlong-calls + -mthumb + -fno-unwind-tables +) diff --git a/cmake/linker/ld/target.cmake b/cmake/linker/ld/target.cmake index 592596576d11..b7349d6ba165 100644 --- a/cmake/linker/ld/target.cmake +++ b/cmake/linker/ld/target.cmake @@ -9,8 +9,8 @@ set_ifndef(LINKERFLAGPREFIX -Wl) if((${CMAKE_LINKER} STREQUAL "${CROSS_COMPILE}ld.bfd") OR ${GNULD_LINKER_IS_BFD}) # ld.bfd was found so let's explicitly use that for linking, see #32237 - list(APPEND TOOLCHAIN_LD_FLAGS -fuse-ld=bfd) - list(APPEND CMAKE_REQUIRED_FLAGS -fuse-ld=bfd) + # list(APPEND TOOLCHAIN_LD_FLAGS -fuse-ld=bfd) + # list(APPEND CMAKE_REQUIRED_FLAGS -fuse-ld=bfd) string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") endif() @@ -154,8 +154,13 @@ macro(toolchain_linker_finalize) set(link_libraries " -o ${zephyr_std_libs}") set(common_link " ${link_libraries}") - set(CMAKE_ASM_LINK_EXECUTABLE " ${common_link}") - set(CMAKE_C_LINK_EXECUTABLE " ${common_link}") + if(DEFINED XTENSA_GCC) + set(CMAKE_ASM_LINK_EXECUTABLE "${XTENSA_GCC} ${common_link}") + set(CMAKE_C_LINK_EXECUTABLE "${XTENSA_GCC} ${common_link}") + else() + set(CMAKE_ASM_LINK_EXECUTABLE " ${common_link}") + set(CMAKE_C_LINK_EXECUTABLE " ${common_link}") + endif() set(cpp_link "${common_link}") if(NOT "${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "host") @@ -167,7 +172,12 @@ macro(toolchain_linker_finalize) set(cpp_link " ${CRTBEGIN_PATH} ${link_libraries} ${CRTEND_PATH}") endif() endif() - set(CMAKE_CXX_LINK_EXECUTABLE " ${cpp_link}") + + if(DEFINED XTENSA_GCC) + set(CMAKE_CXX_LINK_EXECUTABLE "${XTENSA_GCC} ${cpp_link}") + else() + set(CMAKE_CXX_LINK_EXECUTABLE " ${cpp_link}") + endif() endmacro() # Function to map compiler flags into suitable linker flags diff --git a/cmake/linker/lld/target.cmake b/cmake/linker/lld/target.cmake index 96df1c123796..340a33d609d0 100644 --- a/cmake/linker/lld/target.cmake +++ b/cmake/linker/lld/target.cmake @@ -122,10 +122,10 @@ macro(toolchain_linker_finalize) endforeach() string(REPLACE ";" " " zephyr_std_libs "${zephyr_std_libs}") - set(common_link " -o ${zephyr_std_libs}") - set(CMAKE_ASM_LINK_EXECUTABLE " ${common_link}") - set(CMAKE_C_LINK_EXECUTABLE " ${common_link}") - set(CMAKE_CXX_LINK_EXECUTABLE " ${common_link}") + set(common_link " -o ${zephyr_std_libs}") + set(CMAKE_ASM_LINK_EXECUTABLE " ${common_link}") + set(CMAKE_C_LINK_EXECUTABLE " ${common_link}") + set(CMAKE_CXX_LINK_EXECUTABLE " ${common_link}") endmacro() # Function to map compiler flags into suitable linker flags diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index d919e70cb2e8..3b5381a4e5d3 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -6192,6 +6192,10 @@ function(add_llext_target target_name) $ $.xt.* $.xtensa.info + $.ARM.exidx* + $.rel.ARM.exidx* + $.ARM.extab* + $.rel.ARM.extab* $${llext_pkg_input} $${llext_pkg_output} $ diff --git a/cmake/toolchain/llvm/generic.cmake b/cmake/toolchain/llvm/generic.cmake new file mode 100644 index 000000000000..116c1854bc6a --- /dev/null +++ b/cmake/toolchain/llvm/generic.cmake @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(COMPILER clang) +set(TOOLCHAIN_VARIANT_COMPILER llvm CACHE STRING "compiler used by the toolchain variant" FORCE) +set(LINKER ld) +set(BINTOOLS gnu) + + +zephyr_get(LLVM_TOOLCHAIN_PATH) +if(LLVM_TOOLCHAIN_PATH) + set(TOOLCHAIN_HOME ${LLVM_TOOLCHAIN_PATH}/bin/) +endif() + +# When using the Zephyr SDK as our binutils provider, the SDK sysroot contains +# both newlib and picolibc headers. Advertise this to Kconfig so that +# PICOLIBC_SUPPORTED / NEWLIB_LIBC_SUPPORTED are set *before* kconfig.cmake +# runs (generic.cmake is loaded via FindHostTools during the dts phase, whereas +# target.cmake is loaded much later via FindTargetTools in the kernel phase). +set(TOOLCHAIN_HAS_PICOLIBC y CACHE INTERNAL "True if toolchain supports picolibc") +set(TOOLCHAIN_HAS_NEWLIB y CACHE INTERNAL "True if toolchain supports newlib") diff --git a/cmake/toolchain/llvm/llext-link-wrapper.sh b/cmake/toolchain/llvm/llext-link-wrapper.sh new file mode 100755 index 000000000000..593d0150bd72 --- /dev/null +++ b/cmake/toolchain/llvm/llext-link-wrapper.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# llext-link-wrapper.sh +# Wraps the shared library link step for LLEXT modules. +# 1. Makes read-only sections writable via objcopy (fixes "dangerous relocation +# in read-only section" errors from the Xtensa linker) +# 2. Links with GCC + -mtext-section-literals + linker script (fixes "l32r +# literal placed after use" errors from section ordering) +# 3. Strips X flag from .rodata in the output .so (prevents llext_link_helper.py +# from misclassifying .rodata as executable) +# +# Usage: llext-link-wrapper.sh [args...] + +CROSS_PREFIX="$1" +shift + +SCRIPT_DIR="$(dirname "$0")" +GCC="${CROSS_PREFIX}gcc" +OBJCOPY="${CROSS_PREFIX}objcopy" +READELF="${CROSS_PREFIX}readelf" + +# Find output file from -o argument +OUTPUT="" +ARGS=() +skip_next=false +for arg in "$@"; do + if $skip_next; then + OUTPUT="$arg" + ARGS+=("$arg") + skip_next=false + continue + fi + case "$arg" in + --target=*|--target\ *) continue ;; # GCC doesn't need --target + -mcpu=*) continue ;; # GCC doesn't need -mcpu for linking + -o) skip_next=true ;; + esac + + if [[ "$arg" == *.obj ]] && [[ -f "$arg" ]]; then + # Make relevant read-only sections writable in-place + while IFS= read -r section; do + [[ -n "$section" ]] && \ + "$OBJCOPY" --set-section-flags "$section=alloc,contents,load,data" "$arg" 2>/dev/null || true + done < <("$READELF" -SW "$arg" 2>/dev/null | \ + grep -E '\.rodata\.|_log_const|\.module[^_]|\.exported_sym' | \ + grep -v '\.rela\.' | grep -v '\.debug' | \ + grep ' A ' | grep -v ' W' | \ + sed 's/.*\] //' | awk '{print $1}') + fi + ARGS+=("$arg") +done + +# Link with GCC +"$GCC" -mtext-section-literals -Wl,-T,"${SCRIPT_DIR}/llext_shared.ld" "${ARGS[@]}" +rc=$? + +# Post-link: strip X flag from .rodata so llext_link_helper.py classifies it correctly +if [[ $rc -eq 0 ]] && [[ -n "$OUTPUT" ]] && [[ -f "$OUTPUT" ]]; then + "$OBJCOPY" --set-section-flags .rodata=alloc,contents,load,data "$OUTPUT" 2>/dev/null || true +fi + +exit $rc diff --git a/cmake/toolchain/llvm/llext_shared.ld b/cmake/toolchain/llvm/llext_shared.ld new file mode 100644 index 000000000000..3b2a28603fe9 --- /dev/null +++ b/cmake/toolchain/llvm/llext_shared.ld @@ -0,0 +1,18 @@ +/* llext_shared.ld + * Linker script overlay for LLEXT shared libraries built with Clang. + * Places .rodata BEFORE .text so l32r literal references work. + * Merges all .text.* and .literal.* sections into .text. + * .rodata must NOT be marked executable. + */ +SECTIONS { + .rodata : { + *(.rodata .rodata.*) + *(._log_const.*) + *(.module) + *(.exported_sym) + } + .text : { + *(.literal .literal.*) + *(.text .text.*) + } +} diff --git a/cmake/toolchain/llvm/target.cmake b/cmake/toolchain/llvm/target.cmake new file mode 100644 index 000000000000..c47976c5bdb2 --- /dev/null +++ b/cmake/toolchain/llvm/target.cmake @@ -0,0 +1,223 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_LLVM_USE_LD) + set(LINKER ld) +elseif(CONFIG_LLVM_USE_LLD) + set(LINKER lld) +endif() + +if("${ARCH}" STREQUAL "arm") + if(DEFINED CONFIG_ARMV8_M_MAINLINE) + # ARMv8-M mainline is ARMv7-M with additional features from ARMv8-M. + set(triple armv8m.main-none-eabi) + elseif(DEFINED CONFIG_ARMV8_M_BASELINE) + # ARMv8-M baseline is ARMv6-M with additional features from ARMv8-M. + set(triple armv8m.base-none-eabi) + elseif(DEFINED CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + # ARMV7_M_ARMV8_M_MAINLINE means that ARMv7-M or backward compatible ARMv8-M + # processor is used. + set(triple armv7m-none-eabi) + elseif(DEFINED CONFIG_ARMV6_M_ARMV8_M_BASELINE) + # ARMV6_M_ARMV8_M_BASELINE means that ARMv6-M or ARMv8-M supporting the + # Baseline implementation processor is used. + set(triple armv6m-none-eabi) + else() + # Default ARM target supported by all processors. + set(triple arm-none-eabi) + endif() +elseif("${ARCH}" STREQUAL "arm64") + set(triple aarch64-none-elf) +elseif("${ARCH}" STREQUAL "x86") + if(CONFIG_64BIT) + set(triple x86_64-pc-none-elf) + else() + set(triple i686-pc-none-elf) + endif() +elseif("${ARCH}" STREQUAL "riscv") + if(CONFIG_64BIT) + set(triple riscv64-unknown-elf) + else() + set(triple riscv32-unknown-elf) + endif() +elseif("${ARCH}" STREQUAL "xtensa") + # Xtensa uses Clang for compilation with LLD and the Zephyr SDK binutils. + # The target triple encodes the specific Xtensa core variant. + # + # Two names are involved per SoC: + # * XTENSA_TOOLCHAIN_TARGET - Zephyr SDK toolchain target dir name + # (matches CONFIG_SOC_TOOLCHAIN_NAME), + # e.g. "intel_ace30_ptl". + # * XTENSA_CORE_ID - upstream LLVM Xtensa backend -mcpu name, + # typically "__adsp", + # e.g. "intel_ace30_adsp". + # + # Both can be overridden via environment variables. If unset, they are + # derived from CONFIG_SOC_TOOLCHAIN_NAME and a small mapping table for + # the SoCs that ship with mismatched SDK/LLVM names. + + set(XTENSA_TOOLCHAIN_TARGET $ENV{XTENSA_TOOLCHAIN_TARGET}) + if(NOT XTENSA_TOOLCHAIN_TARGET) + if(CONFIG_SOC_TOOLCHAIN_NAME) + set(XTENSA_TOOLCHAIN_TARGET "${CONFIG_SOC_TOOLCHAIN_NAME}") + else() + # Fallback for boards that don't set CONFIG_SOC_TOOLCHAIN_NAME yet. + set(XTENSA_TOOLCHAIN_TARGET "intel_ace30_ptl") + endif() + endif() + + set(XTENSA_CORE_ID $ENV{XTENSA_CORE_ID}) + if(NOT XTENSA_CORE_ID) + # Map Zephyr SDK toolchain target -> upstream LLVM Xtensa -mcpu name. + # Only entries whose names differ between the SDK and LLVM are listed; + # anything not in this table is assumed to be identical in both. + set(_xtensa_sdk_to_llvm_cpu + # Intel ADSP + intel_ace15_mtpm intel_ace15_adsp + intel_ace40 intel_ace40_adsp + intel_ace30_ptl intel_ace30_adsp + ) + list(FIND _xtensa_sdk_to_llvm_cpu "${XTENSA_TOOLCHAIN_TARGET}" _idx) + if(_idx GREATER -1) + math(EXPR _val_idx "${_idx} + 1") + list(GET _xtensa_sdk_to_llvm_cpu ${_val_idx} XTENSA_CORE_ID) + else() + # SDK target name matches the LLVM -mcpu name (true for most + # AMD/MTK/NXP ADSP cores and dc233c / sample_controller*). + set(XTENSA_CORE_ID "${XTENSA_TOOLCHAIN_TARGET}") + endif() + unset(_xtensa_sdk_to_llvm_cpu) + unset(_idx) + unset(_val_idx) + endif() + + set(triple xtensa-${XTENSA_TOOLCHAIN_TARGET}_zephyr-elf) + set(XTENSA_CLANG_MCPU ${XTENSA_CORE_ID}) + + # Use LLVM LLD linker + set(LINKER lld) + set(BINTOOLS llvm) + + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + + # Configure cross-compile prefix for binutils (assembler, linker, objcopy, etc.) + set(CROSS_COMPILE_TARGET xtensa-${XTENSA_TOOLCHAIN_TARGET}_zephyr-elf) + + # Clang-specific flags for Xtensa + list(APPEND TOOLCHAIN_C_FLAGS -mcpu=${XTENSA_CLANG_MCPU}) + # Define __XCC__ so SOF's HiFi detection logic (format.h, fft.h, fir_config.h + # etc.) recognises our LLVM Clang as an Xtensa compiler with HiFi support and + # enters the "#if defined __XCC__" branches that read XCHAL_HAVE_HIFIx from + # . + # Also define __XCC_CLANG__ so the CAVS-family core-isa.h files (tgl, apl, + # cnl, icl) can whitelist LLVM without triggering their "#error xcc should + # not use this header" guard (see modules/hal/xtensa patch below). + list(APPEND TOOLCHAIN_C_FLAGS -D__XCC__ -D__XCC_CLANG__) + + # Use the integrated assembler for all code + list(APPEND TOOLCHAIN_C_FLAGS -fintegrated-as) + + if(CONFIG_COMPILER_CODEGEN_VLIW_ENABLED) + # Add +flix strictly to compile steps to prevent ld from misinterpreting +flix as an object file + add_compile_options("$<$:SHELL:-Xclang -target-feature -Xclang +flix>") + elseif(CONFIG_COMPILER_CODEGEN_VLIW_DISABLED) + # Add -flix strictly to compile steps to override wrapper scripts or default CPU settings + add_compile_options("$<$:SHELL:-Xclang -target-feature -Xclang -flix>") + endif() + # Don't force auto-litpools inline in text sections; place in separate .literal sections instead + + # Force DWARFv4 debug info for compatibility with Zephyr's kobject scanner + # (gen_kobject_list.py). Clang defaults to DWARFv5 which the scanner can't parse. + list(APPEND TOOLCHAIN_C_FLAGS -gdwarf-4) + + # FLIX VLIW instruction bundling - DISABLED by default. + # The packetizer pass in LLVM generates some invalid instruction pairs + # because we don't fully model the hardware FLIX slot constraints yet. + # To enable manually: add '-Xclang -target-feature -Xclang +flix' to CMAKE_C_FLAGS + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Xclang -target-feature -Xclang +flix" CACHE STRING "" FORCE) + + # Ensure the dummy compile test can find the Xtensa assembler and linker. + if(TOOLCHAIN_HOME) + set(ENV{PATH} "${TOOLCHAIN_HOME}:$ENV{PATH}") + endif() + set(_req_flags "") + if(TOOLCHAIN_HOME) + list(APPEND _req_flags -B${TOOLCHAIN_HOME}) + endif() + list(APPEND _req_flags + -mcpu=${XTENSA_CLANG_MCPU} + -nostartfiles + -nostdlib + ) + string(REPLACE ";" " " _req_flags_str "${_req_flags}") + set(CMAKE_REQUIRED_FLAGS "${_req_flags_str}") + + if(TOOLCHAIN_HOME) + list(APPEND TOOLCHAIN_LD_FLAGS -B${TOOLCHAIN_HOME}) + # Derive the per-core SDK ld binary from XTENSA_TOOLCHAIN_TARGET so + # each Xtensa core uses its matching SDK linker (e.g. tgl, ace15, ace30). + set(XTENSA_SDK_LD "${TOOLCHAIN_HOME}xtensa-${XTENSA_TOOLCHAIN_TARGET}_zephyr-elf-ld") + endif() + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -nodefaultlibs" CACHE STRING "" FORCE) + + # Override compiler_set_linker_properties to use compiler-rt builtins + # instead of libgcc; the compiler-rt builtins are distributed with the + # LLVM toolchain and cover all Xtensa intrinsics used by Zephyr/SOF. + function(compiler_set_linker_properties) + set(_clang_rt_dir "${LLVM_TOOLCHAIN_PATH}/lib/clang/23/lib/xtensa-unknown-unknown-elf") + set_linker_property(PROPERTY lib_include_dir "-L\"${_clang_rt_dir}\"") + set_linker_property(PROPERTY rt_library "-lclang_rt.builtins") + endfunction() + + message(STATUS "Xtensa LLVM: triple=${triple} mcpu=${XTENSA_CLANG_MCPU}") + + # .S assembly files need the integrated assembler + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -fintegrated-as -fno-unwind-tables" CACHE STRING "" FORCE) + + # LLEXT shared libraries are loadable modules, not standalone executables. + # Prevent the GCC driver from linking crt0.o/crtn.o into them. + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostartfiles -nodefaultlibs" CACHE STRING "" FORCE) + + # Override the shared library link rule with our wrapper script that: + # 1. Uses objcopy to make .rodata sections writable (fixes "dangerous + # relocation in read-only section") + # 2. Links with GCC + -mtext-section-literals (fixes "l32r literal placed + # after use" errors from section ordering) + set(LLEXT_LINK_WRAPPER "${CMAKE_CURRENT_LIST_DIR}/llext-link-wrapper.sh") + set(XTENSA_CROSS_PREFIX "${TOOLCHAIN_HOME}llvm-") + set(CMAKE_C_CREATE_SHARED_LIBRARY + "${LLEXT_LINK_WRAPPER} ${XTENSA_CROSS_PREFIX} -fuse-ld=lld -o " CACHE STRING "" FORCE) + set(CMAKE_CXX_CREATE_SHARED_LIBRARY + "${LLEXT_LINK_WRAPPER} ${XTENSA_CROSS_PREFIX} -fuse-ld=lld -o " CACHE STRING "" FORCE) + set(CMAKE_C_CREATE_SHARED_MODULE + "${LLEXT_LINK_WRAPPER} ${XTENSA_CROSS_PREFIX} -fuse-ld=lld -o " CACHE STRING "" FORCE) + set(CMAKE_CXX_CREATE_SHARED_MODULE + "${LLEXT_LINK_WRAPPER} ${XTENSA_CROSS_PREFIX} -fuse-ld=lld -o " CACHE STRING "" FORCE) + + # Disable ccache for link steps - ccache can't properly handle our + # wrapper script (it caches/eats the output). + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "") +endif() + +if(DEFINED triple) + set(CMAKE_C_COMPILER_TARGET ${triple}) + set(CMAKE_ASM_COMPILER_TARGET ${triple}) + set(CMAKE_CXX_COMPILER_TARGET ${triple}) + + unset(triple) +endif() + +if(CONFIG_LIBGCC_RTLIB) + set(runtime_lib "libgcc") +elseif(CONFIG_COMPILER_RT_RTLIB) + set(runtime_lib "compiler_rt") +endif() + +if(DEFINED runtime_lib) + if("${ARCH}" STREQUAL "xtensa") + list(APPEND TOOLCHAIN_C_FLAGS --rtlib=${runtime_lib}) + else() + list(APPEND TOOLCHAIN_C_FLAGS --config=${ZEPHYR_BASE}/cmake/toolchain/llvm/clang_${runtime_lib}.cfg) + list(APPEND TOOLCHAIN_LD_FLAGS --config=${ZEPHYR_BASE}/cmake/toolchain/llvm/clang_${runtime_lib}.cfg) + endif() +endif() diff --git a/drivers/dma/dma_intel_adsp_gpdma.c b/drivers/dma/dma_intel_adsp_gpdma.c index 2c9f7b698191..ab8b98522488 100644 --- a/drivers/dma/dma_intel_adsp_gpdma.c +++ b/drivers/dma/dma_intel_adsp_gpdma.c @@ -286,8 +286,8 @@ static void intel_adsp_gpdma_claim_ownership(const struct device *dev) sys_write32(val, reg); #else - sys_write32(LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG, DSP_INIT_LPGPDMA(0)); - sys_write32(LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG, DSP_INIT_LPGPDMA(1)); + sys_write16(LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG, DSP_INIT_LPGPDMA(0)); + sys_write16(LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG, DSP_INIT_LPGPDMA(1)); ARG_UNUSED(dev); #endif /* CONFIG_SOC_SERIES_INTEL_ADSP_ACE */ #endif /* CONFIG_DMA_INTEL_ADSP_GPDMA_NEED_CONTROLLER_OWNERSHIP */ diff --git a/dts/bindings/dma/mediatek,sof-host-dma.yaml b/dts/bindings/dma/mediatek,sof-host-dma.yaml new file mode 100644 index 000000000000..916876b259a1 --- /dev/null +++ b/dts/bindings/dma/mediatek,sof-host-dma.yaml @@ -0,0 +1,12 @@ +# Copyright 2026 MediaTek +# SPDX-License-Identifier: Apache-2.0 + +description: MediaTek SOF host DMA + +compatible: "mediatek,sof-host-dma" + +include: [base.yaml, dma-controller.yaml] + +properties: + dma-channels: + required: true diff --git a/include/zephyr/linker/intlist.ld b/include/zephyr/linker/intlist.ld index 9cad6f32c32f..3ff8726a5479 100644 --- a/include/zephyr/linker/intlist.ld +++ b/include/zephyr/linker/intlist.ld @@ -36,7 +36,7 @@ SECTION_PROLOGUE(.intList,,) { KEEP(*(.irq_info*)) KEEP(*(.intList*)) -} GROUP_ROM_LINK_IN(IDT_LIST, IDT_LIST) +} GROUP_ROM_LINK_IN(IDT_LIST, IDT_LIST) :NONE #else /DISCARD/ : { diff --git a/kernel/include/kswap.h b/kernel/include/kswap.h index 56e2a5da6022..4a86f07a6545 100644 --- a/kernel/include/kswap.h +++ b/kernel/include/kswap.h @@ -81,7 +81,9 @@ static ALWAYS_INLINE unsigned int do_swap(unsigned int key, struct k_spinlock *lock, bool is_spinlock) { - struct k_thread *new_thread, *old_thread; + struct k_thread *new_thread; + struct k_thread *old_thread; + __asm__ volatile("" : : "r"(&new_thread), "r"(&old_thread)); #ifdef CONFIG_SPIN_VALIDATE /* Make sure the key acts to unmask interrupts, if it doesn't, @@ -105,6 +107,7 @@ static ALWAYS_INLINE unsigned int do_swap(unsigned int key, #endif /* CONFIG_SPIN_VALIDATE */ old_thread = _current; + __asm__ volatile("" : : : "memory"); z_check_stack_sentinel(); @@ -179,7 +182,12 @@ static ALWAYS_INLINE unsigned int do_swap(unsigned int key, barrier_dmem_fence_full(); /* write barrier */ } k_spin_release(&_sched_spinlock); - arch_switch(newsh, &old_thread->switch_handle); +#ifdef CONFIG_XTENSA + arch_switch(newsh, (void **)old_thread); +#else + void **switched_from = &old_thread->switch_handle; + arch_switch(newsh, switched_from); +#endif } else { k_spin_release(&_sched_spinlock); } diff --git a/lib/libc/minimal/source/string/string.c b/lib/libc/minimal/source/string/string.c index c801ef31e392..ca8d725a12f2 100644 --- a/lib/libc/minimal/source/string/string.c +++ b/lib/libc/minimal/source/string/string.c @@ -304,6 +304,7 @@ void *memcpy(void *ZRESTRICT d, const void *ZRESTRICT s, size_t n) /* do byte-sized copying until word-aligned or finished */ + #pragma clang loop vectorize(disable) while (((uintptr_t)d_byte) & mask) { if (n == 0) { return d; @@ -317,6 +318,7 @@ void *memcpy(void *ZRESTRICT d, const void *ZRESTRICT s, size_t n) mem_word_t *d_word = (mem_word_t *)d_byte; const mem_word_t *s_word = (const mem_word_t *)s_byte; + #pragma clang loop vectorize(disable) while (n >= sizeof(mem_word_t)) { *(d_word++) = *(s_word++); n -= sizeof(mem_word_t); @@ -329,6 +331,7 @@ void *memcpy(void *ZRESTRICT d, const void *ZRESTRICT s, size_t n) /* do byte-sized copying until finished */ + #pragma clang loop vectorize(disable) while (n > 0) { *(d_byte++) = *(s_byte++); n--; @@ -352,6 +355,7 @@ void *memset(void *buf, int c, size_t n) unsigned char c_byte = (unsigned char)c; #if !defined(CONFIG_MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE) + #pragma clang loop vectorize(disable) while (((uintptr_t)d_byte) & (sizeof(mem_word_t) - 1)) { if (n == 0) { return buf; @@ -371,6 +375,7 @@ void *memset(void *buf, int c, size_t n) c_word |= c_word << 32; #endif + #pragma clang loop vectorize(disable) while (n >= sizeof(mem_word_t)) { *(d_word++) = c_word; n -= sizeof(mem_word_t); @@ -381,6 +386,7 @@ void *memset(void *buf, int c, size_t n) d_byte = (unsigned char *)d_word; #endif + #pragma clang loop vectorize(disable) while (n > 0) { *(d_byte++) = c_byte; n--; diff --git a/soc/amd/acp_6_0/adsp/linker.ld b/soc/amd/acp_6_0/adsp/linker.ld index ff3dd4342f9b..9e4b08cb3a73 100644 --- a/soc/amd/acp_6_0/adsp/linker.ld +++ b/soc/amd/acp_6_0/adsp/linker.ld @@ -14,7 +14,7 @@ OUTPUT_ARCH(xtensa) #include #include -#include +#include "memory.h" #include #include @@ -109,13 +109,13 @@ MEMORY len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/amd/acp_7_0/linker.ld b/soc/amd/acp_7_0/linker.ld index f7dac1ab0ec5..0b522b044a1a 100644 --- a/soc/amd/acp_7_0/linker.ld +++ b/soc/amd/acp_7_0/linker.ld @@ -158,13 +158,13 @@ sram1 : len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/amd/acp_7_x/linker.ld b/soc/amd/acp_7_x/linker.ld index c832e14c939c..2e1bab633e7e 100644 --- a/soc/amd/acp_7_x/linker.ld +++ b/soc/amd/acp_7_x/linker.ld @@ -160,13 +160,13 @@ sram1 : len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/cdns/dc233c/include/xtensa-dc233c.ld b/soc/cdns/dc233c/include/xtensa-dc233c.ld index 5acfdacdc7dc..ca7c4a1fa797 100644 --- a/soc/cdns/dc233c/include/xtensa-dc233c.ld +++ b/soc/cdns/dc233c/include/xtensa-dc233c.ld @@ -123,7 +123,8 @@ SECTIONS >vectors :vectors_phdr #define LIB_OBJ_FUNC_IN_SECT(library, obj_file, func) \ - *##library##:##obj_file##(.literal.##func .text.##func) \ + *##library##:##obj_file##(.literal.##func) \ + *##library##:##obj_file##(.text.##func) #ifdef CONFIG_XTENSA_MMU .vec_helpers : @@ -139,12 +140,14 @@ SECTIONS * TLB multi-hit exception. */ - *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.literal .text) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.literal) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.text) *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.iram.text .iram0.text) *libarch__xtensa__core.a:window_vectors.S.obj(.iram.text) - *libarch__xtensa__core.a:crt1.S.obj(.literal .text) + *libarch__xtensa__core.a:crt1.S.obj(.literal) + *libarch__xtensa__core.a:crt1.S.obj(.text) LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_asm2.c.obj,*) LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,fatal.c.obj,*) @@ -155,7 +158,8 @@ SECTIONS /* To support backtracing */ LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_backtrace.c.obj,*) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal) + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1) /* Userspace related stuff */ LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,xtensa_do_syscall) @@ -171,12 +175,17 @@ SECTIONS LIB_OBJ_FUNC_IN_SECT(libdrivers__console.a,,*) LIB_OBJ_FUNC_IN_SECT(libdrivers__timer.a,,*) - *(.literal.z_vrfy_* .text.z_vrfy_*) - *(.literal.z_mrsh_* .text.z_mrsh_*) - *(.literal.z_impl_* .text.z_impl_*) - *(.literal.z_obj_* .text.z_obj_*) - - *(.literal.k_sys_fatal_error_handler .text.k_sys_fatal_error_handler) + *(.literal.z_vrfy_*) + *(.text.z_vrfy_*) + *(.literal.z_mrsh_*) + *(.text.z_mrsh_*) + *(.literal.z_impl_*) + *(.text.z_impl_*) + *(.literal.z_obj_*) + *(.text.z_obj_*) + + *(.literal.k_sys_fatal_error_handler) + *(.text.k_sys_fatal_error_handler) } >vec_helpers :vec_helpers_phdr #endif /* CONFIG_XTENSA_MMU */ @@ -203,7 +212,20 @@ SECTIONS *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) *(.iram1.literal .iram1) KEEP(*(.init)) - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *libarch__xtensa__core.a:(.literal .literal.*) + *libarch__xtensa__core.a:(.text .text.*) + + *libkernel.a:(.literal .literal.*) + *libkernel.a:(.text .text.*) + + *libzephyr.a:(.literal .literal.*) + *libzephyr.a:(.text .text.*) + + *libmodules_sof.a:(.literal .literal.*) + *libmodules_sof.a:(.text .text.*) + + *(.literal .literal.* .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal) + *(.text .text.* .stub .gnu.warning .gnu.linkonce.t.*) *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) diff --git a/soc/intel/intel_adsp/ace/boot.c b/soc/intel/intel_adsp/ace/boot.c index eeadbc3be5d9..a9b80e1a02d0 100644 --- a/soc/intel/intel_adsp/ace/boot.c +++ b/soc/intel/intel_adsp/ace/boot.c @@ -20,7 +20,7 @@ #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE #define STRINGIFY_MACRO(x) Z_STRINGIFY(x) #define IMRSTACK STRINGIFY_MACRO(IMR_BOOT_LDR_MANIFEST_BASE) -__asm__(".section .imr.boot_entry_d3_restore, \"x\"\n\t" +__asm__(".section .imr.boot_entry_d3_restore, \"ax\"\n\t" ".align 4\n\t" ".global boot_entry_d3_restore\n\t" "boot_entry_d3_restore:\n\t" diff --git a/soc/intel/intel_adsp/ace/include/linker/ace-link-mirrored.ld b/soc/intel/intel_adsp/ace/include/linker/ace-link-mirrored.ld index b4093ee2bd78..2598088cc6ce 100644 --- a/soc/intel/intel_adsp/ace/include/linker/ace-link-mirrored.ld +++ b/soc/intel/intel_adsp/ace/include/linker/ace-link-mirrored.ld @@ -38,23 +38,41 @@ ENTRY(rom_entry); #ifdef CONFIG_KERNEL_COHERENCE #ifdef CONFIG_MMU -#define SEGSTART_CACHED RPO_SET(ALIGN(CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_CACHED_REGION) -#define SEGSTART_UNCACHED RPO_SET(ALIGN(CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_UNCACHED_REGION) +#define SEGSTART_CACHED RPO_SET(ALIGN(phys_dot, CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_CACHED_REGION) +#define SEGSTART_UNCACHED RPO_SET(ALIGN(phys_dot, CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_UNCACHED_REGION) #else -#define SEGSTART_CACHED RPO_SET(ALIGN(64), CONFIG_INTEL_ADSP_CACHED_REGION) -#define SEGSTART_UNCACHED RPO_SET(ALIGN(64), CONFIG_INTEL_ADSP_UNCACHED_REGION) +#define SEGSTART_CACHED RPO_SET(ALIGN(phys_dot, 64), CONFIG_INTEL_ADSP_CACHED_REGION) +#define SEGSTART_UNCACHED RPO_SET(ALIGN(phys_dot, 64), CONFIG_INTEL_ADSP_UNCACHED_REGION) #endif #else #ifdef CONFIG_MMU -#define SEGSTART_CACHED ALIGN(CONFIG_MMU_PAGE_SIZE) -#define SEGSTART_UNCACHED ALIGN(CONFIG_MMU_PAGE_SIZE) +#define SEGSTART_CACHED ALIGN(phys_dot, CONFIG_MMU_PAGE_SIZE) +#define SEGSTART_UNCACHED ALIGN(phys_dot, CONFIG_MMU_PAGE_SIZE) #else -#define SEGSTART_CACHED . -#define SEGSTART_UNCACHED . +#define SEGSTART_CACHED phys_dot +#define SEGSTART_UNCACHED phys_dot #endif #define ucram ram #endif +#ifdef CONFIG_KERNEL_COHERENCE +#ifdef CONFIG_MMU +#define ADDR_CACHED(sym) RPO_SET(ALIGN(sym, CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_CACHED_REGION) +#define ADDR_UNCACHED(sym) RPO_SET(ALIGN(sym, CONFIG_MMU_PAGE_SIZE), CONFIG_INTEL_ADSP_UNCACHED_REGION) +#else +#define ADDR_CACHED(sym) RPO_SET(ALIGN(sym, 64), CONFIG_INTEL_ADSP_CACHED_REGION) +#define ADDR_UNCACHED(sym) RPO_SET(ALIGN(sym, 64), CONFIG_INTEL_ADSP_UNCACHED_REGION) +#endif +#else +#ifdef CONFIG_MMU +#define ADDR_CACHED(sym) ALIGN(sym, CONFIG_MMU_PAGE_SIZE) +#define ADDR_UNCACHED(sym) ALIGN(sym, CONFIG_MMU_PAGE_SIZE) +#else +#define ADDR_CACHED(sym) sym +#define ADDR_UNCACHED(sym) sym +#endif +#endif + /* intlist.ld needs an IDT_LIST memory region */ #define IDT_BASE 0xe0000000 #define IDT_SIZE 0x2000 @@ -107,12 +125,14 @@ MEMORY { } SECTIONS { + phys_dot = 0; /* Boot loader code in IMR memory */ .imr : { _imr_start = .; /* Entry point MUST be here per external configuration */ KEEP (*(.boot_entry.text)) + *(.imr.literal .imr.*.literal) *(.imr .imr.*) } >imr @@ -210,10 +230,12 @@ SECTIONS { KEEP(*(.init)) KEEP(*(.lps_vector)) - *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.gnu.linkonce.literal.* .gnu.linkonce.t.*.literal) MMU_PAGE_ALIGN - *(.literal .text) - *(.literal.* .text.*) + *(.literal) + *(.literal.*) + *(.text) + *(.text.* .stub .gnu.warning .gnu.linkonce.t.*) *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) @@ -263,11 +285,13 @@ SECTIONS { *(*.initcall) _module_init_end = .; } >ram + . = _module_init_end; + phys_dot = . & 0x1fffffff; #define RAMABLE_REGION ram #define ROMABLE_REGION ram - __common_rom_region_start = SEGSTART_CACHED; + __common_rom_region_start = ADDR_CACHED(_module_init_end); #include /* Located in generated directory. This file is populated by calling * zephyr_linker_sources(ROM_SECTIONS ...). Useful for grouping iterable RO structs. @@ -276,8 +300,10 @@ SECTIONS { __rodata_region_end = .; __common_rom_region_end = .; __rodata_region_end = .; + . = __common_rom_region_end; + phys_dot = . & 0x1fffffff; - .noinit SEGSTART_UNCACHED (NOLOAD) : HDR_MMU_PAGE_ALIGN { + .noinit ADDR_UNCACHED(__common_rom_region_end) (NOLOAD) : HDR_MMU_PAGE_ALIGN { __data_start = .; *(.noinit) *(.noinit.*) @@ -287,12 +313,15 @@ SECTIONS { */ #include + __noinit_end = .; } >ucram + . = __noinit_end; + phys_dot = . & 0x1fffffff; #include - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(__noinit_end); - .data SEGSTART_UNCACHED : HDR_MMU_PAGE_ALIGN { + .data ADDR_UNCACHED(__noinit_end) : HDR_MMU_PAGE_ALIGN { *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -312,29 +341,36 @@ SECTIONS { __data_end = .; MMU_PAGE_ALIGN } >ucram + . = __data_end; + phys_dot = . & 0x1fffffff; - .lit4 SEGSTART_CACHED : { + .lit4 ADDR_CACHED(__data_end) : { _lit4_start = .; *(*.lit4) *(.lit4.*) *(.gnu.linkonce.lit4.*) _lit4_end = .; } >ram + . = _lit4_end; + phys_dot = . & 0x1fffffff; /* These values need to change in our scheme, where the common-ram * sections need to be linked in safe/uncached memory but common-rom * wants to use the cache */ -. = SEGSTART_UNCACHED; +. = ADDR_UNCACHED(_lit4_end); #undef RAMABLE_REGION #undef ROMABLE_REGION #define RAMABLE_REGION ucram #define ROMABLE_REGION ucram - .fw_ready SEGSTART_UNCACHED : { + .fw_ready ADDR_UNCACHED(_lit4_end) : { KEEP(*(".fw_ready")); KEEP (*(.fw_ready_metadata)) + __fw_ready_end = .; } > ucram + . = __fw_ready_end; + phys_dot = . & 0x1fffffff; __common_ram_region_start = .; @@ -353,15 +389,20 @@ SECTIONS { #include #include __common_ram_region_end = .; + . = __common_ram_region_end; + phys_dot = . & 0x1fffffff; - .tm_clone_table : { + .tm_clone_table ADDR_CACHED(__common_ram_region_end) : { *(.tm_clone_table) + __tm_clone_table_end = .; } >ram + . = __tm_clone_table_end; + phys_dot = . & 0x1fffffff; /* This section is cached. By default it contains only declared * thread stacks, but applications can put symbols here too. */ - .cached SEGSTART_CACHED : { + .cached ADDR_CACHED(__tm_clone_table_end) : { _cached_start = .; *(.cached .cached.*) #ifdef CONFIG_USERSPACE @@ -371,6 +412,8 @@ SECTIONS { #endif _cached_end = .; } >ram + . = _cached_end; + phys_dot = . & 0x1fffffff; /* Rimage requires 4k alignment between "DATA" and "BSS", can't do * this in the section declaration below because we're also changing @@ -379,8 +422,9 @@ SECTIONS { * seems, --warn-section-align is on by default) */ . = ALIGN(4096); + _bss_start_phys = .; - .bss SEGSTART_UNCACHED (NOLOAD) : + .bss ADDR_UNCACHED(_bss_start_phys) (NOLOAD) : { __bss_start = .; @@ -429,21 +473,26 @@ SECTIONS { MMU_PAGE_ALIGN __bss_end = .; } >ucram + . = __bss_end; + phys_dot = . & 0x1fffffff; - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(__bss_end); _end = ALIGN(8); /* Heap start and end markers. Used to reserve system heap memory. */ - .heap_mem SEGSTART_UNCACHED (NOLOAD) : + .heap_mem ADDR_UNCACHED(__bss_end) (NOLOAD) : { _shared_heap_start = .; *(.shared_heap_mem) _shared_heap_end = .; _heap_start = .; *(.heap_mem) + _heap_end = .; } >ucram + . = _heap_end; + phys_dot = . & 0x1fffffff; - .unused_ram_start_marker SEGSTART_CACHED (NOLOAD) : + .unused_ram_start_marker ADDR_CACHED(_heap_end) (NOLOAD) : { . = ALIGN(4096); _unused_ram_start_marker = .; @@ -451,17 +500,19 @@ SECTIONS { *(.unused_ram_start_marker.*) z_mapped_end = .; } >ram + . = z_mapped_end; + phys_dot = . & 0x1fffffff; /* Heap start and end markers. Used with libc malloc code. */ - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(z_mapped_end); _end = ALIGN(8); - . = SEGSTART_CACHED; + . = ADDR_CACHED(z_mapped_end); z_mapped_end = .; . = L2_SRAM_BASE + L2_SRAM_SIZE; - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(.); _heap_end = .; _heap_sentry = .; - . = SEGSTART_CACHED; + . = ADDR_CACHED(.); _image_ram_end = .; /* dma buffers */ @@ -474,7 +525,7 @@ SECTIONS { /* Non-loadable sections below. Back to cached memory so * the cache remap script doesn't try to move them around needlessly. */ - . = SEGSTART_CACHED; + . = ADDR_CACHED(z_mapped_end); /* rimage module manifest headers */ .module.boot : { KEEP(*(.module.boot)) } >noload diff --git a/soc/intel/intel_adsp/ace/mmu_ace30.c b/soc/intel/intel_adsp/ace/mmu_ace30.c index bc15d1032ba9..5b97fff14aae 100644 --- a/soc/intel/intel_adsp/ace/mmu_ace30.c +++ b/soc/intel/intel_adsp/ace/mmu_ace30.c @@ -166,6 +166,28 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { ) /* Map IMR */ + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_LIT_BASE, + IMR_BOOT_LDR_LIT_BASE + IMR_BOOT_LDR_LIT_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X | XTENSA_MMU_MAP_SHARED, + "imr lit" + ) + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_TEXT_BASE, + IMR_BOOT_LDR_TEXT_BASE + IMR_BOOT_LDR_TEXT_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X | XTENSA_MMU_MAP_SHARED, + "imr text" + ) + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_DATA_BASE, + IMR_BOOT_LDR_DATA_BASE + IMR_BOOT_LDR_DATA_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_SHARED, + "imr data base" + ) + MEM_MAP_CONST_REGION( IMR_ROM_EXT_CODE_BASE, IMR_ROM_EXT_CODE_BASE + IMR_ROM_EXT_CODE_SIZE, @@ -211,7 +233,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { MEM_MAP_CONST_REGION( IMR_BOOT_LDR_STACK_BASE, IMR_BOOT_LDR_STACK_BASE + IMR_BOOT_LDR_STACK_SIZE, - XTENSA_MMU_PERM_W, + XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_SHARED, "imr stack" ) diff --git a/soc/intel/intel_adsp/ace/mmu_ace40.c b/soc/intel/intel_adsp/ace/mmu_ace40.c index 691e8709adc7..681c1ebd0b4c 100644 --- a/soc/intel/intel_adsp/ace/mmu_ace40.c +++ b/soc/intel/intel_adsp/ace/mmu_ace40.c @@ -166,6 +166,28 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { ) /* Map IMR */ + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_LIT_BASE, + IMR_BOOT_LDR_LIT_BASE + IMR_BOOT_LDR_LIT_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X | XTENSA_MMU_MAP_SHARED, + "imr lit" + ) + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_TEXT_BASE, + IMR_BOOT_LDR_TEXT_BASE + IMR_BOOT_LDR_TEXT_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X | XTENSA_MMU_MAP_SHARED, + "imr text" + ) + + MEM_MAP_CONST_REGION( + IMR_BOOT_LDR_DATA_BASE, + IMR_BOOT_LDR_DATA_BASE + IMR_BOOT_LDR_DATA_SIZE, + XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_SHARED, + "imr data base" + ) + MEM_MAP_CONST_REGION( IMR_BOOT_LDR_MANIFEST_BASE - IMR_BOOT_LDR_MANIFEST_SIZE, IMR_BOOT_LDR_MANIFEST_BASE, @@ -197,7 +219,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { MEM_MAP_CONST_REGION( IMR_BOOT_LDR_STACK_BASE, IMR_BOOT_LDR_STACK_BASE + IMR_BOOT_LDR_STACK_SIZE, - XTENSA_MMU_PERM_W, + XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_SHARED, "imr stack" ) diff --git a/soc/intel/intel_adsp/ace/multiprocessing.c b/soc/intel/intel_adsp/ace/multiprocessing.c index 7c18c6be4d2e..dd83c35aac20 100644 --- a/soc/intel/intel_adsp/ace/multiprocessing.c +++ b/soc/intel/intel_adsp/ace/multiprocessing.c @@ -72,6 +72,10 @@ static void ipc_isr(void *arg) #define CAP_INST_SHIFT 24 #define CAP_INST_MASK BIT_MASK(4) +#if CONFIG_MP_MAX_NUM_CPUS == 1 +bool soc_cpus_active[CONFIG_MP_MAX_NUM_CPUS]; +#endif + unsigned int soc_num_cpus; __imr void soc_num_cpus_init(void) diff --git a/soc/intel/intel_adsp/cavs/Kconfig b/soc/intel/intel_adsp/cavs/Kconfig index ae7ad9384525..27403c3d6175 100644 --- a/soc/intel/intel_adsp/cavs/Kconfig +++ b/soc/intel/intel_adsp/cavs/Kconfig @@ -4,6 +4,7 @@ config SOC_SERIES_INTEL_ADSP_CAVS select XTENSA + select XTENSA_CPU_HAS_HIFI3 select XTENSA_HAL if ("$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" && ("$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xt-clang")) select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 diff --git a/soc/intel/intel_adsp/cavs/include/xtensa-cavs-linker.ld b/soc/intel/intel_adsp/cavs/include/xtensa-cavs-linker.ld index 63ce7a0faa26..b294cfed4eda 100644 --- a/soc/intel/intel_adsp/cavs/include/xtensa-cavs-linker.ld +++ b/soc/intel/intel_adsp/cavs/include/xtensa-cavs-linker.ld @@ -36,14 +36,17 @@ ENTRY(rom_entry); */ #ifdef CONFIG_KERNEL_COHERENCE #define RPO_SET(addr, reg) ((addr & 0x1fffffff) | (reg << 29)) -#define SEGSTART_CACHED RPO_SET(ALIGN(64), CONFIG_INTEL_ADSP_CACHED_REGION) -#define SEGSTART_UNCACHED RPO_SET(ALIGN(64), CONFIG_INTEL_ADSP_UNCACHED_REGION) +#define ADDR_CACHED_ALIGN(sym, align) RPO_SET(ALIGN(sym, align), CONFIG_INTEL_ADSP_CACHED_REGION) +#define ADDR_UNCACHED_ALIGN(sym, align) RPO_SET(ALIGN(sym, align), CONFIG_INTEL_ADSP_UNCACHED_REGION) #else -#define SEGSTART_CACHED . -#define SEGSTART_UNCACHED . +#define ADDR_CACHED_ALIGN(sym, align) ALIGN(sym, align) +#define ADDR_UNCACHED_ALIGN(sym, align) ALIGN(sym, align) #define ucram RAM #endif +#define ADDR_CACHED(sym) ADDR_CACHED_ALIGN(sym, 64) +#define ADDR_UNCACHED(sym) ADDR_UNCACHED_ALIGN(sym, 64) + /* intlist.ld needs an IDT_LIST memory region */ #define IDT_BASE 0xe0000000 #define IDT_SIZE 0x2000 @@ -90,6 +93,7 @@ SECTIONS { _imr_start = .; /* Entry point MUST be here per external configuration */ KEEP (*(.boot_entry.text)) + *(.imr.literal .imr.*.literal) *(.imr .imr.*) _imr_end = .; } >imr @@ -120,7 +124,8 @@ SECTIONS { *(.iram0.text) KEEP(*(.init)) KEEP(*(.lps_vector)) - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.literal .literal.* .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal) + *(.text .text.* .stub .gnu.warning .gnu.linkonce.t.*) *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) @@ -180,14 +185,16 @@ SECTIONS { .fw_ready : { KEEP(*(".fw_ready")); KEEP (*(.fw_ready_metadata)) + __fw_ready_end = .; } >RAM - .noinit SEGSTART_UNCACHED : { + .noinit ADDR_UNCACHED(__fw_ready_end) : { *(.noinit) *(.noinit.*) + __noinit_end = .; } >ucram - .data SEGSTART_UNCACHED : { + .data ADDR_UNCACHED(__noinit_end) : { __data_start = .; *(.data) *(.data.*) @@ -211,7 +218,7 @@ SECTIONS { __data_end = .; } >ucram - .lit4 SEGSTART_CACHED : { + .lit4 ADDR_CACHED(__data_end) : { _lit4_start = .; *(*.lit4) *(.lit4.*) @@ -223,22 +230,25 @@ SECTIONS { * sections need to be linked in safe/uncached memory but common-rom * wants to use the cache */ -. = SEGSTART_UNCACHED; +. = ADDR_UNCACHED(_lit4_end); #undef RAMABLE_REGION #undef ROMABLE_REGION #define RAMABLE_REGION ucram #define ROMABLE_REGION ucram #include + __common_ram_region_end = .; + . = ADDR_CACHED(__common_ram_region_end); - .tm_clone_table : { + .tm_clone_table ADDR_CACHED(__common_ram_region_end) : { *(.tm_clone_table) + __tm_clone_table_end = .; } >RAM /* This section is cached. By default it contains only declared * thread stacks, but applications can put symbols here too. */ - .cached SEGSTART_CACHED : { + .cached ADDR_CACHED(__tm_clone_table_end) : { _cached_start = .; *(.cached .cached.*) _cached_end = .; @@ -252,7 +262,7 @@ SECTIONS { */ . = ALIGN(4096); - .bss SEGSTART_UNCACHED (NOLOAD) : + .bss ADDR_UNCACHED_ALIGN(_cached_end, 4096) (NOLOAD) : { __bss_start = .; *(.dynsbss) @@ -276,10 +286,10 @@ SECTIONS { } >ucram /* Heap start and end markers. Mostly unused, though newlib likes them */ - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(__bss_end); _end = ALIGN(8); . = L2_SRAM_BASE + L2_SRAM_SIZE; - . = SEGSTART_UNCACHED; + . = ADDR_UNCACHED(.); _heap_sentry = .; /* dma buffers */ @@ -293,7 +303,7 @@ SECTIONS { /* Non-loadable sections below. Back to cached memory so * the cache remap script doesn't try to move them around needlessly. */ - . = SEGSTART_CACHED; + . = ADDR_CACHED(_cached_end); /* rimage module manifest headers */ .module.boot : { KEEP(*(.module.boot)) } >noload @@ -357,4 +367,9 @@ SECTIONS { #include #endif #include + + /* Discard stack-executability notes emitted by Clang/GCC; Xtensa + * bare-metal targets have no use for them and the older CAVS ld.bfd + * emits a noisy "orphan section" warning otherwise. */ + /DISCARD/ : { *(.note.GNU-stack) } } diff --git a/soc/intel/intel_adsp/common/boot.c b/soc/intel/intel_adsp/common/boot.c index af54fd05221f..210889ce9956 100644 --- a/soc/intel/intel_adsp/common/boot.c +++ b/soc/intel/intel_adsp/common/boot.c @@ -68,7 +68,7 @@ __asm__(".pushsection .boot_entry.text, \"ax\" \n\t" */ #define STRINGIFY_MACRO(x) Z_STRINGIFY(x) #define IMRSTACK STRINGIFY_MACRO(IMR_BOOT_LDR_MANIFEST_BASE) -__asm__(".section .imr.z_boot_asm_entry, \"x\" \n\t" +__asm__(".section .imr.z_boot_asm_entry, \"ax\" \n\t" ".align 4 \n\t" "z_boot_asm_entry: \n\t" " movi a0, 0x4002f \n\t" diff --git a/soc/intel/intel_adsp/common/debug_window.c b/soc/intel/intel_adsp/common/debug_window.c index b88ae62dcc22..08f1b5359900 100644 --- a/soc/intel/intel_adsp/common/debug_window.c +++ b/soc/intel/intel_adsp/common/debug_window.c @@ -70,6 +70,15 @@ static int adsp_dw_find_slot_by_type(uint32_t type) void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size) { int slot_idx; + static bool dw_initialized = false; + + if (!dw_initialized) { + if (ADSP_DW->descs[0].type == 0xffffffff) { + LOG_WRN("Debug Window uninitialized, initializing now..."); + memset((void *)ADSP_DW, 0, CONFIG_MEMORY_WIN_2_SIZE); + } + dw_initialized = true; + } if (!dw_desc->type) { return NULL; diff --git a/soc/intel/intel_adsp/common/include/soc_util.h b/soc/intel/intel_adsp/common/include/soc_util.h index 9de2efb5e672..5dbd14bb07a6 100644 --- a/soc/intel/intel_adsp/common/include/soc_util.h +++ b/soc/intel/intel_adsp/common/include/soc_util.h @@ -11,24 +11,47 @@ /* memcopy used by boot loader */ static ALWAYS_INLINE void bmemcpy(void *dest, void *src, size_t bytes) { - volatile uint32_t *d = (uint32_t *)dest; - volatile uint32_t *s = (uint32_t *)src; - sys_cache_data_invd_range(src, bytes); - for (size_t i = 0; i < (bytes >> 2); i++) { - d[i] = s[i]; + + if ((((uintptr_t)dest | (uintptr_t)src) & 3) == 0) { + uint32_t *d32 = (uint32_t *)dest; + uint32_t *s32 = (uint32_t *)src; + size_t words = bytes / 4; + size_t remainder = bytes % 4; + + for (size_t i = 0; i < words; i++) { + d32[i] = s32[i]; + } + + uint8_t *d8 = (uint8_t *)(d32 + words); + uint8_t *s8 = (uint8_t *)(s32 + words); + for (size_t i = 0; i < remainder; i++) { + d8[i] = s8[i]; + } + } else { + uint8_t *d8 = (uint8_t *)dest; + uint8_t *s8 = (uint8_t *)src; + for (size_t i = 0; i < bytes; i++) { + d8[i] = s8[i]; + } } sys_cache_data_flush_range(dest, bytes); } -/* bzero used by bootloader */ static ALWAYS_INLINE void bbzero(void *dest, size_t bytes) { - volatile uint32_t *d = (uint32_t *)dest; + uint32_t *d32 = (uint32_t *)dest; + size_t words = bytes / 4; + size_t remainder = bytes % 4; + + for (size_t i = 0; i < words; i++) { + d32[i] = 0; + } - for (size_t i = 0; i < (bytes >> 2); i++) { - d[i] = 0; + uint8_t *d8 = (uint8_t *)(d32 + words); + for (size_t i = 0; i < remainder; i++) { + d8[i] = 0; } sys_cache_data_flush_range(dest, bytes); diff --git a/soc/nxp/imx/imx8/adsp/linker.ld b/soc/nxp/imx/imx8/adsp/linker.ld index 7b9e71974426..70474137fd78 100644 --- a/soc/nxp/imx/imx8/adsp/linker.ld +++ b/soc/nxp/imx/imx8/adsp/linker.ld @@ -95,13 +95,13 @@ MEMORY len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/nxp/imx/imx8m/adsp/linker.ld b/soc/nxp/imx/imx8m/adsp/linker.ld index f73e527151a2..5905f798c109 100644 --- a/soc/nxp/imx/imx8m/adsp/linker.ld +++ b/soc/nxp/imx/imx8m/adsp/linker.ld @@ -95,13 +95,13 @@ MEMORY len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/nxp/imx/imx8ulp/adsp/linker.ld b/soc/nxp/imx/imx8ulp/adsp/linker.ld index 059d783df575..41d2e289ba58 100644 --- a/soc/nxp/imx/imx8ulp/adsp/linker.ld +++ b/soc/nxp/imx/imx8ulp/adsp/linker.ld @@ -95,13 +95,13 @@ MEMORY len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/soc/nxp/imx/imx8x/adsp/linker.ld b/soc/nxp/imx/imx8x/adsp/linker.ld index a78518d2bc3b..040e834828f0 100644 --- a/soc/nxp/imx/imx8x/adsp/linker.ld +++ b/soc/nxp/imx/imx8x/adsp/linker.ld @@ -95,13 +95,13 @@ MEMORY len = IDT_SIZE #endif - static_uuid_entries_seg (!ari) : + static_uuid_entries_seg : org = UUID_ENTRY_ELF_BASE, len = UUID_ENTRY_ELF_SIZE - static_log_entries_seg (!ari) : + static_log_entries_seg : org = LOG_ENTRY_ELF_BASE, len = LOG_ENTRY_ELF_SIZE - fw_metadata_seg (!ari) : + fw_metadata_seg : org = EXT_MANIFEST_ELF_BASE, len = EXT_MANIFEST_ELF_SIZE } diff --git a/subsys/llext/llext_link.c b/subsys/llext/llext_link.c index 31f55d5ead36..17c58d969a7f 100644 --- a/subsys/llext/llext_link.c +++ b/subsys/llext/llext_link.c @@ -328,14 +328,16 @@ static int llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_ continue; } - uint8_t *rel_addr = (uint8_t *)ext->mem[LLEXT_MEM_TEXT] - - ldr->sects[LLEXT_MEM_TEXT].sh_offset; + uint8_t *rel_addr; if (tgt) { /* Relocatable / partially linked ELF. */ - rel_addr += rela.r_offset + tgt->sh_offset; + unsigned int tgt_sect_idx = tgt - ext->sect_hdrs; + rel_addr = (uint8_t *)llext_loaded_sect_ptr(ldr, ext, tgt_sect_idx) + rela.r_offset; } else { /* Shared / dynamically linked ELF */ + rel_addr = (uint8_t *)ext->mem[LLEXT_MEM_TEXT] - + ldr->sects[LLEXT_MEM_TEXT].sh_offset; ssize_t offset = llext_file_offset(ldr, rela.r_offset); if (offset < 0) { diff --git a/subsys/llext/llext_load.c b/subsys/llext/llext_load.c index 67adbd82855f..c8ee6840a148 100644 --- a/subsys/llext/llext_load.c +++ b/subsys/llext/llext_load.c @@ -46,13 +46,34 @@ __weak int arch_elf_veneer_init(struct llext_loader *ldr, struct llext *ext) const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct llext *ext, unsigned int sh_ndx) { + if (sh_ndx >= ext->sect_cnt) { + return NULL; + } + + elf_shdr_t *shdr = ext->sect_hdrs + sh_ndx; enum llext_mem mem_idx = ldr->sect_map[sh_ndx].mem_idx; - if (mem_idx == LLEXT_MEM_COUNT) { - return NULL; + /* For relocatable ELFs (ET_REL), all sections have sh_addr=0. + * Always prefer the sect_map runtime DRAM address when the section + * has been loaded (mem_idx != LLEXT_MEM_COUNT), so that relocation + * uses the runtime address rather than the file-image (IMR/ROM) + * pointer that llext_peek() would return. + * + * Only fall back to llext_peek() for sections with a valid linked + * address (sh_addr >= 0x08000000) that are NOT in the sect_map + * (e.g. pre-located read-only sections in ROM/IMR). + * For ET_REL sections (sh_addr=0), return NULL so callers fall back + * to llext_peek() themselves with appropriate error handling. + */ + if (mem_idx != LLEXT_MEM_COUNT) { + return (const uint8_t *)ext->mem[mem_idx] + ldr->sect_map[sh_ndx].offset; } - return (const uint8_t *)ext->mem[mem_idx] + ldr->sect_map[sh_ndx].offset; + if (shdr->sh_addr >= 0x08000000) { + return llext_peek(ldr, shdr->sh_offset); + } + + return NULL; } /* @@ -511,7 +532,7 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext, continue; } - if (REGIONS_OVERLAP_ON(x, y, sh_offset)) { + if (ldr->hdr.e_type != ET_REL && REGIONS_OVERLAP_ON(x, y, sh_offset)) { LOG_ERR("Region %d ELF file range (%#zx-%#zx) " "overlaps with %d (%#zx-%#zx)", i, REGION_BOT(x, sh_offset), REGION_TOP(x, sh_offset), @@ -784,30 +805,40 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr = ext->sect_hdrs + shndx; uintptr_t section_addr = shdr->sh_addr; - if (ldr_parm->pre_located && - (!ldr_parm->section_detached || !ldr_parm->section_detached(shdr))) { - sym_tab->syms[j].addr = (uint8_t *)sym.st_value + - (ldr->hdr.e_type == ET_REL ? section_addr : 0); - } else { - const void *base; - - base = llext_loaded_sect_ptr(ldr, ext, shndx); + if (ldr->hdr.e_type == ET_REL) { + const void *base = llext_loaded_sect_ptr(ldr, ext, shndx); if (!base) { - /* If the section is not mapped, try to peek. - * Be noisy about it, since this is addressing - * data that was missed by llext_map_sections. - */ base = llext_peek(ldr, shdr->sh_offset); - if (base) { - LOG_DBG("section %d peeked at %p", shndx, base); - } else { + if (!base) { LOG_ERR("No data for section %d", shndx); return -ENOTSUP; } } + sym_tab->syms[j].addr = (uint8_t *)base + sym.st_value; + } else { + if (ldr_parm->pre_located && + (!ldr_parm->section_detached || !ldr_parm->section_detached(shdr))) { + sym_tab->syms[j].addr = (uint8_t *)sym.st_value; + } else { + const void *base; + + base = llext_loaded_sect_ptr(ldr, ext, shndx); + if (!base) { + /* If the section is not mapped, try to peek. + * Be noisy about it, since this is addressing + * data that was missed by llext_map_sections. + */ + base = llext_peek(ldr, shdr->sh_offset); + if (base) { + LOG_DBG("section %d peeked at %p", shndx, base); + } else { + LOG_ERR("No data for section %d", shndx); + return -ENOTSUP; + } + } - sym_tab->syms[j].addr = (uint8_t *)base + sym.st_value - - (ldr->hdr.e_type == ET_REL ? 0 : section_addr); + sym_tab->syms[j].addr = (uint8_t *)base + sym.st_value - section_addr; + } } LOG_DBG("function symbol %d name %s addr %p",