diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index a2368adc81240..0b28d33d7052e 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -79,6 +79,26 @@ config CPU_CORTEX_A78 help This option signifies the use of a Cortex-A78 CPU +config CPU_CORTEX_A510 + bool + select CPU_CORTEX_A + select ARMV9_A + help + This option signifies the use of a Cortex-A510 CPU, which is ARM's + efficiency core implementing the ARMv9-A architecture. It provides + power-efficient processing optimized for embedded applications with + ARMv9-A features. + +config CPU_CORTEX_A320 + bool + select CPU_CORTEX_A + select ARMV9_A + help + This option signifies the use of a Cortex-A320 CPU, which implements + the ARMv9.2-A architecture. It provides advanced features including + enhanced SVE2, improved security extensions, and specialized performance + optimizations. + config CPU_CORTEX_R82 bool select CPU_AARCH64_CORTEX_R @@ -101,10 +121,15 @@ config MAIN_STACK_SIZE config IDLE_STACK_SIZE default 4096 +config PRIVILEGED_STACK_SIZE + default 4096 if FPU_SHARING + default 2048 + config ISR_STACK_SIZE default 4096 config TEST_EXTRA_STACK_SIZE + default 4096 if FPU_SHARING default 2048 config SYSTEM_WORKQUEUE_STACK_SIZE @@ -223,6 +248,20 @@ config ARMV8_A so that it can support some features included in the AArch64 state. It supports the T32 and A32 instruction sets. +config ARMV9_A + bool + select ATOMIC_OPERATIONS_BUILTIN + select CPU_HAS_MMU + select ARCH_HAS_USERSPACE if ARM_MMU + select ARCH_HAS_NOCACHE_MEMORY_SUPPORT if ARM_MMU + imply ARM64_SVE if FPU_SHARING + help + This option signifies the use of an ARMv9-A processor + implementation. + ARMv9-A builds on ARMv8-A and introduces additional security, + performance, and machine learning capabilities while maintaining + backward compatibility with ARMv8-A software. + rsource "xen/Kconfig" endif # CPU_CORTEX_A @@ -380,4 +419,27 @@ config ARM64_BOOT_DISABLE_DCACHE cache and then disable data cache, it will will be re-enabled after MMU is configured and enabled. +config ARM64_SVE + bool "Scalable Vector Extension (SVE) support" + depends on ARMV9_A + help + Enable support for ARM64 Scalable Vector Extension (SVE). + This allows threads to use SVE instructions and automatically + handles context switching of SVE registers (Z0-Z31, P0-P15, FFR) + if CONFIG_FPU_SHARING is also set. Requires ARMv9-A architecture. + +config ARM64_SVE_VL_MAX + int "Maximum SVE vector length in bytes" + depends on ARM64_SVE + default 16 + range 16 256 + help + Maximum supported SVE vector length in bytes. This determines + the SVE context size within each thread structure. Valid values + are any power of two from 16 to 256 inclusive (128 to 2048 bits). + This can be smaller than the hardware supported vector length to + save some per-thread memory in which case the hardware will be + limited to the specified length. Having a larger value than what + the hardware supports will only waste memory. + endif # CPU_CORTEX_A || CPU_AARCH64_CORTEX_R diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index cca65252021aa..c9cb6827967ca 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -337,7 +337,7 @@ static bool z_arm64_stack_corruption_check(struct arch_esf *esf, uint64_t esr, u * a new nested exception triggered by FPU accessing (var_args). */ arch_flush_local_fpu(); - write_cpacr_el1(read_cpacr_el1() | CPACR_EL1_FPEN_NOTRAP); + write_cpacr_el1(read_cpacr_el1() | CPACR_EL1_FPEN); #endif arch_curr_cpu()->arch.corrupted_sp = 0UL; EXCEPTION_DUMP("STACK OVERFLOW FROM KERNEL," diff --git a/arch/arm64/core/fpu.S b/arch/arm64/core/fpu.S index cfa78e8088d6a..abb1db9364862 100644 --- a/arch/arm64/core/fpu.S +++ b/arch/arm64/core/fpu.S @@ -7,12 +7,20 @@ #include #include +#include _ASM_FILE_PROLOGUE GTEXT(z_arm64_fpu_save) SECTION_FUNC(TEXT, z_arm64_fpu_save) + mrs x1, fpsr + mrs x2, fpcr + str w1, [x0, #__z_arm64_fp_context_fpsr_OFFSET] + str w2, [x0, #__z_arm64_fp_context_fpcr_OFFSET] + + /* Save NEON registers */ + add x0, x0, #__z_arm64_fp_context_neon_OFFSET stp q0, q1, [x0, #(16 * 0)] stp q2, q3, [x0, #(16 * 2)] stp q4, q5, [x0, #(16 * 4)] @@ -30,16 +38,18 @@ SECTION_FUNC(TEXT, z_arm64_fpu_save) stp q28, q29, [x0, #(16 * 28)] stp q30, q31, [x0, #(16 * 30)] - mrs x1, fpsr - mrs x2, fpcr - str w1, [x0, #(16 * 32 + 0)] - str w2, [x0, #(16 * 32 + 4)] - ret GTEXT(z_arm64_fpu_restore) SECTION_FUNC(TEXT, z_arm64_fpu_restore) + ldr w1, [x0, #__z_arm64_fp_context_fpsr_OFFSET] + ldr w2, [x0, #__z_arm64_fp_context_fpcr_OFFSET] + msr fpsr, x1 + msr fpcr, x2 + + /* Restore NEON registers */ + add x0, x0, #__z_arm64_fp_context_neon_OFFSET ldp q0, q1, [x0, #(16 * 0)] ldp q2, q3, [x0, #(16 * 2)] ldp q4, q5, [x0, #(16 * 4)] @@ -57,9 +67,164 @@ SECTION_FUNC(TEXT, z_arm64_fpu_restore) ldp q28, q29, [x0, #(16 * 28)] ldp q30, q31, [x0, #(16 * 30)] - ldr w1, [x0, #(16 * 32 + 0)] - ldr w2, [x0, #(16 * 32 + 4)] - msr fpsr, x1 - msr fpcr, x2 + ret + +#ifdef CONFIG_ARM64_SVE + +GTEXT(z_arm64_sve_save) +SECTION_FUNC(TEXT, z_arm64_sve_save) + + /* Save control registers */ + mrs x2, fpsr + mrs x3, fpcr + str w2, [x0, #__z_arm64_fp_context_fpsr_OFFSET] + str w3, [x0, #__z_arm64_fp_context_fpcr_OFFSET] + + /* Get Z registers base address */ + add x2, x0, #__z_arm64_fp_context_sve_z_regs_OFFSET + + /* Save Z registers */ + str z0, [x2, #0, MUL VL] + str z1, [x2, #1, MUL VL] + str z2, [x2, #2, MUL VL] + str z3, [x2, #3, MUL VL] + str z4, [x2, #4, MUL VL] + str z5, [x2, #5, MUL VL] + str z6, [x2, #6, MUL VL] + str z7, [x2, #7, MUL VL] + str z8, [x2, #8, MUL VL] + str z9, [x2, #9, MUL VL] + str z10, [x2, #10, MUL VL] + str z11, [x2, #11, MUL VL] + str z12, [x2, #12, MUL VL] + str z13, [x2, #13, MUL VL] + str z14, [x2, #14, MUL VL] + str z15, [x2, #15, MUL VL] + str z16, [x2, #16, MUL VL] + str z17, [x2, #17, MUL VL] + str z18, [x2, #18, MUL VL] + str z19, [x2, #19, MUL VL] + str z20, [x2, #20, MUL VL] + str z21, [x2, #21, MUL VL] + str z22, [x2, #22, MUL VL] + str z23, [x2, #23, MUL VL] + str z24, [x2, #24, MUL VL] + str z25, [x2, #25, MUL VL] + str z26, [x2, #26, MUL VL] + str z27, [x2, #27, MUL VL] + str z28, [x2, #28, MUL VL] + str z29, [x2, #29, MUL VL] + str z30, [x2, #30, MUL VL] + str z31, [x2, #31, MUL VL] + + /* Get P registers base address */ + mov x3, #__z_arm64_fp_context_sve_p_regs_OFFSET + add x3, x0, x3 + + /* Save P registers */ + str p0, [x3, #0, MUL VL] + str p1, [x3, #1, MUL VL] + str p2, [x3, #2, MUL VL] + str p3, [x3, #3, MUL VL] + str p4, [x3, #4, MUL VL] + str p5, [x3, #5, MUL VL] + str p6, [x3, #6, MUL VL] + str p7, [x3, #7, MUL VL] + str p8, [x3, #8, MUL VL] + str p9, [x3, #9, MUL VL] + str p10, [x3, #10, MUL VL] + str p11, [x3, #11, MUL VL] + str p12, [x3, #12, MUL VL] + str p13, [x3, #13, MUL VL] + str p14, [x3, #14, MUL VL] + str p15, [x3, #15, MUL VL] + + /* Get FFR base address */ + mov x4, #__z_arm64_fp_context_sve_ffr_OFFSET + add x4, x0, x4 + + /* Save FFR */ + rdffr p0.b + str p0, [x4] + + ret + +GTEXT(z_arm64_sve_restore) +SECTION_FUNC(TEXT, z_arm64_sve_restore) + + /* Get Z registers base address */ + add x2, x0, #__z_arm64_fp_context_sve_z_regs_OFFSET + + /* Restore Z registers */ + ldr z0, [x2, #0, MUL VL] + ldr z1, [x2, #1, MUL VL] + ldr z2, [x2, #2, MUL VL] + ldr z3, [x2, #3, MUL VL] + ldr z4, [x2, #4, MUL VL] + ldr z5, [x2, #5, MUL VL] + ldr z6, [x2, #6, MUL VL] + ldr z7, [x2, #7, MUL VL] + ldr z8, [x2, #8, MUL VL] + ldr z9, [x2, #9, MUL VL] + ldr z10, [x2, #10, MUL VL] + ldr z11, [x2, #11, MUL VL] + ldr z12, [x2, #12, MUL VL] + ldr z13, [x2, #13, MUL VL] + ldr z14, [x2, #14, MUL VL] + ldr z15, [x2, #15, MUL VL] + ldr z16, [x2, #16, MUL VL] + ldr z17, [x2, #17, MUL VL] + ldr z18, [x2, #18, MUL VL] + ldr z19, [x2, #19, MUL VL] + ldr z20, [x2, #20, MUL VL] + ldr z21, [x2, #21, MUL VL] + ldr z22, [x2, #22, MUL VL] + ldr z23, [x2, #23, MUL VL] + ldr z24, [x2, #24, MUL VL] + ldr z25, [x2, #25, MUL VL] + ldr z26, [x2, #26, MUL VL] + ldr z27, [x2, #27, MUL VL] + ldr z28, [x2, #28, MUL VL] + ldr z29, [x2, #29, MUL VL] + ldr z30, [x2, #30, MUL VL] + ldr z31, [x2, #31, MUL VL] + + /* Get FFR base address */ + mov x4, #__z_arm64_fp_context_sve_ffr_OFFSET + add x4, x0, x4 + + /* Restore FFR */ + ldr p0, [x4] + wrffr p0.b + + /* Get P registers base address */ + mov x3, #__z_arm64_fp_context_sve_p_regs_OFFSET + add x3, x0, x3 + + /* Restore P registers intervals */ + ldr p0, [x3, #0, MUL VL] + ldr p1, [x3, #1, MUL VL] + ldr p2, [x3, #2, MUL VL] + ldr p3, [x3, #3, MUL VL] + ldr p4, [x3, #4, MUL VL] + ldr p5, [x3, #5, MUL VL] + ldr p6, [x3, #6, MUL VL] + ldr p7, [x3, #7, MUL VL] + ldr p8, [x3, #8, MUL VL] + ldr p9, [x3, #9, MUL VL] + ldr p10, [x3, #10, MUL VL] + ldr p11, [x3, #11, MUL VL] + ldr p12, [x3, #12, MUL VL] + ldr p13, [x3, #13, MUL VL] + ldr p14, [x3, #14, MUL VL] + ldr p15, [x3, #15, MUL VL] + + /* Restore control registers */ + ldr w2, [x0, #__z_arm64_fp_context_fpsr_OFFSET] + ldr w3, [x0, #__z_arm64_fp_context_fpcr_OFFSET] + msr fpsr, x2 + msr fpcr, x3 ret + +#endif /* CONFIG_ARM64_SVE */ diff --git a/arch/arm64/core/fpu.c b/arch/arm64/core/fpu.c index 09a60685b9e82..f6654a08105ea 100644 --- a/arch/arm64/core/fpu.c +++ b/arch/arm64/core/fpu.c @@ -15,6 +15,8 @@ /* to be found in fpu.S */ extern void z_arm64_fpu_save(struct z_arm64_fp_context *saved_fp_context); extern void z_arm64_fpu_restore(struct z_arm64_fp_context *saved_fp_context); +extern void z_arm64_sve_save(struct z_arm64_fp_context *saved_fp_context); +extern void z_arm64_sve_restore(struct z_arm64_fp_context *saved_fp_context); #define FPU_DEBUG 0 @@ -53,7 +55,7 @@ static void DBG(char *msg, struct k_thread *th) if (th == NULL) { th = _current; } - v = *(unsigned char *)&th->arch.saved_fp_context; + v = *(unsigned char *)&th->arch.saved_fp_context.neon; *p++ = ' '; *p++ = ((v >> 4) < 10) ? ((v >> 4) + '0') : ((v >> 4) - 10 + 'a'); *p++ = ((v & 15) < 10) ? ((v & 15) + '0') : ((v & 15) - 10 + 'a'); @@ -91,6 +93,46 @@ static inline void DBG_PC(char *msg, uintptr_t pc) { } #endif /* FPU_DEBUG */ +#ifdef CONFIG_ARM64_SVE + +/* Get current SVE vector length */ +static inline uint32_t z_arm64_sve_get_vl(void) +{ + uint32_t vl; + + __asm__("rdvl %0, #1" : "=r"(vl)); + return vl; +} + +#define USE_SVE(t) ((t) && (t)->arch.saved_fp_context.sve.simd_mode == SIMD_SVE) + +/* Convert NEON V registers to SVE Z registers in place */ +static void convert_Vx_to_Zx(struct z_arm64_fp_context *context) +{ + uint32_t vl = z_arm64_sve_get_vl(); + + if (CONFIG_ARM64_SVE_VL_MAX <= 16 || vl <= 16) { + return; + } + + /* + * Since it's a union, we need to extend each 128-bit NEON register + * to the full SVE vector length, working backwards to avoid overwriting + * data we still need to copy. + */ + for (int i = 31; i >= 0; i--) { + /* Copy the 128-bit NEON value to the low 128 bits of the Z register */ + *(__int128 *)&context->sve.z_regs[i * vl] = context->neon.v_regs[i]; + + /* Zero the upper part of the Z register (beyond 128 bits) */ + memset(&context->sve.z_regs[i * vl + 16], 0, vl - 16); + } +} + +#else +#define USE_SVE(t) false +#endif + /* * Flush FPU content and disable access. * This is called locally and also from flush_fpu_ipi_handler(). @@ -105,19 +147,30 @@ void arch_flush_local_fpu(void) uint64_t cpacr = read_cpacr_el1(); /* turn on FPU access */ - write_cpacr_el1(cpacr | CPACR_EL1_FPEN_NOTRAP); + cpacr |= CPACR_EL1_FPEN; + if (USE_SVE(owner)) { + cpacr |= CPACR_EL1_ZEN; + } + write_cpacr_el1(cpacr); barrier_isync_fence_full(); /* save current owner's content */ - z_arm64_fpu_save(&owner->arch.saved_fp_context); + if (USE_SVE(owner)) { + z_arm64_sve_save(&owner->arch.saved_fp_context); + } else { + z_arm64_fpu_save(&owner->arch.saved_fp_context); + } + /* make sure content made it to memory before releasing */ barrier_dsync_fence_full(); + /* release ownership */ atomic_ptr_clear(&_current_cpu->arch.fpu_owner); DBG("disable", owner); /* disable FPU access */ - write_cpacr_el1(cpacr & ~CPACR_EL1_FPEN_NOTRAP); + cpacr &= ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN); + write_cpacr_el1(cpacr); barrier_isync_fence_full(); } } @@ -173,7 +226,7 @@ void z_arm64_fpu_enter_exc(void) __ASSERT(read_daif() & DAIF_IRQ_BIT, "must be called with IRQs disabled"); /* always deny FPU access whenever an exception is entered */ - write_cpacr_el1(read_cpacr_el1() & ~CPACR_EL1_FPEN_NOTRAP); + write_cpacr_el1(read_cpacr_el1() & ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN)); barrier_isync_fence_full(); } @@ -253,29 +306,48 @@ static bool simulate_str_q_insn(struct arch_esf *esf) * don't get interrupted that is. To ensure that we mask interrupts to * the triggering exception context. */ -void z_arm64_fpu_trap(struct arch_esf *esf) +void z_arm64_fpu_trap(struct arch_esf *esf, uint32_t exception_class) { __ASSERT(read_daif() & DAIF_IRQ_BIT, "must be called with IRQs disabled"); /* check if a quick simulation can do it */ - if (simulate_str_q_insn(esf)) { + if (!(IS_ENABLED(CONFIG_ARM64_SVE) && exception_class == 0x19) && + simulate_str_q_insn(esf)) { return; } DBG_PC("trap entry", esf->elr); + struct k_thread *owner = atomic_ptr_get(&_current_cpu->arch.fpu_owner); + uint64_t cpacr = read_cpacr_el1(); + /* turn on FPU access */ - write_cpacr_el1(read_cpacr_el1() | CPACR_EL1_FPEN_NOTRAP); + cpacr |= CPACR_EL1_FPEN; + if (USE_SVE(owner)) { + cpacr |= CPACR_EL1_ZEN; + } + write_cpacr_el1(cpacr); barrier_isync_fence_full(); /* save current owner's content if any */ - struct k_thread *owner = atomic_ptr_get(&_current_cpu->arch.fpu_owner); - if (owner) { - z_arm64_fpu_save(&owner->arch.saved_fp_context); + if (USE_SVE(owner)) { + z_arm64_sve_save(&owner->arch.saved_fp_context); + DBG("sve_save", owner); + } else { + z_arm64_fpu_save(&owner->arch.saved_fp_context); + DBG("fpu_save", owner); + } barrier_dsync_fence_full(); atomic_ptr_clear(&_current_cpu->arch.fpu_owner); - DBG("save", owner); + } + + if (IS_ENABLED(CONFIG_ARM64_SVE) && exception_class == 0x19 && + !(cpacr & CPACR_EL1_ZEN)) { + /* SVE trap - also enable SVE access */ + cpacr |= CPACR_EL1_ZEN; + write_cpacr_el1(cpacr); + barrier_isync_fence_full(); } if (arch_exception_depth() > 1) { @@ -300,9 +372,34 @@ void z_arm64_fpu_trap(struct arch_esf *esf) /* become new owner */ atomic_ptr_set(&_current_cpu->arch.fpu_owner, _current); +#ifdef CONFIG_ARM64_SVE + if (exception_class == 0x19) { + /* SVE trap */ + if (_current->arch.saved_fp_context.sve.simd_mode == SIMD_NEON) { + /* upgrade from Neon to SVE before loading regs */ + convert_Vx_to_Zx(&_current->arch.saved_fp_context); + } + _current->arch.saved_fp_context.sve.simd_mode = SIMD_SVE; + } else if (_current->arch.saved_fp_context.sve.simd_mode != SIMD_SVE) { + /* no SVE trap and context is not SVE either */ + if ((cpacr & CPACR_EL1_ZEN) != 0) { + /* disable SVE access leaving only FP */ + cpacr &= ~CPACR_EL1_ZEN; + write_cpacr_el1(cpacr); + barrier_isync_fence_full(); + } + _current->arch.saved_fp_context.sve.simd_mode = SIMD_NEON; + } +#endif + /* restore our content */ - z_arm64_fpu_restore(&_current->arch.saved_fp_context); - DBG("restore", NULL); + if (USE_SVE(_current)) { + z_arm64_sve_restore(&_current->arch.saved_fp_context); + DBG("sve_restore", NULL); + } else { + z_arm64_fpu_restore(&_current->arch.saved_fp_context); + DBG("fpu_restore", NULL); + } } /* @@ -323,10 +420,14 @@ static void fpu_access_update(unsigned int exc_update_level) /* We're about to execute non-exception code */ if (atomic_ptr_get(&_current_cpu->arch.fpu_owner) == _current) { /* turn on FPU access */ - write_cpacr_el1(cpacr | CPACR_EL1_FPEN_NOTRAP); + cpacr |= CPACR_EL1_FPEN; + if (USE_SVE(_current)) { + cpacr |= CPACR_EL1_ZEN; + } + write_cpacr_el1(cpacr); } else { /* deny FPU access */ - write_cpacr_el1(cpacr & ~CPACR_EL1_FPEN_NOTRAP); + write_cpacr_el1(cpacr & ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN)); } } else { /* @@ -334,7 +435,7 @@ static void fpu_access_update(unsigned int exc_update_level) * access as we want to make sure IRQs are disabled before * granting it access (see z_arm64_fpu_trap() documentation). */ - write_cpacr_el1(cpacr & ~CPACR_EL1_FPEN_NOTRAP); + write_cpacr_el1(cpacr & ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN)); } barrier_isync_fence_full(); } diff --git a/arch/arm64/core/offsets/offsets.c b/arch/arm64/core/offsets/offsets.c index 772f0df3a8d05..a2eba37113631 100644 --- a/arch/arm64/core/offsets/offsets.c +++ b/arch/arm64/core/offsets/offsets.c @@ -29,6 +29,7 @@ #include #include #include +#include GEN_OFFSET_SYM(_thread_arch_t, exception_depth); @@ -77,6 +78,20 @@ GEN_NAMED_OFFSET_SYM(arm_smccc_res_t, a6, a6_a7); #endif /* CONFIG_HAS_ARM_SMCCC */ +#ifdef CONFIG_FPU_SHARING +GEN_OFFSET_SYM(z_arm64_fp_context, fpsr); +GEN_OFFSET_SYM(z_arm64_fp_context, fpcr); +GEN_OFFSET_SYM(z_arm64_fp_context, neon); +#ifdef CONFIG_ARM64_SVE +GEN_ABSOLUTE_SYM(__z_arm64_fp_context_sve_z_regs_OFFSET, + offsetof(struct z_arm64_fp_context, sve.z_regs)); +GEN_ABSOLUTE_SYM(__z_arm64_fp_context_sve_p_regs_OFFSET, + offsetof(struct z_arm64_fp_context, sve.p_regs)); +GEN_ABSOLUTE_SYM(__z_arm64_fp_context_sve_ffr_OFFSET, + offsetof(struct z_arm64_fp_context, sve.ffr)); +#endif +#endif + GEN_ABS_SYM_END #endif /* _ARM_OFFSETS_INC_ */ diff --git a/arch/arm64/core/reset.c b/arch/arm64/core/reset.c index 48ff0e29f79a7..3624715379b05 100644 --- a/arch/arm64/core/reset.c +++ b/arch/arm64/core/reset.c @@ -78,7 +78,22 @@ void z_arm64_el3_init(void) reg &= ~(CPTR_TTA_BIT | /* Do not trap sysreg accesses */ CPTR_TFP_BIT | /* Do not trap SVE, SIMD and FP */ CPTR_TCPAC_BIT); /* Do not trap CPTR_EL2 / CPACR_EL1 accesses */ + +#ifdef CONFIG_ARM64_SVE + /* Enable SVE for EL2 and below if SVE is implemented */ + if (is_sve_implemented()) { + reg |= CPTR_EZ_BIT; /* Enable SVE access for lower ELs */ + write_cptr_el3(reg); + + /* Initialize ZCR_EL3 for full SVE vector length */ + /* ZCR_EL3.LEN = 0x1ff means full hardware vector length */ + write_zcr_el3(0x1ff); + } else { + write_cptr_el3(reg); + } +#else write_cptr_el3(reg); +#endif reg = 0U; /* Reset */ #ifdef CONFIG_ARMV8_A_NS @@ -156,8 +171,24 @@ void z_arm64_el2_init(void) reg = 0U; /* RES0 */ reg |= CPTR_EL2_RES1; /* RES1 */ reg &= ~(CPTR_TFP_BIT | /* Do not trap SVE, SIMD and FP */ - CPTR_TCPAC_BIT); /* Do not trap CPACR_EL1 accesses */ + CPTR_TCPAC_BIT | /* Do not trap CPACR_EL1 accesses */ + CPTR_EL2_TZ_BIT); /* Do not trap SVE to EL2 */ +#ifdef CONFIG_ARM64_SVE + /* Enable SVE for EL1 and EL0 if SVE is implemented */ + if (is_sve_implemented()) { + reg &= ~CPTR_EL2_ZEN_MASK; + reg |= (CPTR_EL2_ZEN_EL1_EN | CPTR_EL2_ZEN_EL0_EN); + write_cptr_el2(reg); + + /* Initialize ZCR_EL2 for full SVE vector length */ + /* ZCR_EL2.LEN = 0x1ff means full hardware vector length */ + write_zcr_el2(0x1ff); + } else { + write_cptr_el2(reg); + } +#else write_cptr_el2(reg); +#endif zero_cntvoff_el2(); /* Set 64-bit virtual timer offset to 0 */ zero_cnthctl_el2(); @@ -191,9 +222,22 @@ void z_arm64_el1_init(void) barrier_isync_fence_full(); reg = 0U; /* RES0 */ - reg |= CPACR_EL1_FPEN_NOTRAP; /* Do not trap NEON/SIMD/FP initially */ + reg |= CPACR_EL1_FPEN; /* Do not trap NEON/SIMD/FP initially */ /* TODO: CONFIG_FLOAT_*_FORBIDDEN */ +#ifdef CONFIG_ARM64_SVE + /* Enable SVE access if SVE is implemented */ + if (is_sve_implemented()) { + reg |= CPACR_EL1_ZEN; /* Do not trap SVE initially */ + write_cpacr_el1(reg); + + /* Initialize ZCR_EL1 SVE vector length */ + write_zcr_el1(CONFIG_ARM64_SVE_VL_MAX/16 - 1); + } else { + write_cpacr_el1(reg); + } +#else write_cpacr_el1(reg); +#endif reg = read_sctlr_el1(); reg |= (SCTLR_EL1_RES1 | /* RES1 */ diff --git a/arch/arm64/core/switch.S b/arch/arm64/core/switch.S index 06a95d37b7a02..38c7bf7b24e52 100644 --- a/arch/arm64/core/switch.S +++ b/arch/arm64/core/switch.S @@ -153,8 +153,15 @@ SECTION_FUNC(TEXT, z_arm64_sync_exc) #ifdef CONFIG_FPU_SHARING cmp x1, #0x07 /*Access to SIMD or floating-point */ - bne 1f - mov x0, sp + beq fpu_sve_trap +#ifdef CONFIG_ARM64_SVE + cmp x1, #0x19 /*Trapped access to SVE functionality */ + beq fpu_sve_trap +#endif + b 1f +fpu_sve_trap: + mov x0, sp /* ESF pointer */ + /* x1 already contains exception class (EC) - pass as second argument */ bl z_arm64_fpu_trap b z_arm64_exit_exc_fpu_done 1: diff --git a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig b/boards/arm/fvp_base_revc_2xaem/Kconfig similarity index 100% rename from boards/arm/fvp_base_revc_2xaemv8a/Kconfig rename to boards/arm/fvp_base_revc_2xaem/Kconfig diff --git a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.defconfig b/boards/arm/fvp_base_revc_2xaem/Kconfig.defconfig similarity index 65% rename from boards/arm/fvp_base_revc_2xaemv8a/Kconfig.defconfig rename to boards/arm/fvp_base_revc_2xaem/Kconfig.defconfig index 3f1e48df8cc70..fcef90bc9a9e1 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.defconfig +++ b/boards/arm/fvp_base_revc_2xaem/Kconfig.defconfig @@ -1,9 +1,9 @@ # Copyright (c) 2021 Carlo Caione # SPDX-License-Identifier: Apache-2.0 -if BOARD_FVP_BASE_REVC_2XAEMV8A +if BOARD_FVP_BASE_REVC_2XAEM config BUILD_OUTPUT_BIN default y -endif # BOARD_FVP_BASE_REVC_2XAEMV8A +endif # BOARD_FVP_BASE_REVC_2XAEM diff --git a/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem new file mode 100644 index 0000000000000..49d3908e33959 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FVP_BASE_REVC_2XAEM + bool + select SOC_SERIES_FVP_AEM + select SOC_FVP_V8A if BOARD_QUALIFIERS = "v8a" + select SOC_FVP_V8A if BOARD_QUALIFIERS = "v8a/smp" + select SOC_FVP_V8A if BOARD_QUALIFIERS = "v8a/smp/ns" + select SOC_FVP_V9A if BOARD_QUALIFIERS = "v9a" + select SOC_FVP_V9A if BOARD_QUALIFIERS = "v9a/smp" + select SOC_FVP_V9A if BOARD_QUALIFIERS = "v9a/smp/ns" + select SOC_FVP_A320 if BOARD_QUALIFIERS = "a320" diff --git a/boards/arm/fvp_base_revc_2xaem/board.cmake b/boards/arm/fvp_base_revc_2xaem/board.cmake new file mode 100644 index 0000000000000..25612fb71099d --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/board.cmake @@ -0,0 +1,153 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +set(SUPPORTED_EMU_PLATFORMS armfvp) +set(ARMFVP_BIN_NAME FVP_Base_RevC-2xAEMvA) + +set(ARMFVP_FLAGS + -C bp.secure_memory=0 + -C cluster0.NUM_CORES=${CONFIG_MP_MAX_NUM_CPUS} + -C bp.refcounter.non_arch_start_at_default=1 + # UART0 config + -C bp.pl011_uart0.out_file=- + -C bp.pl011_uart0.unbuffered_output=1 + -C bp.terminal_0.start_telnet=0 + # UART1 config + -C bp.pl011_uart1.out_file=- + -C bp.pl011_uart1.unbuffered_output=1 + -C bp.terminal_1.start_telnet=0 + # UART2 config + -C bp.pl011_uart2.out_file=- + -C bp.pl011_uart2.unbuffered_output=1 + -C bp.terminal_2.start_telnet=0 + # UART3 config + -C bp.pl011_uart3.out_file=- + -C bp.pl011_uart3.unbuffered_output=1 + -C bp.terminal_3.start_telnet=0 + + -C bp.vis.disable_visualisation=1 + -C bp.vis.rate_limit-enable=0 + -C gic_distributor.ARE-fixed-to-one=1 + -C gic_distributor.ITS-device-bits=16 + -C cache_state_modelled=0 + ) + +# Add ARMv9-A specific configuration flags for all ARMv9-A variants +if(CONFIG_ARMV9_A) + set(ARMFVP_FLAGS ${ARMFVP_FLAGS} + # Enable ARMv9.0 extension (includes all ARMv8.x features) + -C cluster0.has_arm_v9-0=1 + # Enable SVE and SVE2 support (mandatory for ARMv9.0 compliance) + -C cluster0.has_sve=1 + -C cluster0.sve.has_sve2=1 + -C cluster0.sve.sve2_version=2 + -C cluster0.sve.enable_at_reset=1 + # Enable enhanced PAC and BTI support (ARMv9.0 features) + -C cluster0.enhanced_pac2_level=3 + -C cluster0.has_enhanced_pac=1 + ) + # Set minimum FVP version known to work with ARMv9.0 features (SVE2, enhanced PAC/BTI) + set(ARMFVP_MIN_VERSION 11.29.27) +endif() + +# Add Cortex-A320 specific configuration flags +if(CONFIG_BOARD_FVP_BASE_REVC_2XAEM_A320) + set(ARMFVP_FLAGS ${ARMFVP_FLAGS} + # Cortex-A320 specific CPU identification + -C cluster0.MIDR=0x410FD8F0 + -C cluster0.AMIIDR=0xD8F0043B + -C cluster0.AMPIDR=0x4000BBD8F + -C cluster0.ERRIIDR=0xD8F0043B + -C cluster0.ERRPIDR=0x4000BBD8F + -C cluster0.PMUPIDR=0x4000BBD80 + -C cluster0.CTIPIDR=0x4003BBD8F + -C cluster0.DBGPIDR=0x4003BBD8F + + # ARMv9.2-A support level + -C cluster0.has_arm_v9-2=1 + + # Advanced SIMD and crypto support + -C cluster0.advsimd_bf16_support_level=1 + -C cluster0.advsimd_i8mm_support_level=1 + -C cluster0.cpu0.crypto_sha3=1 + -C cluster0.cpu0.crypto_sha512=1 + -C cluster0.cpu0.crypto_sm3=1 + -C cluster0.cpu0.crypto_sm4=1 + -C cluster0.cpu0.enable_crc32=1 + + # Memory tagging support + -C cluster0.memory_tagging_support_level=3 + + # Enhanced security features + -C cluster0.has_qarma3_pac=1 + -C cluster0.has_const_pac=2 + + # SVE configuration for Cortex-A320 + -C cluster0.sve.veclen=2 + + # Performance monitoring + -C cluster0.pmu-num_counters=6 + -C cluster0.configure_pmu_events_with_json='{"pmu_events":["SVE_INST_RETIRED","BR_INDNR_TAKEN_RETIRED","BR_IND_RETIRED","EXC_IRQ","EXC_FIQ","EXC_RETURN","EXC_TAKEN","L1D_CACHE_RD","L2D_CACHE_RD","BUS_ACCESS_RD","BUS_ACCESS_WR","MEM_ACCESS_RD","MEM_ACCESS_WR","BR_PRED_RETIRED","BR_IMMED_MIS_PRED_RETIRED","BR_IND_MIS_PRED_RETIRED","BR_RETURN_PRED_RETIRED","BR_RETURN_MIS_PRED_RETIRED","BR_INDNR_PRED_RETIRED","BR_INDNR_MIS_PRED_RETIRED","BR_IMMED_PRED_RETIRED"]}' + + # Cache configuration + -C cluster0.dcache-ways=4 + -C cluster0.icache-ways=4 + -C cluster0.l2cache-ways=8 + -C cluster0.icache-log2linelen=6 + -C cluster0.l2cache-read_bus_width_in_bytes=16 + -C cluster0.l2cache-write_bus_width_in_bytes=32 + + # Debug and trace configuration + -C cluster0.has_ets=1 + -C cluster0.has_trbe=1 + -C cluster0.has_self_hosted_trace_extension=2 + + # Advanced architectural features + -C cluster0.has_ccidx=1 + -C cluster0.has_16k_granule=1 + -C cluster0.ecv_support_level=2 + -C cluster0.has_cvadp_support=1 + -C cluster0.has_lrcpc=1 + -C cluster0.has_dot_product=2 + -C cluster0.has_wfet_and_wfit=2 + -C cluster0.has_xs=2 + -C cluster0.has_v8_5_debug_over_power_down=2 + -C cluster0.has_v8_7_fp_enhancements=2 + -C cluster0.has_amu=1 + -C cluster0.has_mpmm=1 + -C cluster0.has_mpam=2 + -C cluster0.has_ras=2 + + # Memory system configuration + -C cluster0.stage12_tlb_size=1024 + -C cluster0.restriction_on_speculative_execution=2 + -C cluster0.restriction_on_speculative_execution_aarch32=2 + + # Error handling + -C cluster0.number_of_error_records=3 + -C cluster0.ERXMISC0_mask=0xC003FFC3 + ) + # Set minimum FVP version for Cortex-A320 features + set(ARMFVP_MIN_VERSION 11.29.27) +endif() + +if(CONFIG_BUILD_WITH_TFA) + set(TFA_PLAT "fvp") + + if(CONFIG_TFA_MAKE_BUILD_TYPE_DEBUG) + set(FVP_SECURE_FLASH_FILE ${TFA_BINARY_DIR}/fvp/debug/bl1.bin) + set(FVP_FLASH_FILE ${TFA_BINARY_DIR}/fvp/debug/fip.bin) + else() + set(FVP_SECURE_FLASH_FILE ${TFA_BINARY_DIR}/fvp/release/bl1.bin) + set(FVP_FLASH_FILE ${TFA_BINARY_DIR}/fvp/release/fip.bin) + endif() + +elseif(CONFIG_PM_CPU_OPS_FVP) + # Configure RVBAR_EL3 for bare metal SMP when using FVP PM CPU ops driver + set(ARMFVP_FLAGS ${ARMFVP_FLAGS} + # Set RVBAR_EL3 for secondary CPUs to Zephyr image base address + -C cluster0.cpu1.RVBAR=${CONFIG_KERNEL_VM_BASE} + -C cluster0.cpu2.RVBAR=${CONFIG_KERNEL_VM_BASE} + -C cluster0.cpu3.RVBAR=${CONFIG_KERNEL_VM_BASE} + ) +endif() diff --git a/boards/arm/fvp_base_revc_2xaem/board.yml b/boards/arm/fvp_base_revc_2xaem/board.yml new file mode 100644 index 0000000000000..d0c8c71d5bf07 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/board.yml @@ -0,0 +1,16 @@ +board: + name: fvp_base_revc_2xaem + full_name: BASE RevC 2xAEM (Architectural Envelope Model) Fixed Virtual Platform + vendor: arm + socs: + - name: v8a + variants: + - name: smp + variants: + - name: ns + - name: v9a + variants: + - name: smp + variants: + - name: ns + - name: a320 diff --git a/boards/arm/fvp_base_revc_2xaemv8a/doc/index.rst b/boards/arm/fvp_base_revc_2xaem/doc/index.rst similarity index 56% rename from boards/arm/fvp_base_revc_2xaemv8a/doc/index.rst rename to boards/arm/fvp_base_revc_2xaem/doc/index.rst index 0954a2d90a130..c6e74bff8f380 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/doc/index.rst +++ b/boards/arm/fvp_base_revc_2xaem/doc/index.rst @@ -1,16 +1,16 @@ -.. _fvp_base_revc_2xaemv8a: +.. _fvp_base_revc_2xaem: -ARM BASE RevC AEMv8A Fixed Virtual Platforms -############################################ +ARM BASE RevC 2xAEM Fixed Virtual Platforms +########################################### Overview ******** This board configuration will use ARM Fixed Virtual Platforms(FVP) to emulate -a generic Armv8-A 64-bit hardware platform. +a generic AEM (Architectural Envelope Model) hardware platform supporting both +ARMv8-A and ARMv9-A architectures. -This configuration provides support for a generic Armv8-A 64-bit CPU and -these devices: +This configuration provides support for generic AEM CPUs and these devices: * GICv3 interrupt controller * ARM architected (Generic) timer @@ -38,6 +38,31 @@ The following hardware features are supported: The kernel currently does not support other hardware features on this platform. +Board Variants +============== + +The following targets are available: + +* ``fvp_base_revc_2xaem/v8a`` - ARMv8-A (64-bit) with Cortex-A53 cores +* ``fvp_base_revc_2xaem/v8a/smp`` - ARMv8-A SMP (4 cores) +* ``fvp_base_revc_2xaem/v8a/smp/ns`` - ARMv8-A SMP Non-Secure +* ``fvp_base_revc_2xaem/v9a`` - ARMv9-A (64-bit) with Cortex-A510 cores +* ``fvp_base_revc_2xaem/v9a/smp`` - ARMv9-A SMP (4 cores) +* ``fvp_base_revc_2xaem/v9a/smp/ns`` - ARMv9-A SMP Non-Secure +* ``fvp_base_revc_2xaem/a320`` - ARMv9.2-A with Cortex-A320 configuration + +**Cortex-A320 Variant:** + +The ``fvp_base_revc_2xaem/a320`` variant provides Cortex-A320 specific FVP +configuration with: + +* ARMv9.2-A architecture compliance +* Enhanced cryptographic extensions (SHA3, SHA512, SM3, SM4) +* Advanced memory tagging (MTE Level 3) +* QARMA3 Pointer Authentication +* Optimized cache configuration for Cortex-A320 +* Performance monitoring unit with SVE-specific events + Devices ======== @@ -77,12 +102,44 @@ ARM FVP emulated environment, for example, with the :zephyr:code-sample:`synchro .. zephyr-app-commands:: :zephyr-app: samples/synchronization :host-os: unix - :board: fvp_base_revc_2xaemv8a + :board: fvp_base_revc_2xaem/v8a :goals: build -This will build an image with the synchronization sample app. +This will build an image with the synchronization sample app for ARMv8-A. Then you can run it with ``west build -t run``. +For ARMv9-A variants: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: fvp_base_revc_2xaem/v9a + :goals: build + +For Cortex-A320 specific configuration: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :host-os: unix + :board: fvp_base_revc_2xaem/a320 + :goals: build + +For SMP variants: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: fvp_base_revc_2xaem/v8a/smp + :goals: build + +For SMP Non-Secure variants with TF-A: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: fvp_base_revc_2xaem/v8a/smp/ns + :goals: build + Running Zephyr at EL1NS *********************** @@ -106,6 +163,17 @@ then export the :envvar:`ARMFVP_BL1_FILE` and :envvar:`ARMFVP_FIP_FILE` environm export ARMFVP_BL1_FILE= export ARMFVP_FIP_FILE= +Migration from Legacy Board Names +********************************* + +The legacy board name ``fvp_base_revc_2xaemv8a`` has been replaced with the +unified ``fvp_base_revc_2xaem/v8a`` naming. Update your build commands: + +* Old: ``west build -b fvp_base_revc_2xaemv8a`` +* New: ``west build -b fvp_base_revc_2xaem/v8a`` + +The legacy board name remains supported for backward compatibility. + Debugging ========= diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi similarity index 89% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi index 3a6ff898bf2db..49eeecd175520 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi @@ -3,19 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -/dts-v1/; - #include -#include #include / { - model = "FVP Base RevC 2xAEMv8A"; - chosen { /* * The SRAM node is actually located in the - * DRAM region of the FVP Base RevC 2xAEMv8A. + * DRAM region of the FVP Base RevC 2xAEM. */ zephyr,sram = &dram0; zephyr,flash = &flash0; @@ -32,27 +27,23 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; - compatible = "arm,cortex-a53"; reg = <0>; }; - cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; - compatible = "arm,cortex-a53"; reg = <0x100>; }; - cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; - compatible = "arm,cortex-a53"; reg = <0x200>; }; - cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; - compatible = "arm,cortex-a53"; reg = <0x300>; }; }; @@ -96,6 +87,17 @@ }; }; + v2m_sysreg: sysreg@1c010000 { + compatible = "arm,vexpress-sysreg"; + reg = <0x1c010000 0x1000>; + }; + + pwrc: power-controller@1c100000 { + compatible = "arm,fvp-pwrc"; + reg = <0x1c100000 0x1000>; + arm,vexpress-sysreg = <&v2m_sysreg>; + }; + uart0: uart@1c090000 { compatible = "arm,pl011"; reg = <0x1c090000 0x1000>; diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.dts new file mode 100644 index 0000000000000..715085507689c --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "fvp_base_revc_2xaem.dtsi" + +/ { + model = "FVP Base RevC 2xAEMv9A (Cortex-A320)"; +}; + +&cpu0 { + compatible = "arm,cortex-a320"; +}; + +&cpu1 { + compatible = "arm,cortex-a320"; +}; + +&cpu2 { + compatible = "arm,cortex-a320"; +}; + +&cpu3 { + compatible = "arm,cortex-a320"; +}; diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml similarity index 59% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml index 02a956dc62889..76b773904193e 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml @@ -1,8 +1,8 @@ -# Copyright (c) 2021 Carlo Caione +# Copyright (c) 2025 BayLibre SAS # SPDX-License-Identifier: Apache-2.0 -identifier: fvp_base_revc_2xaemv8a -name: FVP Emulation FVP_Base_RevC-2xAEMvA +identifier: fvp_base_revc_2xaem/a320 +name: FVP Emulation FVP_Base_RevC-2xAEMv9A (Cortex-A320) arch: arm64 type: sim simulation: diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320_defconfig new file mode 100644 index 0000000000000..45560359c52c8 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320_defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_XIP=n + +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.dts new file mode 100644 index 0000000000000..265bd8e0142ed --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 Carlo Caione + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "fvp_base_revc_2xaem.dtsi" + +/ { + model = "FVP Base RevC 2xAEM ARMv8-A"; +}; + +&cpu0 { + compatible = "arm,cortex-a53"; +}; + +&cpu1 { + compatible = "arm,cortex-a53"; +}; + +&cpu2 { + compatible = "arm,cortex-a53"; +}; + +&cpu3 { + compatible = "arm,cortex-a53"; +}; diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.yaml new file mode 100644 index 0000000000000..8b2b6c66d822c --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.yaml @@ -0,0 +1,21 @@ +identifier: fvp_base_revc_2xaem/v8a +name: FVP Base RevC 2xAEM ARMv8-A +arch: arm64 +type: sim +simulation: + - name: armfvp + exec: FVP_Base_RevC-2xAEMvA +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +vendor: arm +supported: + - gpio + - uart + - smp +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_defconfig similarity index 100% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_defconfig rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_defconfig diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.dts new file mode 100644 index 0000000000000..6e4d671cef68f --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.dts @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2021 Carlo Caione + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fvp_base_revc_2xaem_v8a.dts" diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml new file mode 100644 index 0000000000000..c464a1eeac4bc --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaem/v8a/smp +name: FVP Base RevC 2xAEM ARMv8-A (SMP) +arch: arm64 +type: sim +simulation: + - name: armfvp + exec: FVP_Base_RevC-2xAEMvA +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +vendor: arm +supported: + - gpio + - uart + - smp +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig new file mode 100644 index 0000000000000..dbd17ee82debb --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig @@ -0,0 +1,31 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable SMP +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 +CONFIG_CACHE_MANAGEMENT=y +CONFIG_TIMEOUT_64BIT=y +CONFIG_ARM64_SET_VMPIDR_EL2=y +CONFIG_MAX_THREAD_BYTES=3 + +# CPU control without PSCI +CONFIG_PM_CPU_OPS_PSCI=n +CONFIG_PM_CPU_OPS=y +CONFIG_PM_CPU_OPS_FVP=y diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.dts similarity index 75% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.dts rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.dts index e208047aadcb8..42021e6861410 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.dts +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.dts @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "fvp_base_revc_2xaemv8a.dts" +#include "fvp_base_revc_2xaem_v8a.dts" diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.yaml similarity index 70% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.yaml rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.yaml index fae3074e6d817..391bef80ac852 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.yaml +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.yaml @@ -1,8 +1,8 @@ # Copyright (c) 2022 Arm Limited (or its affiliates). All rights reserved. # SPDX-License-Identifier: Apache-2.0 -identifier: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns -name: FVP Emulation FVP_Base_RevC-2xAEMvA (SMP) +identifier: fvp_base_revc_2xaem/v8a/smp/ns +name: FVP Base RevC 2xAEM ARMv8-A (SMP Non-Secure) arch: arm64 type: sim simulation: diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns_defconfig similarity index 100% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns_defconfig rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns_defconfig diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.dts new file mode 100644 index 0000000000000..2210995f42a11 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "fvp_base_revc_2xaem.dtsi" + +/ { + model = "FVP Base RevC 2xAEM ARMv9A"; +}; + +&cpu0 { + compatible = "arm,cortex-a510"; +}; + +&cpu1 { + compatible = "arm,cortex-a510"; +}; + +&cpu2 { + compatible = "arm,cortex-a510"; +}; + +&cpu3 { + compatible = "arm,cortex-a510"; +}; diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.yaml new file mode 100644 index 0000000000000..72227152205a4 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaem/v9a +name: FVP Emulation FVP_Base_RevC-2xAEMv9A +arch: arm64 +type: sim +simulation: + - name: armfvp + exec: FVP_Base_RevC-2xAEMvA +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +vendor: arm diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_defconfig new file mode 100644 index 0000000000000..45560359c52c8 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_XIP=n + +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.dts new file mode 100644 index 0000000000000..727c1c75da679 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.dts @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fvp_base_revc_2xaem_v9a.dts" diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.yaml new file mode 100644 index 0000000000000..491677d860f12 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaem/v9a/smp +name: FVP Emulation FVP_Base_RevC-2xAEMv9A (SMP) +arch: arm64 +type: sim +simulation: + - name: armfvp + exec: FVP_Base_RevC-2xAEMvA +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +vendor: arm diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_defconfig new file mode 100644 index 0000000000000..dbd17ee82debb --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_defconfig @@ -0,0 +1,31 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable SMP +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 +CONFIG_CACHE_MANAGEMENT=y +CONFIG_TIMEOUT_64BIT=y +CONFIG_ARM64_SET_VMPIDR_EL2=y +CONFIG_MAX_THREAD_BYTES=3 + +# CPU control without PSCI +CONFIG_PM_CPU_OPS_PSCI=n +CONFIG_PM_CPU_OPS=y +CONFIG_PM_CPU_OPS_FVP=y diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.dts b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.dts new file mode 100644 index 0000000000000..727c1c75da679 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.dts @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fvp_base_revc_2xaem_v9a.dts" diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.yaml new file mode 100644 index 0000000000000..482576cad5048 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaem/v9a/smp/ns +name: FVP Emulation FVP_Base_RevC-2xAEMv9A (SMP) (Non-Secure) +arch: arm64 +type: sim +simulation: + - name: armfvp + exec: FVP_Base_RevC-2xAEMvA +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +vendor: arm diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns_defconfig new file mode 100644 index 0000000000000..37aadc6d399b3 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns_defconfig @@ -0,0 +1,33 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable TFA +CONFIG_ARMV8_A_NS=y +CONFIG_BUILD_WITH_TFA=y + +# Enable SMP +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 +CONFIG_CACHE_MANAGEMENT=y +CONFIG_TIMEOUT_64BIT=y +CONFIG_ARM64_SET_VMPIDR_EL2=y +CONFIG_MAX_THREAD_BYTES=3 + +# PSCI is supported +CONFIG_PM_CPU_OPS=y diff --git a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a b/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a deleted file mode 100644 index 874f1dba01531..0000000000000 --- a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2021 Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_FVP_BASE_REVC_2XAEMV8A - select SOC_SERIES_FVP_AEMV8A - select SOC_FVP_BASE_REVC_2XAEMV8A diff --git a/boards/arm/fvp_base_revc_2xaemv8a/board.cmake b/boards/arm/fvp_base_revc_2xaemv8a/board.cmake deleted file mode 100644 index 0df438fad9e6b..0000000000000 --- a/boards/arm/fvp_base_revc_2xaemv8a/board.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2021 Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -set(SUPPORTED_EMU_PLATFORMS armfvp) -set(ARMFVP_BIN_NAME FVP_Base_RevC-2xAEMvA) - -set(ARMFVP_FLAGS - -C bp.secure_memory=0 - -C cluster0.NUM_CORES=${CONFIG_MP_MAX_NUM_CPUS} - -C bp.refcounter.non_arch_start_at_default=1 - # UART0 config - -C bp.pl011_uart0.out_file=- - -C bp.pl011_uart0.unbuffered_output=1 - -C bp.terminal_0.start_telnet=0 - # UART1 config - -C bp.pl011_uart1.out_file=- - -C bp.pl011_uart1.unbuffered_output=1 - -C bp.terminal_1.start_telnet=0 - # UART2 config - -C bp.pl011_uart2.out_file=- - -C bp.pl011_uart2.unbuffered_output=1 - -C bp.terminal_2.start_telnet=0 - # UART3 config - -C bp.pl011_uart3.out_file=- - -C bp.pl011_uart3.unbuffered_output=1 - -C bp.terminal_3.start_telnet=0 - - -C bp.vis.disable_visualisation=1 - -C bp.vis.rate_limit-enable=0 - -C gic_distributor.ARE-fixed-to-one=1 - -C gic_distributor.ITS-device-bits=16 - -C cache_state_modelled=0 - ) - -if(CONFIG_BUILD_WITH_TFA) - set(TFA_PLAT "fvp") - - if(CONFIG_TFA_MAKE_BUILD_TYPE_DEBUG) - set(FVP_SECURE_FLASH_FILE ${TFA_BINARY_DIR}/fvp/debug/bl1.bin) - set(FVP_FLASH_FILE ${TFA_BINARY_DIR}/fvp/debug/fip.bin) - else() - set(FVP_SECURE_FLASH_FILE ${TFA_BINARY_DIR}/fvp/release/bl1.bin) - set(FVP_FLASH_FILE ${TFA_BINARY_DIR}/fvp/release/fip.bin) - endif() - -endif() diff --git a/boards/arm/fvp_base_revc_2xaemv8a/board.yml b/boards/arm/fvp_base_revc_2xaemv8a/board.yml deleted file mode 100644 index 3af023b670ec9..0000000000000 --- a/boards/arm/fvp_base_revc_2xaemv8a/board.yml +++ /dev/null @@ -1,10 +0,0 @@ -board: - name: fvp_base_revc_2xaemv8a - full_name: BASE RevC AEMv8A Fixed Virtual Platforms - vendor: arm - socs: - - name: fvp_base_revc_2xaemv8a - variants: - - name: smp - variants: - - name: ns diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index 1cc3856cee8ad..2066c1f5da545 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -67,3 +67,12 @@ set(esp32_devkitc_wrover/esp32/appcpu_DEPRECATED set(scobc_module1_DEPRECATED scobc_a1 ) +set(fvp_base_revc_2xaemv8a_DEPRECATED + fvp_base_revc_2xaem/v8a +) +set(fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp_DEPRECATED + fvp_base_revc_2xaem/v8a/smp +) +set(fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns_DEPRECATED + fvp_base_revc_2xaem/v8a/smp/ns +) diff --git a/cmake/compiler/gcc/target_arm64.cmake b/cmake/compiler/gcc/target_arm64.cmake index 2bc16e61bc1f0..7c3304e58bb2e 100644 --- a/cmake/compiler/gcc/target_arm64.cmake +++ b/cmake/compiler/gcc/target_arm64.cmake @@ -1,4 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 + +# Add SVE support if enabled +if(CONFIG_ARM64_SVE) + if(DEFINED GCC_M_ARCH) + set(GCC_M_ARCH "${GCC_M_ARCH}+sve") + else() + set(GCC_M_ARCH "armv9-a+sve") + endif() +endif() + if(DEFINED GCC_M_CPU) list(APPEND TOOLCHAIN_C_FLAGS -mcpu=${GCC_M_CPU}) list(APPEND TOOLCHAIN_LD_FLAGS -mcpu=${GCC_M_CPU}) diff --git a/cmake/compiler/iar/iccarm-cpu.cmake b/cmake/compiler/iar/iccarm-cpu.cmake index 76af74b316438..454d5ded0455b 100644 --- a/cmake/compiler/iar/iccarm-cpu.cmake +++ b/cmake/compiler/iar/iccarm-cpu.cmake @@ -95,6 +95,8 @@ elseif("${ARCH}" STREQUAL "arm64") set(ICCARM_CPU cortex-a76) elseif(CONFIG_CPU_CORTEX_A72) set(ICCARM_CPU Cortex-A72) + elseif(CONFIG_CPU_CORTEX_A510) + set(ICCARM_CPU Cortex-A510) elseif(CONFIG_CPU_CORTEX_R82) set(ICCARM_CPU Cortex-R82) endif() diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index 734f118ad3e36..ce0c92867de50 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -4,7 +4,7 @@ # KConfig'uration and sets this to GCC_M_CPU if("${ARCH}" STREQUAL "arm") - if (CONFIG_CPU_CORTEX_M0) + if(CONFIG_CPU_CORTEX_M0) set(GCC_M_CPU cortex-m0) elseif(CONFIG_CPU_CORTEX_M0PLUS) set(GCC_M_CPU cortex-m0plus) @@ -19,13 +19,13 @@ if("${ARCH}" STREQUAL "arm") elseif(CONFIG_CPU_CORTEX_M23) set(GCC_M_CPU cortex-m23) elseif(CONFIG_CPU_CORTEX_M33) - if (CONFIG_ARMV8_M_DSP) + if(CONFIG_ARMV8_M_DSP) set(GCC_M_CPU cortex-m33) else() set(GCC_M_CPU cortex-m33+nodsp) endif() elseif(CONFIG_CPU_CORTEX_M52) - if (CONFIG_ARMV8_1_M_MVEF) + if(CONFIG_ARMV8_1_M_MVEF) set(GCC_M_CPU cortex-m52) elseif(CONFIG_ARMV8_1_M_MVEI) set(GCC_M_CPU cortex-m52+nomve.fp) @@ -35,7 +35,7 @@ if("${ARCH}" STREQUAL "arm") set(GCC_M_CPU cortex-m52+nodsp) endif() elseif(CONFIG_CPU_CORTEX_M55) - if (CONFIG_ARMV8_1_M_MVEF) + if(CONFIG_ARMV8_1_M_MVEF) set(GCC_M_CPU cortex-m55) elseif(CONFIG_ARMV8_1_M_MVEI) set(GCC_M_CPU cortex-m55+nomve.fp) @@ -45,7 +45,7 @@ if("${ARCH}" STREQUAL "arm") set(GCC_M_CPU cortex-m55+nodsp) endif() elseif(CONFIG_CPU_CORTEX_M85) - if (CONFIG_ARMV8_1_M_MVEF) + if(CONFIG_ARMV8_1_M_MVEF) set(GCC_M_CPU cortex-m85) elseif(CONFIG_ARMV8_1_M_MVEI) set(GCC_M_CPU cortex-m85+nomve.fp) @@ -115,6 +115,14 @@ elseif("${ARCH}" STREQUAL "arm64") set(GCC_M_CPU cortex-a72) elseif(CONFIG_CPU_CORTEX_A78) set(GCC_M_CPU cortex-a78) + elseif(CONFIG_CPU_CORTEX_A510) + set(GCC_M_CPU cortex-a510) + elseif(CONFIG_CPU_CORTEX_A320) + # Cortex-A320 was announced in February 2025 and is not yet supported in any GCC version + # Use cortex-a710 as fallback since both are high-performance ARMv9-A cores with similar features + # TODO: Update to use cortex-a320 when GCC support is added (likely in GCC 15 or 16) + set(GCC_M_CPU cortex-a710) + message(STATUS "Using cortex-a710 as fallback for cortex-a320 (not yet supported in GCC)") elseif(CONFIG_CPU_CORTEX_R82) set(GCC_M_CPU cortex-r82) endif() diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 7ce2df1414994..4b3f631a8b2c2 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -102,6 +102,23 @@ New APIs and options * :c:func:`z_arm_save_mpu_context` / :c:func:`z_arm_restore_mpu_context` * Existing :c:func:`z_arm_save_fp_context` and :c:func:`z_arm_save_fp_context` have also been updated + * ARM64 + + * The following boardtargets have been renamed: + + * fvp_base_revc_2xaemv8a → fvp_base_revc_2xaem/v8a + * fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp + → fvp_base_revc_2xaem/v8a/smp + * fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + → fvp_base_revc_2xaem/v8a/smp/ns + + * New board targets: + + * fvp_base_revc_2xaem/v9a (basic ARMv9-A single core) + * fvp_base_revc_2xaem/v9a/smp (ARMv9-A SMP 4 cores) + * fvp_base_revc_2xaem/v9a/smp/ns (ARMv9-A SMP non-secure with TFA) + * fvp_base_revc_2xaem/a320 (Cortex-A320 specific) + * Bluetooth * Audio diff --git a/drivers/pm_cpu_ops/CMakeLists.txt b/drivers/pm_cpu_ops/CMakeLists.txt index 15643f4702a3f..84dbce3641781 100644 --- a/drivers/pm_cpu_ops/CMakeLists.txt +++ b/drivers/pm_cpu_ops/CMakeLists.txt @@ -6,4 +6,6 @@ zephyr_library_sources_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops_weak_impl.c) zephyr_library_sources_ifdef(CONFIG_PM_CPU_OPS_PSCI pm_cpu_ops_psci.c) +zephyr_library_sources_ifdef(CONFIG_PM_CPU_OPS_FVP pm_cpu_ops_fvp.c) + zephyr_library_sources_ifdef(CONFIG_PSCI_SHELL psci_shell.c) diff --git a/drivers/pm_cpu_ops/Kconfig b/drivers/pm_cpu_ops/Kconfig index 43d549f59bde5..b315e99524ac2 100644 --- a/drivers/pm_cpu_ops/Kconfig +++ b/drivers/pm_cpu_ops/Kconfig @@ -30,6 +30,17 @@ config PM_CPU_OPS_PSCI 0022A ("Power State Coordination Interface System Software on ARM processors"). +config PM_CPU_OPS_FVP + bool "Support for ARM FVP CPU power management" + depends on DT_HAS_ARM_FVP_PWRC_ENABLED && !PM_CPU_OPS_PSCI + default y if SMP + select PM_CPU_OPS_HAS_DRIVER + help + Say Y here if you want Zephyr to support CPU power management + operations on ARM Fixed Virtual Platform (FVP) without PSCI. + This driver directly controls the FVP power controller and + V2M system registers for CPU power-on and system reset operations. + config PSCI_SHELL bool "Support for PSCI interface shell commands" depends on SHELL && PM_CPU_OPS_PSCI diff --git a/drivers/pm_cpu_ops/pm_cpu_ops_fvp.c b/drivers/pm_cpu_ops/pm_cpu_ops_fvp.c new file mode 100644 index 0000000000000..65b6d6d7dc703 --- /dev/null +++ b/drivers/pm_cpu_ops/pm_cpu_ops_fvp.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT arm_fvp_pwrc + +#define LOG_LEVEL CONFIG_PM_CPU_OPS_LOG_LEVEL +#include +LOG_MODULE_REGISTER(fvp_pm_cpu_ops); + +#include +#include +#include +#include +#include + +/* FVP Platform Constants */ +#define FVP_PWRC_BASE DT_INST_REG_ADDR(0) +#define FVP_V2M_SYSREGS_BASE DT_REG_ADDR(DT_INST_PHANDLE(0, arm_vexpress_sysreg)) + +/* FVP Power Controller Register Offsets */ +#define PWRC_PPONR_OFF 0x4 /* Power-on Request */ +#define PWRC_PSYSR_OFF 0x10 /* System Status Register */ + +/* PSYSR Register Bits */ +#define PSYSR_AFF_L0 BIT(29) /* Affinity Level 0 */ + +/* V2M System Registers */ +#define V2M_SYS_CFGCTRL_OFF 0xa4 /* System Configuration Control Register */ + +/* V2M Configuration Control Register bits */ +#define V2M_CFGCTRL_START BIT(31) /* Start operation */ +#define V2M_CFGCTRL_RW BIT(30) /* Read/Write operation */ +#define V2M_CFGCTRL_FUNC_MASK GENMASK(27, 20) /* Function field */ +#define V2M_CFGCTRL_FUNC(fn) FIELD_PREP(V2M_CFGCTRL_FUNC_MASK, (fn)) + +/* V2M System Configuration Functions */ +#define V2M_FUNC_REBOOT 0x09 /* System reboot */ + +/* + * Memory mapping strategy: + * + * To conserve memory (especially page tables) in Zephyr, we use temporary + * mappings for hardware register access. Each operation maps the required + * registers, performs the operation, then unmaps them immediately. + * + * CPU power operations are infrequent and not performance-critical. Memory + * conservation is therefore more important than runtime optimizations. + */ +#define FVP_REGISTER_MAP_SIZE 0x1000 /* 4KB pages for register mapping */ + +static inline void fvp_pwrc_write_pponr(uintptr_t pwrc_vaddr, unsigned long mpidr) +{ + sys_write32((uint32_t)mpidr, pwrc_vaddr + PWRC_PPONR_OFF); + LOG_DBG("FVP: PPONR write: MPIDR=0x%lx", mpidr); +} + +static inline uint32_t fvp_pwrc_read_psysr(uintptr_t pwrc_vaddr, unsigned long mpidr) +{ + /* Write MPIDR to PSYSR to select which CPU to query */ + sys_write32((uint32_t)mpidr, pwrc_vaddr + PWRC_PSYSR_OFF); + + /* Read the status for the selected CPU */ + return sys_read32(pwrc_vaddr + PWRC_PSYSR_OFF); +} + + +static int fvp_cpu_power_on(unsigned long target_mpidr, uintptr_t entry_point) +{ + uint8_t *pwrc_vaddr_ptr; + uintptr_t pwrc_vaddr; + uint32_t psysr; + int timeout = 10000; /* 1 second timeout */ + + LOG_DBG("FVP: Powering on CPU MPIDR=0x%lx, entry=0x%lx", + target_mpidr, entry_point); + + /* Map power controller registers once for the entire operation */ + k_mem_map_phys_bare(&pwrc_vaddr_ptr, FVP_PWRC_BASE, FVP_REGISTER_MAP_SIZE, + K_MEM_PERM_RW | K_MEM_CACHE_NONE); + pwrc_vaddr = (uintptr_t)pwrc_vaddr_ptr; + + /* + * Wait for any pending power-off to complete. + * The target CPU must be in OFF state before we can power it on. + */ + do { + psysr = fvp_pwrc_read_psysr(pwrc_vaddr, target_mpidr); + if (timeout-- <= 0) { + LOG_ERR("FVP: Timeout waiting for CPU 0x%lx power-off " + "to complete, PSYSR=0x%x", target_mpidr, psysr); + k_mem_unmap_phys_bare(pwrc_vaddr_ptr, FVP_REGISTER_MAP_SIZE); + return -ETIMEDOUT; + } + k_busy_wait(100); + } while ((psysr & PSYSR_AFF_L0) != 0); + + LOG_DBG("FVP: CPU 0x%lx is powered off (PSYSR=0x%x)", target_mpidr, psysr); + + /* Power on the target CPU via FVP power controller */ + fvp_pwrc_write_pponr(pwrc_vaddr, target_mpidr); + + /* Unmap power controller registers */ + k_mem_unmap_phys_bare(pwrc_vaddr_ptr, FVP_REGISTER_MAP_SIZE); + + /* Ensure power-on request completes */ + barrier_dsync_fence_full(); + + /* Send event to wake up the target CPU from WFE loop */ + __asm__ volatile("sev" ::: "memory"); + + LOG_DBG("FVP: Power-on request completed for CPU 0x%lx", target_mpidr); + return 0; +} + +int pm_cpu_on(unsigned long mpidr, uintptr_t entry_point) +{ + return fvp_cpu_power_on(mpidr, entry_point); +} + +int pm_cpu_off(void) +{ + /* + * This is incompatible with our register mapping strategy. + * A CPU that shuts itself down might not complete the register + * unmapping before losing power. + */ + return -ENOTSUP; +} + +static inline void fvp_v2m_sys_cfgwrite(uint32_t function) +{ + uint8_t *v2m_vaddr_ptr; + uintptr_t v2m_vaddr; + uint32_t val = V2M_CFGCTRL_START | V2M_CFGCTRL_RW | V2M_CFGCTRL_FUNC(function); + + /* Temporarily map V2M system registers */ + k_mem_map_phys_bare(&v2m_vaddr_ptr, FVP_V2M_SYSREGS_BASE, FVP_REGISTER_MAP_SIZE, + K_MEM_PERM_RW | K_MEM_CACHE_NONE); + v2m_vaddr = (uintptr_t)v2m_vaddr_ptr; + + sys_write32(val, v2m_vaddr + V2M_SYS_CFGCTRL_OFF); + + LOG_DBG("FVP: V2M SYS_CFGCTRL write: 0x%x (func=0x%x)", val, function); + + /* Unmap V2M registers */ + k_mem_unmap_phys_bare(v2m_vaddr_ptr, FVP_REGISTER_MAP_SIZE); +} + +int pm_system_reset(unsigned char reset_type) +{ + LOG_DBG("FVP: System reset requested (type=%u)", reset_type); + + /* + * FVP supports system reset via the V2M System Configuration Controller. + * Both warm and cold reset use the same mechanism - the V2M reboot function. + */ + fvp_v2m_sys_cfgwrite(V2M_FUNC_REBOOT); + + /* + * The reset should happen immediately, but in case it doesn't work, + * we'll wait a bit and return an error. + */ + k_busy_wait(1000000); /* Wait 1 second */ + + LOG_ERR("FVP: System reset failed - system did not reset"); + return -ETIMEDOUT; +} diff --git a/dts/arm64/armv9-a.dtsi b/dts/arm64/armv9-a.dtsi new file mode 100644 index 0000000000000..fb503703beacf --- /dev/null +++ b/dts/arm64/armv9-a.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" + +/ { + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + }; +}; diff --git a/dts/bindings/cpu/arm,cortex-a320.yaml b/dts/bindings/cpu/arm,cortex-a320.yaml new file mode 100644 index 0000000000000..1eddfcdb83b2f --- /dev/null +++ b/dts/bindings/cpu/arm,cortex-a320.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +description: ARM Cortex-A320 CPU + +compatible: "arm,cortex-a320" + +include: cpu.yaml diff --git a/dts/bindings/cpu/arm,cortex-a510.yaml b/dts/bindings/cpu/arm,cortex-a510.yaml new file mode 100644 index 0000000000000..16ffdb3bdff03 --- /dev/null +++ b/dts/bindings/cpu/arm,cortex-a510.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +description: ARM Cortex-A510 CPU + +compatible: "arm,cortex-a510" + +include: cpu.yaml diff --git a/dts/bindings/pm_cpu_ops/arm,fvp-pwrc.yaml b/dts/bindings/pm_cpu_ops/arm,fvp-pwrc.yaml new file mode 100644 index 0000000000000..ce4bf065110b7 --- /dev/null +++ b/dts/bindings/pm_cpu_ops/arm,fvp-pwrc.yaml @@ -0,0 +1,42 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +description: | + ARM Fixed Virtual Platform (FVP) Power Controller (PWRC) + + The FVP PWRC provides CPU power management capabilities on ARM Fixed Virtual + Platform models. This hardware block is part of the Base_PowerController + component and controls CPU power states for bare-metal operation when PSCI + firmware is not available. + + The PWRC registers include: + - PPOFFR (0x00): Power off processor request + - PPONR (0x04): Power on processor request + - PCOFFR (0x08): Power off cluster request + - PWKUPR (0x0c): Wakeup request control + - PSYSR (0x10): System power status register + + For system reset operations, this controller requires access to the V2M + System Registers (vexpress-sysreg). + + Reference: + - Fast Models FVP Reference Guide (ARM DUI 0966) + - ARM Trusted Firmware-A: drivers/arm/fvp/fvp_pwrc.c + +compatible: "arm,fvp-pwrc" + +include: base.yaml + +properties: + reg: + required: true + description: | + Base address and size of the FVP Power Controller register block. + Typically 0x1c100000 with size 0x1000 on FVP Base RevC platforms. + + arm,vexpress-sysreg: + type: phandle + description: | + Reference to the ARM Versatile Express System Registers (v2m_sysreg) node. + Required for system reset operations via the SYS_CFGCTRL register. + See ARM Motherboard Express µATX Technical Reference Manual (DUI 0447). diff --git a/include/zephyr/arch/arm64/cpu.h b/include/zephyr/arch/arm64/cpu.h index 076f2d9b0257e..6a69fe76ad597 100644 --- a/include/zephyr/arch/arm64/cpu.h +++ b/include/zephyr/arch/arm64/cpu.h @@ -54,7 +54,8 @@ #define SCTLR_I_BIT BIT(12) #define SCTLR_BR_BIT BIT(17) -#define CPACR_EL1_FPEN_NOTRAP (0x3 << 20) +#define CPACR_EL1_FPEN GENMASK(21, 20) +#define CPACR_EL1_ZEN GENMASK(17, 16) #define SCR_NS_BIT BIT(0) #define SCR_IRQ_BIT BIT(1) @@ -113,6 +114,12 @@ #define ID_AA64PFR0_EL2_SHIFT (8) #define ID_AA64PFR0_EL3_SHIFT (12) #define ID_AA64PFR0_ELX_MASK (0xf) +#define ID_AA64PFR0_FP_SHIFT (16) +#define ID_AA64PFR0_FP_MASK (0xf) +#define ID_AA64PFR0_ADVSIMD_SHIFT (20) +#define ID_AA64PFR0_ADVSIMD_MASK (0xf) +#define ID_AA64PFR0_SVE_SHIFT (32) +#define ID_AA64PFR0_SVE_MASK (0xf) #define ID_AA64PFR0_SEL2_SHIFT (36) #define ID_AA64PFR0_SEL2_MASK (0xf) @@ -132,8 +139,20 @@ #define CPTR_TTA_BIT BIT(20) #define CPTR_TCPAC_BIT BIT(31) +/* SVE-specific CPTR_EL2 bits */ +#define CPTR_EL2_TZ_BIT BIT(8) +#define CPTR_EL2_ZEN_SHIFT 16 +#define CPTR_EL2_ZEN_MASK (0x3 << CPTR_EL2_ZEN_SHIFT) +#define CPTR_EL2_ZEN_EL1_EN BIT(16) +#define CPTR_EL2_ZEN_EL0_EN BIT(17) + #define CPTR_EL2_RES1 BIT(13) | BIT(12) | BIT(9) | (0xff) +/* SVE Control Register (ZCR) */ +#define ZCR_EL1 S3_0_C1_C2_0 +#define ZCR_EL2 S3_4_C1_C2_0 +#define ZCR_EL3 S3_6_C1_C2_0 + #define HCR_FMO_BIT BIT(3) #define HCR_IMO_BIT BIT(4) #define HCR_AMO_BIT BIT(5) diff --git a/include/zephyr/arch/arm64/lib_helpers.h b/include/zephyr/arch/arm64/lib_helpers.h index e720808dbb09a..f73813ea81694 100644 --- a/include/zephyr/arch/arm64/lib_helpers.h +++ b/include/zephyr/arch/arm64/lib_helpers.h @@ -69,7 +69,11 @@ MAKE_REG_HELPER(csselr_el1); MAKE_REG_HELPER(daif) MAKE_REG_HELPER(hcr_el2); MAKE_REG_HELPER(id_aa64pfr0_el1); +MAKE_REG_HELPER(id_aa64pfr1_el1); MAKE_REG_HELPER(id_aa64mmfr0_el1); +MAKE_REG_HELPER(id_aa64isar0_el1); +MAKE_REG_HELPER(id_aa64isar1_el1); +MAKE_REG_HELPER(id_aa64isar2_el1); MAKE_REG_HELPER(mpidr_el1); MAKE_REG_HELPER(par_el1); #if !defined(CONFIG_ARMV8_R) @@ -91,6 +95,7 @@ MAKE_REG_HELPER_EL123(spsr) MAKE_REG_HELPER_EL123(tcr) MAKE_REG_HELPER_EL123(ttbr0) MAKE_REG_HELPER_EL123(vbar) +MAKE_REG_HELPER_EL123(zcr) #if defined(CONFIG_ARM_MPU) /* Armv8-R aarch64 mpu registers */ @@ -199,6 +204,11 @@ static inline bool is_in_secure_state(void) return !IS_ENABLED(CONFIG_ARMV8_A_NS); } +static inline bool is_sve_implemented(void) +{ + return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT) & ID_AA64PFR0_SVE_MASK) != 0U); +} + #endif /* !_ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_ARCH_ARM64_LIB_HELPERS_H_ */ diff --git a/include/zephyr/arch/arm64/thread.h b/include/zephyr/arch/arm64/thread.h index 457a8c078394e..16fdb430ee76a 100644 --- a/include/zephyr/arch/arm64/thread.h +++ b/include/zephyr/arch/arm64/thread.h @@ -43,13 +43,24 @@ struct _callee_saved { typedef struct _callee_saved _callee_saved_t; struct z_arm64_fp_context { - __int128 q0, q1, q2, q3, q4, q5, q6, q7; - __int128 q8, q9, q10, q11, q12, q13, q14, q15; - __int128 q16, q17, q18, q19, q20, q21, q22, q23; - __int128 q24, q25, q26, q27, q28, q29, q30, q31; uint32_t fpsr, fpcr; + union { + struct { + __int128 v_regs[32]; + } neon; +#ifdef CONFIG_ARM64_SVE + struct { + uint8_t z_regs[32 * CONFIG_ARM64_SVE_VL_MAX] __aligned(8); + uint8_t p_regs[16 * (CONFIG_ARM64_SVE_VL_MAX / 8)]; + uint8_t ffr[CONFIG_ARM64_SVE_VL_MAX / 8]; + enum { SIMD_NONE = 0, SIMD_NEON, SIMD_SVE } simd_mode; + } sve; +#endif + }; }; +typedef struct z_arm64_fp_context z_arm64_fp_context; + struct _thread_arch { #if defined(CONFIG_USERSPACE) || defined(CONFIG_ARM64_STACK_PROTECTION) #if defined(CONFIG_ARM_MMU) @@ -64,10 +75,11 @@ struct _thread_arch { #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK uint64_t stack_limit; #endif + uint8_t exception_depth; + /* Keep large structures at the end to avoid offset issues */ #ifdef CONFIG_FPU_SHARING struct z_arm64_fp_context saved_fp_context; #endif - uint8_t exception_depth; }; typedef struct _thread_arch _thread_arch_t; diff --git a/modules/trusted-firmware-a/CMakeLists.txt b/modules/trusted-firmware-a/CMakeLists.txt index 0c0230174f094..d4e0a56c2639b 100644 --- a/modules/trusted-firmware-a/CMakeLists.txt +++ b/modules/trusted-firmware-a/CMakeLists.txt @@ -28,12 +28,20 @@ if (CONFIG_BUILD_WITH_TFA) set(TFA_BUILD_DEBUG "0") endif() + # ARMv9-A is AArch64-only, disable AArch32 register context + if (CONFIG_ARMV9_A) + set(TFA_AARCH32_REGS "CTX_INCLUDE_AARCH32_REGS=0") + else() + set(TFA_AARCH32_REGS "") + endif() + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND make -C ${ZEPHYR_TRUSTED_FIRMWARE_A_MODULE_DIR} DEBUG=${TFA_BUILD_DEBUG} CROSS_COMPILE=${CROSS_COMPILE} BUILD_BASE=${TFA_BINARY_DIR} PLAT=${TFA_PLAT} BL33=${CMAKE_BINARY_DIR}/zephyr/${KERNEL_BIN_NAME} + ${TFA_AARCH32_REGS} all fip ) endif() diff --git a/samples/net/dhcpv4_client/README.rst b/samples/net/dhcpv4_client/README.rst index 05d9df3c95640..0ff5a39089d3b 100644 --- a/samples/net/dhcpv4_client/README.rst +++ b/samples/net/dhcpv4_client/README.rst @@ -196,7 +196,7 @@ Arm FVP ======== * :zephyr:board:`fvp_baser_aemv8r` -* :ref:`fvp_base_revc_2xaemv8a` +* :ref:`fvp_base_revc_2xaem` This sample application running on Arm FVP board can negotiate IP address from DHCPv4 server running on Arm FVP, so there is no extra diff --git a/soc/arm/fvp_aemv8a/CMakeLists.txt b/soc/arm/fvp_aem/CMakeLists.txt similarity index 100% rename from soc/arm/fvp_aemv8a/CMakeLists.txt rename to soc/arm/fvp_aem/CMakeLists.txt diff --git a/soc/arm/fvp_aem/Kconfig b/soc/arm/fvp_aem/Kconfig new file mode 100644 index 0000000000000..14e0c8317ad58 --- /dev/null +++ b/soc/arm/fvp_aem/Kconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_FVP_AEM + bool + help + Enable support for ARM FVP AEM (Architectural Envelope Model) Series + +config SOC_FVP_V8A + bool + select ARM64 + select CPU_CORTEX_A53 + +config SOC_FVP_V9A + bool + select ARM64 + select CPU_CORTEX_A510 + +config SOC_FVP_A320 + bool + select ARM64 + select CPU_CORTEX_A320 diff --git a/soc/arm/fvp_aemv8a/Kconfig.defconfig b/soc/arm/fvp_aem/Kconfig.defconfig similarity index 80% rename from soc/arm/fvp_aemv8a/Kconfig.defconfig rename to soc/arm/fvp_aem/Kconfig.defconfig index 38c672c767564..5722e15041983 100644 --- a/soc/arm/fvp_aemv8a/Kconfig.defconfig +++ b/soc/arm/fvp_aem/Kconfig.defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2021 Carlo Caione # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_FVP_AEMV8A +if SOC_SERIES_FVP_AEM config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 @@ -10,8 +10,6 @@ config NUM_IRQS default 16384 if GIC_V3_ITS default 128 if !GIC_V3_ITS -if SOC_FVP_BASE_REVC_2XAEMV8A - # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash @@ -21,6 +19,4 @@ config FLASH_SIZE config FLASH_BASE_ADDRESS default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) -endif # SOC_FVP_BASE_REVC_2XAEMV8A - -endif # SOC_SERIES_FVP_AEMV8A +endif # SOC_SERIES_FVP_AEM diff --git a/soc/arm/fvp_aem/Kconfig.soc b/soc/arm/fvp_aem/Kconfig.soc new file mode 100644 index 0000000000000..4f675398b4318 --- /dev/null +++ b/soc/arm/fvp_aem/Kconfig.soc @@ -0,0 +1,26 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_FVP_AEM + bool + select SOC_FAMILY_ARM64 + +config SOC_FVP_V8A + bool + select SOC_SERIES_FVP_AEM + +config SOC_FVP_V9A + bool + select SOC_SERIES_FVP_AEM + +config SOC_FVP_A320 + bool + select SOC_SERIES_FVP_AEM + +config SOC + default "v8a" if SOC_FVP_V8A + default "v9a" if SOC_FVP_V9A + default "a320" if SOC_FVP_A320 + +config SOC_SERIES + default "fvp_aem" if SOC_SERIES_FVP_AEM diff --git a/soc/arm/fvp_aemv8a/mmu_regions.c b/soc/arm/fvp_aem/mmu_regions.c similarity index 100% rename from soc/arm/fvp_aemv8a/mmu_regions.c rename to soc/arm/fvp_aem/mmu_regions.c diff --git a/soc/arm/fvp_aemv8a/Kconfig b/soc/arm/fvp_aemv8a/Kconfig deleted file mode 100644 index 879ff0030db6a..0000000000000 --- a/soc/arm/fvp_aemv8a/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2021 Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_FVP_AEMV8A - select ARM64 - help - Enable support for ARM FVP AEMv8A AArch64 Series - -config SOC_FVP_BASE_REVC_2XAEMV8A - select CPU_CORTEX_A53 diff --git a/soc/arm/fvp_aemv8a/Kconfig.soc b/soc/arm/fvp_aemv8a/Kconfig.soc deleted file mode 100644 index bf7739156749e..0000000000000 --- a/soc/arm/fvp_aemv8a/Kconfig.soc +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2021 Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_FVP_AEMV8A - bool - select SOC_FAMILY_ARM64 - -config SOC_FVP_BASE_REVC_2XAEMV8A - bool - -config SOC - default "fvp_base_revc_2xaemv8a" if SOC_FVP_BASE_REVC_2XAEMV8A - -config SOC_SERIES - default "fvp_aemv8a" if SOC_SERIES_FVP_AEMV8A diff --git a/soc/arm/soc.yml b/soc/arm/soc.yml index 821da33e9cf95..8bea602a50370 100644 --- a/soc/arm/soc.yml +++ b/soc/arm/soc.yml @@ -29,9 +29,11 @@ family: - name: designstart_fpga_cortex_m3 - name: arm64 series: - - name: fvp_aemv8a + - name: fvp_aem socs: - - name: fvp_base_revc_2xaemv8a + - name: v8a + - name: v9a + - name: a320 - name: fvp_aemv8r socs: - name: fvp_aemv8r_aarch64 diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h index 118e3c7a6bea5..7f3a97ecfe15e 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -133,6 +133,8 @@ extern "C" { #define PROCESSOR_NAME "cortex-a76" #elif defined(CONFIG_CPU_CORTEX_A78) #define PROCESSOR_NAME "cortex-a78" +#elif defined(CONFIG_CPU_CORTEX_A510) +#define PROCESSOR_NAME "cortex-a510" #elif defined(CONFIG_CPU_CORTEX_R82) #define PROCESSOR_NAME "armv8.4-a+nolse" #endif diff --git a/tests/arch/arm64/arm64_gicv3_its/testcase.yaml b/tests/arch/arm64/arm64_gicv3_its/testcase.yaml index f04143dcc1414..a5d564e9e22e1 100644 --- a/tests/arch/arm64/arm64_gicv3_its/testcase.yaml +++ b/tests/arch/arm64/arm64_gicv3_its/testcase.yaml @@ -1,5 +1,5 @@ tests: arch.arm64.gicv3_its: build_only: true - platform_allow: fvp_base_revc_2xaemv8a + platform_allow: fvp_base_revc_2xaem/v8a skip: true diff --git a/tests/arch/arm64/arm64_isa_features/CMakeLists.txt b/tests/arch/arm64/arm64_isa_features/CMakeLists.txt new file mode 100644 index 0000000000000..b0a6b8af2776e --- /dev/null +++ b/tests/arch/arm64/arm64_isa_features/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(arm64_isa_features) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/arch/arm64/arm64_isa_features/prj.conf b/tests/arch/arm64/arm64_isa_features/prj.conf new file mode 100644 index 0000000000000..328a3676b6852 --- /dev/null +++ b/tests/arch/arm64/arm64_isa_features/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_OUTPUT_DISASSEMBLY=y diff --git a/tests/arch/arm64/arm64_isa_features/src/main.c b/tests/arch/arm64/arm64_isa_features/src/main.c new file mode 100644 index 0000000000000..92ea0e63228d3 --- /dev/null +++ b/tests/arch/arm64/arm64_isa_features/src/main.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +ZTEST_SUITE(arm64_isa_features, NULL, NULL, NULL, NULL, NULL); + +ZTEST(arm64_isa_features, test_arm64_feature_detection) +{ + uint64_t pfr0 = read_id_aa64pfr0_el1(); + uint64_t current_el = read_currentel(); + uint64_t mmfr0 = read_id_aa64mmfr0_el1(); + + TC_PRINT("=== ARM64 ISA Feature Detection ===\n"); + TC_PRINT("ID_AA64PFR0_EL1: 0x%016llx\n", pfr0); + TC_PRINT("ID_AA64MMFR0_EL1: 0x%016llx\n", mmfr0); + + /* Check for ARMv9-A specific features */ + TC_PRINT("\n=== Feature Analysis ===\n"); + + /* SVE support (Scalable Vector Extension) */ + bool sve = is_sve_implemented(); + + TC_PRINT("SVE support: %s\n", sve ? "YES" : "NO"); + + if (sve) { +#ifdef CONFIG_ARM64_SVE + uint32_t vl; + + __asm__("rdvl %0, #1" : "=r"(vl)); + TC_PRINT("SVE vector length: %u bytes\n", vl); + + if (vl < CONFIG_ARM64_SVE_VL_MAX) { + TC_PRINT("Warning: CONFIG_ARM64_SVE_VL_MAX=%u while the hardware " + "vector length is %u.\n", CONFIG_ARM64_SVE_VL_MAX, vl); + TC_PRINT("Warning: This will waste memory in struct k_thread.\n"); + } +#else + TC_PRINT("Warning: CONFIG_ARM64_SVE is not set\n"); +#endif + } + + /* Current Exception Level */ + TC_PRINT("Current EL: EL%llu\n", GET_EL(current_el)); + + /* Check EL support */ + TC_PRINT("EL0 AArch64: %s\n", is_el_implemented(0) ? "YES" : "NO"); + TC_PRINT("EL1 AArch64: %s\n", is_el_implemented(1) ? "YES" : "NO"); + TC_PRINT("EL2 AArch64: %s\n", is_el_implemented(2) ? "YES" : "NO"); + TC_PRINT("EL3 AArch64: %s\n", is_el_implemented(3) ? "YES" : "NO"); + + /* Advanced SIMD (NEON) */ + uint64_t advsimd = (pfr0 >> ID_AA64PFR0_ADVSIMD_SHIFT) & ID_AA64PFR0_ADVSIMD_MASK; + + TC_PRINT("Advanced SIMD (NEON): %s (0x%llx)\n", + (advsimd == 0) ? "YES" : (advsimd == 0xf) ? "NO" : "PARTIAL", advsimd); + + /* Floating Point */ + uint64_t fp = (pfr0 >> ID_AA64PFR0_FP_SHIFT) & ID_AA64PFR0_FP_MASK; + + TC_PRINT("Floating Point: %s (0x%llx)\n", + (fp == 0) ? "YES" : (fp == 0xf) ? "NO" : "PARTIAL", fp); + + /* Check for additional ARMv8.5-A+ and ARMv9-A indicators */ + uint64_t pfr1 = read_id_aa64pfr1_el1(); + uint64_t isar0 = read_id_aa64isar0_el1(); + uint64_t isar1 = read_id_aa64isar1_el1(); + uint64_t isar2 = read_id_aa64isar2_el1(); + + TC_PRINT("\nID_AA64PFR1_EL1: 0x%016llx\n", pfr1); + TC_PRINT("ID_AA64ISAR0_EL1: 0x%016llx\n", isar0); + TC_PRINT("ID_AA64ISAR1_EL1: 0x%016llx\n", isar1); + TC_PRINT("ID_AA64ISAR2_EL1: 0x%016llx\n", isar2); + + /* Check for ARMv8.1 LSE atomics */ + uint64_t lse = (isar0 >> 20) & 0xf; + + TC_PRINT("LSE Atomics: %s (0x%llx)\n", lse ? "YES" : "NO", lse); + + /* Check for Pointer Authentication */ + uint64_t pauth_api = (isar1 >> 4) & 0xf; + uint64_t pauth_apa = (isar1 >> 8) & 0xf; + uint64_t pauth_gpi = (isar1 >> 28) & 0xf; + uint64_t pauth_gpa = (isar1 >> 24) & 0xf; + + TC_PRINT("Pointer Auth (API - Address ImplDef): %s (0x%llx)\n", + pauth_api ? "YES" : "NO", pauth_api); + TC_PRINT("Pointer Auth (APA - Address Arch): %s (0x%llx)\n", + pauth_apa ? "YES" : "NO", pauth_apa); + TC_PRINT("Pointer Auth (GPI - Instr ImplDef): %s (0x%llx)\n", + pauth_gpi ? "YES" : "NO", pauth_gpi); + TC_PRINT("Pointer Auth (GPA - Instr Arch): %s (0x%llx)\n", + pauth_gpa ? "YES" : "NO", pauth_gpa); + + /* Decode APA level */ + if (pauth_apa == 0x5) { + TC_PRINT(" APA Level 5: Enhanced PAC with FPACCOMBINE\n"); + } else if (pauth_apa == 0x4) { + TC_PRINT(" APA Level 4: Enhanced PAC with FPAC\n"); + } else if (pauth_apa == 0x3) { + TC_PRINT(" APA Level 3: Enhanced PAC2\n"); + } else if (pauth_apa == 0x1) { + TC_PRINT(" APA Level 1: Basic PAC\n"); + } + + /* Check for Branch Target Identification (ARMv8.5-A) */ + uint64_t bti = (pfr1 >> 0) & 0xf; + + TC_PRINT("Branch Target Identification (BTI): %s (0x%llx)\n", bti ? "YES" : "NO", bti); + + /* Check for Memory Tagging Extensions (ARMv8.5-A) */ + uint64_t mte = (pfr1 >> 8) & 0xf; + + TC_PRINT("Memory Tagging Extension (MTE): %s (0x%llx)\n", mte ? "YES" : "NO", mte); + if (mte == 0x2) { + TC_PRINT(" MTE Level 2: Full MTE\n"); + } else if (mte == 0x1) { + TC_PRINT(" MTE Level 1: EL0-only\n"); + } + + /* Check for Random Number Generation (ARMv8.5-A) */ + uint64_t rndr = (pfr1 >> 16) & 0xf; + + TC_PRINT("Random Number Generation (RNDR): %s (0x%llx)\n", rndr ? "YES" : "NO", rndr); + + /* Check for Speculative Store Bypass Safe (ARMv8.5-A) */ + uint64_t ssbs = (pfr1 >> 12) & 0xf; + + TC_PRINT("Speculative Store Bypass Safe (SSBS): %s (0x%llx)\n", ssbs ? "YES" : "NO", ssbs); + + /* Check for additional ISAR2 features */ + /* WFxT - Wait For Event/Interrupt with Timeout (ARMv8.7-A) */ + uint64_t wfxt = (isar2 >> 0) & 0xf; + + TC_PRINT("WFxT (Wait with Timeout): %s (0x%llx)\n", wfxt ? "YES" : "NO", wfxt); + + /* RPRES - Reciprocal Estimate and Reciprocal Square Root Estimate */ + uint64_t rpres = (isar2 >> 4) & 0xf; + + TC_PRINT("RPRES (Reciprocal Precision): %s (0x%llx)\n", rpres ? "YES" : "NO", rpres); + + /* GPA3 - Generic Pointer Authentication using QARMA3 */ + uint64_t gpa3 = (isar2 >> 8) & 0xf; + + TC_PRINT("Pointer Auth (GPA3 - QARMA3): %s (0x%llx)\n", gpa3 ? "YES" : "NO", gpa3); + + /* APA3 - Address Pointer Authentication using QARMA3 */ + uint64_t apa3 = (isar2 >> 12) & 0xf; + + TC_PRINT("Pointer Auth (APA3 - QARMA3): %s (0x%llx)\n", apa3 ? "YES" : "NO", apa3); + + /* MOPS - Memory Copy and Memory Set instructions (ARMv8.8-A) */ + uint64_t mops = (isar2 >> 16) & 0xf; + + TC_PRINT("MOPS (Memory Copy/Set): %s (0x%llx)\n", mops ? "YES" : "NO", mops); + + /* BC - BC (Branch Consistency) model */ + uint64_t bc = (isar2 >> 20) & 0xf; + + TC_PRINT("BC (Branch Consistency): %s (0x%llx)\n", bc ? "YES" : "NO", bc); + + TC_PRINT("\n=== Architecture Assessment ===\n"); + if (sve) { + TC_PRINT("Architecture: ARMv9-A (SVE detected)\n"); + if (bti || mte || rndr) { + TC_PRINT("ARMv8.5-A+ features: "); + if (bti) { + TC_PRINT("BTI "); + } + if (mte) { + TC_PRINT("MTE "); + } + if (rndr) { + TC_PRINT("RNDR "); + } + if (ssbs) { + TC_PRINT("SSBS "); + } + TC_PRINT("\n"); + } + if (wfxt || mops || gpa3 || apa3) { + TC_PRINT("ARMv8.7-A+ features: "); + if (wfxt) { + TC_PRINT("WFxT "); + } + if (mops) { + TC_PRINT("MOPS "); + } + if (gpa3) { + TC_PRINT("GPA3 "); + } + if (apa3) { + TC_PRINT("APA3 "); + } + TC_PRINT("\n"); + } + } else if (bti || mte || rndr || ssbs) { + TC_PRINT("Architecture: ARMv8.5-A+ (BTI/MTE/RNDR detected)\n"); + } else if (lse >= 2 && (pauth_api || pauth_apa)) { + TC_PRINT("Architecture: ARMv8.1+ with enhanced features (LSE Level 2+ and PAC)\n"); + } else if (lse || pauth_api || pauth_apa) { + TC_PRINT("Architecture: ARMv8.1+ with ARMv9-A features (LSE/PAC)\n"); + } else { + TC_PRINT("Architecture: ARMv8-A (no ARMv8.1+ features detected)\n"); + } + + /* Decode LSE level */ + if (lse >= 2) { + TC_PRINT("LSE Level 2: Atomics with enhanced ordering\n"); + } else if (lse == 1) { + TC_PRINT("LSE Level 1: Basic atomic instructions\n"); + } + + /* Basic validation that we can read system registers */ + zassert_not_equal(pfr0, 0, "ID_AA64PFR0_EL1 should not be zero"); + zassert_not_equal(current_el, 0, "CurrentEL should not be zero"); + + /* We should be running in EL1 */ + zassert_equal(GET_EL(current_el), 1, "Should be running in EL1"); + + /* ARMv9-A configuration validation */ + if (IS_ENABLED(CONFIG_ARMV9_A)) { + /* ARMv9-A mandates SVE support */ + zassert_true(sve, "CONFIG_ARMV9_A enabled but no SVE detected"); + + /* ARMv9-A should have enhanced security features */ + zassert_true(pauth_api || pauth_apa, + "CONFIG_ARMV9_A enabled but no Pointer Authentication detected"); + + /* If PAC is present, validate it's enhanced (Level 3+) */ + if (pauth_apa) { + zassert_true(pauth_apa >= 3, + "CONFIG_ARMV9_A enabled but PAC level too low (0x%llx) - " + "expected enhanced PAC (Level 3+)", pauth_apa); + } + + /* ARMv9-A platforms should support modern atomic operations */ + zassert_true(lse >= 1, + "CONFIG_ARMV9_A enabled but no LSE atomics detected"); + } +} diff --git a/tests/arch/arm64/arm64_isa_features/testcase.yaml b/tests/arch/arm64/arm64_isa_features/testcase.yaml new file mode 100644 index 0000000000000..c16f80bf64496 --- /dev/null +++ b/tests/arch/arm64/arm64_isa_features/testcase.yaml @@ -0,0 +1,8 @@ +common: + arch_allow: arm64 + tags: arm64 + +tests: + arch.arm64.isa_features: + integration_platforms: + - fvp_base_revc_2xaem/v9a diff --git a/tests/arch/arm64/arm64_smc_call/testcase.yaml b/tests/arch/arm64/arm64_smc_call/testcase.yaml index eb424fe1a5237..b6f5fde44d908 100644 --- a/tests/arch/arm64/arm64_smc_call/testcase.yaml +++ b/tests/arch/arm64/arm64_smc_call/testcase.yaml @@ -1,6 +1,6 @@ tests: arch.arm64.smc_call.smc: - platform_allow: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + platform_allow: fvp_base_revc_2xaem/v8a/smp/ns tags: - arm - smc diff --git a/tests/arch/arm64/arm64_sve_ctx/CMakeLists.txt b/tests/arch/arm64/arm64_sve_ctx/CMakeLists.txt new file mode 100644 index 0000000000000..e3f0b7a642362 --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(arm64_sve_ctx) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/arch/arm64/arm64_sve_ctx/prj.conf b/tests/arch/arm64/arm64_sve_ctx/prj.conf new file mode 100644 index 0000000000000..362628190122e --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/prj.conf @@ -0,0 +1,10 @@ +CONFIG_ZTEST=y +CONFIG_FPU=y +CONFIG_FPU_SHARING=y +CONFIG_ARM64_SVE=y +CONFIG_ARM64_SVE_VL_MAX=256 + +# Enable userspace for SVE context switching test +CONFIG_USERSPACE=y +CONFIG_MAX_THREAD_BYTES=3 +CONFIG_TEST_USERSPACE=y diff --git a/tests/arch/arm64/arm64_sve_ctx/src/main.c b/tests/arch/arm64/arm64_sve_ctx/src/main.c new file mode 100644 index 0000000000000..151c064121def --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/src/main.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/* Helper function for SVE vector length */ +static inline uint32_t sve_get_vl(void) +{ + uint32_t vl; + + __asm__("rdvl %0, #1" : "=r"(vl)); + return vl; +} + +ZTEST(arm64_sve_ctx, test_sve_basic_instructions) +{ + /* Check if SVE is actually available */ + uint64_t pfr0 = read_id_aa64pfr0_el1(); + bool sve = is_sve_implemented(); + + TC_PRINT("=== SVE Feature Check ===\n"); + TC_PRINT("ID_AA64PFR0_EL1: 0x%016llx\n", pfr0); + TC_PRINT("SVE support: %s\n", sve ? "YES" : "NO"); + zassert_true(sve, "SVE support required for this test"); + + /* Simple test: just try to read SVE vector length */ + TC_PRINT("About to test SVE access...\n"); + uint32_t vl = sve_get_vl(); + + TC_PRINT("SVE vector length: %u bytes\n", vl); + zassert_not_equal(vl, 0, "SVE vector length should not be zero"); + + /* Verify vector length is within expected bounds */ + zassert_true(vl >= 16, "SVE vector length must be at least 16 bytes"); + zassert_true(vl <= CONFIG_ARM64_SVE_VL_MAX, + "SVE vector length %u exceeds maximum %u", vl, CONFIG_ARM64_SVE_VL_MAX); + if (vl < CONFIG_ARM64_SVE_VL_MAX) { + TC_PRINT("Warning: CONFIG_ARM64_SVE_VL_MAX=%u while the hardware " + "vector length is %u.\n", CONFIG_ARM64_SVE_VL_MAX, vl); + TC_PRINT("Warning: This will waste memory in struct k_thread.\n"); + } +} + +#define STACK_SIZE 4096 +#define THREAD_PRIORITY 1 + +K_THREAD_STACK_DEFINE(thread1_stack, STACK_SIZE); +K_THREAD_STACK_DEFINE(thread2_stack, STACK_SIZE); + +static struct k_thread thread1_data; +static struct k_thread thread2_data; + +/* Synchronization */ +static struct k_sem sync_sem; +static struct k_sem done_sem; + +/* User space memory partition for test results */ +K_APPMEM_PARTITION_DEFINE(sve_test_partition); +K_APP_DMEM(sve_test_partition) static volatile bool thread1_sve_ok; +K_APP_DMEM(sve_test_partition) static volatile bool thread2_sve_ok; + +/* Set unique patterns in SVE Z registers for thread identification */ +static inline void sve_set_thread_pattern(uint32_t thread_id) +{ + /* Create unique 32-bit pattern based on thread ID */ + uint32_t pattern = 0x12340000 | (thread_id & 0xFFF); + + /* Use SVE DUP instruction to fill Z registers with pattern */ + __asm__ volatile ( + "mov w0, %w0\n" + "sve_pattern_loop_%=:\n" + "dup z0.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z1.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z2.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z3.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z4.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z5.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z6.s, w0\n" + "add w0, w0, #0x1000\n" + "dup z7.s, w0\n" + : + : "r" (pattern) + : "w0", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "memory" + ); +} + +/* Set patterns in SVE P (predicate) registers */ +static inline void sve_set_predicate_pattern(uint32_t thread_id) +{ + /* Set alternating patterns in predicate registers */ + if (thread_id & 1) { + __asm__ volatile ( + "ptrue p0.b\n" + "pfalse p1.b\n" + "ptrue p2.s\n" + "pfalse p3.b\n" + ::: "p0", "p1", "p2", "p3", "memory" + ); + } else { + __asm__ volatile ( + "pfalse p0.b\n" + "ptrue p1.h\n" + "pfalse p2.b\n" + "ptrue p3.d\n" + ::: "p0", "p1", "p2", "p3", "memory" + ); + } +} + +/* Verify SVE Z register patterns */ +static inline bool sve_verify_z_pattern(uint32_t thread_id) +{ + /* Use stack-allocated buffer for user threads */ + uint32_t actual_buffer[8 * 256/4] __aligned(8); + uint32_t *actual_p = actual_buffer; + uint32_t vl = sve_get_vl(); + uint32_t expected_base = 0x12340000 | (thread_id & 0xFFF); + bool result = true; + + /* Store elements from Z registers to memory, then read back */ + __asm__ volatile ( + "str z0, [%0, #0, MUL VL]\n" + "str z1, [%0, #1, MUL VL]\n" + "str z2, [%0, #2, MUL VL]\n" + "str z3, [%0, #3, MUL VL]\n" + "str z4, [%0, #4, MUL VL]\n" + "str z5, [%0, #5, MUL VL]\n" + "str z6, [%0, #6, MUL VL]\n" + "str z7, [%0, #7, MUL VL]\n" + : + : "r" (actual_buffer) + : "memory" + ); + + /* Verify each register has expected sequential pattern */ + for (int i = 0; i < 8; i++) { + for (int j = 0; j < vl/4; j++) { + uint32_t expected = expected_base + (i * 0x1000); + uint32_t actual = *actual_p++; + + if (actual != expected) { + TC_PRINT("Thread %u: Z%d mismatch - " + "expected 0x%x, got 0x%x\n", + thread_id, i, expected, actual); + result = false; + } + } + } + + return result; +} + +/* Verify SVE P register patterns */ +static inline bool sve_verify_p_pattern(uint32_t thread_id) +{ + uint8_t p_buffer[4 * 256/8]; + uint8_t *p_p = p_buffer; + uint32_t vl = sve_get_vl(); + bool result = true; + + /* Store predicate registers to memory and read them back */ + __asm__ volatile ( + "str p0, [%0, #0, MUL VL]\n" + "str p1, [%0, #1, MUL VL]\n" + "str p2, [%0, #2, MUL VL]\n" + "str p3, [%0, #3, MUL VL]\n" + : + : "r" (p_buffer) + : "memory" + ); + + /* Check expected patterns based on thread ID */ + for (int i = 0; i < 4; i++) { + for (int j = 0; j < vl/8; j++) { + /* Thread 1: p0=true, p1=false, p2=true, p3=false */ + /* Thread 2: p0=false, p1=true, p2=false, p3=true */ + /* p0 = b, p1 = h, p2 = s, p3 = d */ + static const uint8_t patterns[4] = { 0xff, 0x55, 0x11, 0x01 }; + uint8_t expected = ((thread_id ^ i) & 1) ? patterns[i] : 0; + uint8_t actual = *p_p++; + + if (actual != expected) { + TC_PRINT("Thread %u: P%d mismatch - " + "expected 0x%x, got 0x%x\n", + thread_id, i, expected, actual); + result = false; + } + } + } + + return result; +} + +/* + * Test thread functions + */ +static void sve_test_thread1(void *arg1, void *arg2, void *arg3) +{ + const uint32_t thread_id = 1; + + TC_PRINT("Thread 1: Starting SVE context test\n"); + + /* Set initial SVE patterns */ + sve_set_thread_pattern(thread_id); + sve_set_predicate_pattern(thread_id); + + /* Immediate validation after setting patterns - NO function calls in between */ + zassert_true(sve_verify_z_pattern(thread_id), + "Thread 1: Initial Z pattern validation failed"); + zassert_true(sve_verify_p_pattern(thread_id), + "Thread 1: Initial P pattern validation failed"); + + TC_PRINT("Thread 1: Set initial SVE patterns\n"); + + /* Signal that we're ready and wait for other thread */ + k_sem_give(&sync_sem); + k_msleep(1); + k_sem_take(&sync_sem, K_FOREVER); + + /* Verify our patterns are still intact */ + bool z_ok = sve_verify_z_pattern(thread_id); + bool p_ok = sve_verify_p_pattern(thread_id); + + thread1_sve_ok = z_ok && p_ok; + + TC_PRINT("Thread 1: SVE verification %s (Z:%s P:%s)\n", + thread1_sve_ok ? "PASSED" : "FAILED", + z_ok ? "OK" : "FAIL", p_ok ? "OK" : "FAIL"); + + k_sem_give(&sync_sem); +} + +static void sve_test_thread2(void *arg1, void *arg2, void *arg3) +{ + const uint32_t thread_id = 2; + + TC_PRINT("Thread 2: Starting SVE context test\n"); + + /* Wait for thread 1 to be ready */ + k_sem_take(&sync_sem, K_FOREVER); + + /* Set our own SVE patterns */ + sve_set_thread_pattern(thread_id); + sve_set_predicate_pattern(thread_id); + + /* Immediate validation after setting patterns - NO function calls in between */ + zassert_true(sve_verify_z_pattern(thread_id), + "Thread 2: Initial Z pattern validation failed"); + zassert_true(sve_verify_p_pattern(thread_id), + "Thread 2: Initial P pattern validation failed"); + + TC_PRINT("Thread 2: Set initial SVE patterns\n"); + + /* Signal thread 1 to continue */ + k_sem_give(&sync_sem); + k_msleep(1); + k_sem_take(&sync_sem, K_FOREVER); + + /* Verify our patterns are still intact */ + bool z_ok = sve_verify_z_pattern(thread_id); + bool p_ok = sve_verify_p_pattern(thread_id); + + thread2_sve_ok = z_ok && p_ok; + + TC_PRINT("Thread 2: SVE verification %s (Z:%s P:%s)\n", + thread2_sve_ok ? "PASSED" : "FAILED", + z_ok ? "OK" : "FAIL", p_ok ? "OK" : "FAIL"); + + k_sem_give(&done_sem); +} + +/* + * Test suite setup and tests + */ +static struct k_mem_domain sve_test_domain; + +static void *sve_ctx_setup(void) +{ + k_sem_init(&sync_sem, 0, 1); + k_sem_init(&done_sem, 0, 1); + + /* Initialize memory domain for user threads */ + struct k_mem_partition *parts[] = { &sve_test_partition }; + + k_mem_domain_init(&sve_test_domain, 1, parts); + + return NULL; +} + +static void sve_ctx_before(void *fixture) +{ + /* Reset test results and semaphores before each test */ + thread1_sve_ok = false; + thread2_sve_ok = false; + k_sem_reset(&sync_sem); + k_sem_reset(&done_sem); +} + +ZTEST(arm64_sve_ctx, test_sve_context_switching_privileged) +{ + TC_PRINT("=== Testing SVE Context Switching: Privileged vs Privileged ===\n"); + + /* Create privileged kernel threads that will use SVE */ + k_thread_create(&thread1_data, thread1_stack, STACK_SIZE, + sve_test_thread1, NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&thread1_data, "sve_priv_thread1"); + + k_thread_create(&thread2_data, thread2_stack, STACK_SIZE, + sve_test_thread2, NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&thread2_data, "sve_priv_thread2"); + + /* Wait for both threads to complete */ + k_sem_take(&done_sem, K_FOREVER); + + /* Clean up */ + k_thread_join(&thread1_data, K_FOREVER); + k_thread_join(&thread2_data, K_FOREVER); + + /* Verify both threads maintained their SVE context */ + zassert_true(thread1_sve_ok, "Privileged Thread 1 SVE context was corrupted"); + zassert_true(thread2_sve_ok, "Privileged Thread 2 SVE context was corrupted"); +} + +ZTEST(arm64_sve_ctx, test_sve_context_switching_user) +{ + TC_PRINT("=== Testing SVE Context Switching: User vs User ===\n"); + + /* Create user threads that will use SVE */ + k_thread_create(&thread1_data, thread1_stack, STACK_SIZE, + sve_test_thread1, NULL, NULL, NULL, + THREAD_PRIORITY, K_USER, K_NO_WAIT); + k_thread_name_set(&thread1_data, "sve_user_thread1"); + + /* Grant permission to semaphores for user thread 1 */ + k_object_access_grant(&sync_sem, &thread1_data); + k_object_access_grant(&done_sem, &thread1_data); + + /* Add thread 1 to memory domain for accessing result variables */ + k_mem_domain_add_thread(&sve_test_domain, &thread1_data); + + k_thread_create(&thread2_data, thread2_stack, STACK_SIZE, + sve_test_thread2, NULL, NULL, NULL, + THREAD_PRIORITY, K_USER, K_NO_WAIT); + k_thread_name_set(&thread2_data, "sve_user_thread2"); + + /* Grant permission to semaphores for user thread 2 */ + k_object_access_grant(&sync_sem, &thread2_data); + k_object_access_grant(&done_sem, &thread2_data); + + /* Add thread 2 to memory domain for accessing result variables */ + k_mem_domain_add_thread(&sve_test_domain, &thread2_data); + + /* Wait for both threads to complete */ + k_sem_take(&done_sem, K_FOREVER); + + /* Clean up */ + k_thread_join(&thread1_data, K_FOREVER); + k_thread_join(&thread2_data, K_FOREVER); + + /* Verify both threads maintained their SVE context */ + zassert_true(thread1_sve_ok, "User Thread 1 SVE context was corrupted"); + zassert_true(thread2_sve_ok, "User Thread 2 SVE context was corrupted"); +} + +ZTEST(arm64_sve_ctx, test_sve_context_switching_mixed) +{ + TC_PRINT("=== Testing SVE Context Switching: User vs Privileged ===\n"); + + /* Create mixed privilege threads: thread 1 = user, thread 2 = privileged */ + k_thread_create(&thread1_data, thread1_stack, STACK_SIZE, + sve_test_thread1, NULL, NULL, NULL, + THREAD_PRIORITY, K_USER, K_NO_WAIT); + k_thread_name_set(&thread1_data, "sve_user_thread1"); + + /* Grant permission to semaphores for user thread 1 */ + k_object_access_grant(&sync_sem, &thread1_data); + k_object_access_grant(&done_sem, &thread1_data); + + /* Add thread 1 to memory domain for accessing result variables */ + k_mem_domain_add_thread(&sve_test_domain, &thread1_data); + + k_thread_create(&thread2_data, thread2_stack, STACK_SIZE, + sve_test_thread2, NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&thread2_data, "sve_priv_thread2"); + + /* Privileged thread doesn't need special permissions */ + + /* Wait for both threads to complete */ + k_sem_take(&done_sem, K_FOREVER); + + /* Clean up */ + k_thread_join(&thread1_data, K_FOREVER); + k_thread_join(&thread2_data, K_FOREVER); + + /* Verify both threads maintained their SVE context */ + zassert_true(thread1_sve_ok, "User Thread 1 SVE context was corrupted"); + zassert_true(thread2_sve_ok, "Privileged Thread 2 SVE context was corrupted"); +} + +ZTEST_SUITE(arm64_sve_ctx, NULL, sve_ctx_setup, sve_ctx_before, NULL, NULL); diff --git a/tests/arch/arm64/arm64_sve_ctx/testcase.yaml b/tests/arch/arm64/arm64_sve_ctx/testcase.yaml new file mode 100644 index 0000000000000..724ca2c1912ff --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/testcase.yaml @@ -0,0 +1,10 @@ +tests: + arch.arm64.sve_ctx: + arch_allow: arm64 + filter: CONFIG_ARM64_SVE + integration_platforms: + - fvp_base_revc_2xaem/v9a + tags: + - sve + - arm64 + - context_switch diff --git a/tests/arch/common/interrupt/src/nested_irq.c b/tests/arch/common/interrupt/src/nested_irq.c index e2a9b70ee360e..415f8ad83cd0f 100644 --- a/tests/arch/common/interrupt/src/nested_irq.c +++ b/tests/arch/common/interrupt/src/nested_irq.c @@ -46,10 +46,12 @@ #elif defined(CONFIG_GIC) /* * For the platforms that use the ARM GIC, use the SGI (software generated - * interrupt) lines 14 and 15 for testing. + * interrupt) lines 6 and 7 for testing. + * SGI 0-2 are used by Zephyr for SMP IPIs. + * SGI 8-15 are unaccessible from Non-Secure state. */ -#define IRQ0_LINE 14 -#define IRQ1_LINE 15 +#define IRQ0_LINE 6 +#define IRQ1_LINE 7 /* * Choose lower prio for IRQ0 and higher priority for IRQ1 diff --git a/tests/kernel/mem_protect/syscalls/src/main.c b/tests/kernel/mem_protect/syscalls/src/main.c index 5c7311a9df617..fde992f4ae8db 100644 --- a/tests/kernel/mem_protect/syscalls/src/main.c +++ b/tests/kernel/mem_protect/syscalls/src/main.c @@ -13,7 +13,7 @@ #define BUF_SIZE 32 -#if defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEMV8A) +#if defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEM) #define SLEEP_MS_LONG 30000 #elif defined(CONFIG_BOARD_INTEL_ADSP_ACE30_PTL_SIM) || \ defined(CONFIG_BOARD_INTEL_ADSP_ACE40_NVL_SIM) diff --git a/tests/subsys/zbus/dyn_channel/testcase.yaml b/tests/subsys/zbus/dyn_channel/testcase.yaml index 3b8cd0b4b5ee4..ce793070e68ad 100644 --- a/tests/subsys/zbus/dyn_channel/testcase.yaml +++ b/tests/subsys/zbus/dyn_channel/testcase.yaml @@ -1,6 +1,6 @@ tests: message_bus.zbus.dyn_channel.static_and_dynamic_channels: - platform_exclude: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + platform_exclude: fvp_base_revc_2xaem/v8a/smp/ns tags: zbus integration_platforms: - native_sim diff --git a/tests/subsys/zbus/hlp_priority_boost/testcase.yaml b/tests/subsys/zbus/hlp_priority_boost/testcase.yaml index 4b06750635146..270d98327054a 100644 --- a/tests/subsys/zbus/hlp_priority_boost/testcase.yaml +++ b/tests/subsys/zbus/hlp_priority_boost/testcase.yaml @@ -1,7 +1,7 @@ tests: message_bus.zbus.hlp_priority_boost: platform_exclude: - - fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + - fvp_base_revc_2xaem/v8a/smp/ns # All Intel Audio DSP platforms have non-coherent cache # between CPUs. So the zbus_channel struct data goes # out-of-sync between CPUs with multiple producer and diff --git a/tests/subsys/zbus/integration/testcase.yaml b/tests/subsys/zbus/integration/testcase.yaml index 9443c61b2f868..8bbc5ecf4418a 100644 --- a/tests/subsys/zbus/integration/testcase.yaml +++ b/tests/subsys/zbus/integration/testcase.yaml @@ -5,7 +5,7 @@ tests: - qemu_cortex_a9 - hifive_unleashed/fu540/e51 - hifive_unleashed/fu540/u54 - - fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + - fvp_base_revc_2xaem/v8a/smp/ns tags: zbus integration_platforms: - native_sim diff --git a/tests/subsys/zbus/unittests/testcase.yaml b/tests/subsys/zbus/unittests/testcase.yaml index 21350d3eccbf8..58f9e1c962172 100644 --- a/tests/subsys/zbus/unittests/testcase.yaml +++ b/tests/subsys/zbus/unittests/testcase.yaml @@ -1,6 +1,6 @@ tests: message_bus.zbus.general_unittests: - platform_exclude: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + platform_exclude: fvp_base_revc_2xaem/v8a/smp/ns tags: zbus integration_platforms: - native_sim @@ -13,7 +13,7 @@ tests: extra_configs: - CONFIG_CMAKE_LINKER_GENERATOR=y message_bus.zbus.general_unittests_without_priority_boost: - platform_exclude: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + platform_exclude: fvp_base_revc_2xaem/v8a/smp/ns tags: zbus integration_platforms: - native_sim diff --git a/tests/subsys/zbus/user_data/testcase.yaml b/tests/subsys/zbus/user_data/testcase.yaml index f2d357e6bc6c0..4890b4f613339 100644 --- a/tests/subsys/zbus/user_data/testcase.yaml +++ b/tests/subsys/zbus/user_data/testcase.yaml @@ -1,6 +1,6 @@ tests: message_bus.zbus.user_data.channel_user_data: - platform_exclude: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp/ns + platform_exclude: fvp_base_revc_2xaem/v8a/smp/ns tags: zbus integration_platforms: - native_sim diff --git a/tests/ztest/error_hook/src/main.c b/tests/ztest/error_hook/src/main.c index 325f931a62db3..119de13363c19 100644 --- a/tests/ztest/error_hook/src/main.c +++ b/tests/ztest/error_hook/src/main.c @@ -134,7 +134,7 @@ __no_optimization static void trigger_fault_divide_zero(void) defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || \ defined(CONFIG_BOARD_QEMU_CORTEX_R5) || \ defined(CONFIG_ARMV8_R) || defined(CONFIG_AARCH32_ARMV8_R) || \ - defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEMV8A) || \ + defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEM) || \ defined(CONFIG_SOC_NSIM_EM11D) ztest_test_skip(); #endif