From 720c17fbdab56a46bb4f35dd5fba391ae3e25ba9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 3 Oct 2025 05:11:49 -0400 Subject: [PATCH 01/18] tests: arm64: Fix nested_irq test for Non-Secure state Change SGI interrupt lines from 14-15 to 6-7 for nested interrupt testing. SGI 8-15 are unaccessible from Non-Secure state (e.g., when running with TF-A), causing test failures. SGI 0-2 are reserved for Zephyr SMP IPIs, so use SGI 6-7 which work in both Secure and Non-Secure configurations. Fixes test failure: "isr0 did not execute" assertion at line 184. Signed-off-by: Nicolas Pitre --- tests/arch/common/interrupt/src/nested_irq.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 From 9f385d669a13f7b52eb1f0dfe2320954c87b06f1 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 02/18] drivers: pm_cpu_ops: Add ARM FVP CPU power management driver Add a new PM CPU ops driver for ARM Fixed Virtual Platform (FVP) that enables bare metal SMP support without ARM Trusted Firmware (ATF). The driver provides CPU power-on and system reset operations by directly interfacing with FVP's power controller (PWRC) and V2M system registers. The implementation includes RVBAR_EL3 configuration to redirect secondary CPU reset vectors to Zephyr's image header, enabling proper SMP initialization without firmware assistance. Signed-off-by: Nicolas Pitre --- boards/arm/fvp_base_revc_2xaemv8a/board.cmake | 8 + drivers/pm_cpu_ops/CMakeLists.txt | 2 + drivers/pm_cpu_ops/Kconfig | 11 ++ drivers/pm_cpu_ops/pm_cpu_ops_fvp.c | 170 ++++++++++++++++++ dts/bindings/pm_cpu_ops/arm,fvp-pwrc.yaml | 42 +++++ 5 files changed, 233 insertions(+) create mode 100644 drivers/pm_cpu_ops/pm_cpu_ops_fvp.c create mode 100644 dts/bindings/pm_cpu_ops/arm,fvp-pwrc.yaml diff --git a/boards/arm/fvp_base_revc_2xaemv8a/board.cmake b/boards/arm/fvp_base_revc_2xaemv8a/board.cmake index 0df438fad9e6b..eaf8ec44ab112 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/board.cmake +++ b/boards/arm/fvp_base_revc_2xaemv8a/board.cmake @@ -43,4 +43,12 @@ if(CONFIG_BUILD_WITH_TFA) 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/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/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). From 46d1d5727136d46c1df00a77c24d27bdf3d871c2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 03/18] boards: arm: fvp_base_revc_2xaemv8a: allow SMP on bare metal This adds necessary configuration files to build with SMP and no trusted firmware. Given PSCI is not available, CPU power management uses the FVP power controller directly. Signed-off-by: Nicolas Pitre --- .../fvp_base_revc_2xaemv8a.dts | 11 +++++++ ...vc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts | 6 ++++ ...c_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml | 16 ++++++++++ ...emv8a_fvp_base_revc_2xaemv8a_smp_defconfig | 31 +++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts create mode 100644 boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml create mode 100644 boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_defconfig diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts index 3a6ff898bf2db..f75be1130b389 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts +++ b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts @@ -96,6 +96,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_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts new file mode 100644 index 0000000000000..76a89c4aa5090 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fvp_base_revc_2xaemv8a.dts" diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml new file mode 100644 index 0000000000000..47e6399c9e003 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp +name: FVP Emulation FVP_Base_RevC-2xAEMvA (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_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_defconfig b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_defconfig new file mode 100644 index 0000000000000..dbd17ee82debb --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_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 From 2e98d31bc819fc05d41eb0dabccc76bfa5366dd4 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 04/18] soc: arm: fvp_aem: Create unified SOC series structure Reorganize fvp_aemv8a SOC into unified fvp_aem series with a v8a architecture variants to enable cleaner board target naming. This also sets the stage for upcoming ARMv9-A support. Signed-off-by: Nicolas Pitre --- .../Kconfig.fvp_base_revc_2xaemv8a | 3 +-- boards/arm/fvp_base_revc_2xaemv8a/board.yml | 2 +- soc/arm/{fvp_aemv8a => fvp_aem}/CMakeLists.txt | 0 soc/arm/{fvp_aemv8a => fvp_aem}/Kconfig | 10 ++++++---- .../{fvp_aemv8a => fvp_aem}/Kconfig.defconfig | 8 ++------ soc/arm/fvp_aem/Kconfig.soc | 16 ++++++++++++++++ soc/arm/{fvp_aemv8a => fvp_aem}/mmu_regions.c | 0 soc/arm/fvp_aemv8a/Kconfig.soc | 15 --------------- soc/arm/soc.yml | 4 ++-- 9 files changed, 28 insertions(+), 30 deletions(-) rename soc/arm/{fvp_aemv8a => fvp_aem}/CMakeLists.txt (100%) rename soc/arm/{fvp_aemv8a => fvp_aem}/Kconfig (52%) rename soc/arm/{fvp_aemv8a => fvp_aem}/Kconfig.defconfig (80%) create mode 100644 soc/arm/fvp_aem/Kconfig.soc rename soc/arm/{fvp_aemv8a => fvp_aem}/mmu_regions.c (100%) delete mode 100644 soc/arm/fvp_aemv8a/Kconfig.soc 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 index 874f1dba01531..894a2c9992d55 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a +++ b/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a @@ -2,5 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_FVP_BASE_REVC_2XAEMV8A - select SOC_SERIES_FVP_AEMV8A - select SOC_FVP_BASE_REVC_2XAEMV8A + select SOC_FVP_V8A diff --git a/boards/arm/fvp_base_revc_2xaemv8a/board.yml b/boards/arm/fvp_base_revc_2xaemv8a/board.yml index 3af023b670ec9..e09e8ea0470da 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/board.yml +++ b/boards/arm/fvp_base_revc_2xaemv8a/board.yml @@ -3,7 +3,7 @@ board: full_name: BASE RevC AEMv8A Fixed Virtual Platforms vendor: arm socs: - - name: fvp_base_revc_2xaemv8a + - name: v8a variants: - name: smp variants: 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_aemv8a/Kconfig b/soc/arm/fvp_aem/Kconfig similarity index 52% rename from soc/arm/fvp_aemv8a/Kconfig rename to soc/arm/fvp_aem/Kconfig index 879ff0030db6a..eca0da629d54a 100644 --- a/soc/arm/fvp_aemv8a/Kconfig +++ b/soc/arm/fvp_aem/Kconfig @@ -1,10 +1,12 @@ # Copyright (c) 2021 Carlo Caione # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_FVP_AEMV8A - select ARM64 +config SOC_SERIES_FVP_AEM + bool help - Enable support for ARM FVP AEMv8A AArch64 Series + Enable support for ARM FVP AEM (Architectural Envelope Model) Series -config SOC_FVP_BASE_REVC_2XAEMV8A +config SOC_FVP_V8A + bool + select ARM64 select CPU_CORTEX_A53 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..935476d9f8d7f --- /dev/null +++ b/soc/arm/fvp_aem/Kconfig.soc @@ -0,0 +1,16 @@ +# 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 + default "v8a" if SOC_FVP_V8A + +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.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..d112dc12a8b8a 100644 --- a/soc/arm/soc.yml +++ b/soc/arm/soc.yml @@ -29,9 +29,9 @@ family: - name: designstart_fpga_cortex_m3 - name: arm64 series: - - name: fvp_aemv8a + - name: fvp_aem socs: - - name: fvp_base_revc_2xaemv8a + - name: v8a - name: fvp_aemv8r socs: - name: fvp_aemv8r_aarch64 From 78503c238022db7e6cd69bf4f77f81bfa8f33f17 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 2 Oct 2025 05:55:22 -0400 Subject: [PATCH 05/18] boards: arm: Create unified fvp_base_revc_2xaem board structure Create unified board configuration to replace verbose board naming with shorter hierarchical structure. This board works with the new unified fvp_aem SOC series and supports the v8a architecture variant. This enables board targets like: - fvp_base_revc_2xaem/v8a (basic ARMv8-A) - fvp_base_revc_2xaem/v8a/smp (ARMv8-A SMP) - fvp_base_revc_2xaem/v8a/smp/ns (ARMv8-A SMP non-secure) The structure replaces the existing overly verbose board with a cleaner, more maintainable organization and provides a foundation for adding v9a variants. Signed-off-by: Nicolas Pitre --- .../Kconfig | 0 .../Kconfig.defconfig | 4 +- .../Kconfig.fvp_base_revc_2xaem} | 2 +- .../board.cmake | 0 boards/arm/fvp_base_revc_2xaem/board.yml | 10 +++++ .../doc/index.rst | 42 +++++++++++++++---- .../fvp_base_revc_2xaem_v8a.dts} | 4 +- .../fvp_base_revc_2xaem_v8a.yaml | 21 ++++++++++ .../fvp_base_revc_2xaem_v8a_defconfig} | 0 .../fvp_base_revc_2xaem_v8a_smp.dts | 6 +++ .../fvp_base_revc_2xaem_v8a_smp.yaml} | 12 +++++- .../fvp_base_revc_2xaem_v8a_smp_defconfig} | 0 .../fvp_base_revc_2xaem_v8a_smp_ns.dts} | 2 +- .../fvp_base_revc_2xaem_v8a_smp_ns.yaml} | 4 +- .../fvp_base_revc_2xaem_v8a_smp_ns_defconfig} | 0 boards/arm/fvp_base_revc_2xaemv8a/board.yml | 10 ----- .../fvp_base_revc_2xaemv8a.yaml | 16 ------- ...vc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts | 6 --- doc/releases/release-notes-4.3.rst | 10 +++++ samples/net/dhcpv4_client/README.rst | 2 +- .../arch/arm64/arm64_gicv3_its/testcase.yaml | 2 +- tests/arch/arm64/arm64_smc_call/testcase.yaml | 2 +- tests/kernel/mem_protect/syscalls/src/main.c | 2 +- tests/subsys/zbus/dyn_channel/testcase.yaml | 2 +- .../zbus/hlp_priority_boost/testcase.yaml | 2 +- tests/subsys/zbus/integration/testcase.yaml | 2 +- tests/subsys/zbus/unittests/testcase.yaml | 4 +- tests/subsys/zbus/user_data/testcase.yaml | 2 +- tests/ztest/error_hook/src/main.c | 2 +- 29 files changed, 110 insertions(+), 61 deletions(-) rename boards/arm/{fvp_base_revc_2xaemv8a => fvp_base_revc_2xaem}/Kconfig (100%) rename boards/arm/{fvp_base_revc_2xaemv8a => fvp_base_revc_2xaem}/Kconfig.defconfig (65%) rename boards/arm/{fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a => fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem} (76%) rename boards/arm/{fvp_base_revc_2xaemv8a => fvp_base_revc_2xaem}/board.cmake (100%) create mode 100644 boards/arm/fvp_base_revc_2xaem/board.yml rename boards/arm/{fvp_base_revc_2xaemv8a => fvp_base_revc_2xaem}/doc/index.rst (74%) rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.dts} (97%) create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.yaml rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_defconfig => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_defconfig} (100%) create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.dts rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml} (57%) rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_defconfig => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig} (100%) rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.dts => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.dts} (75%) rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns.yaml => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns.yaml} (70%) rename boards/arm/{fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_ns_defconfig => fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_ns_defconfig} (100%) delete mode 100644 boards/arm/fvp_base_revc_2xaemv8a/board.yml delete mode 100644 boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml delete mode 100644 boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts 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_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem similarity index 76% rename from boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a rename to boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem index 894a2c9992d55..306d8c739ac47 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/Kconfig.fvp_base_revc_2xaemv8a +++ b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem @@ -1,5 +1,5 @@ # Copyright (c) 2021 Carlo Caione # SPDX-License-Identifier: Apache-2.0 -config BOARD_FVP_BASE_REVC_2XAEMV8A +config BOARD_FVP_BASE_REVC_2XAEM select SOC_FVP_V8A diff --git a/boards/arm/fvp_base_revc_2xaemv8a/board.cmake b/boards/arm/fvp_base_revc_2xaem/board.cmake similarity index 100% rename from boards/arm/fvp_base_revc_2xaemv8a/board.cmake rename to boards/arm/fvp_base_revc_2xaem/board.cmake 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..4b4ae06122241 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/board.yml @@ -0,0 +1,10 @@ +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 diff --git a/boards/arm/fvp_base_revc_2xaemv8a/doc/index.rst b/boards/arm/fvp_base_revc_2xaem/doc/index.rst similarity index 74% rename from boards/arm/fvp_base_revc_2xaemv8a/doc/index.rst rename to boards/arm/fvp_base_revc_2xaem/doc/index.rst index 0954a2d90a130..ae56982affaae 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,16 @@ The following hardware features are supported: The kernel currently does not support other hardware features on this platform. +Board Variants +============== + +The following board targets are available: + +* ``fvp_base_revc_2xaem/v8a`` - ARMv8-A (64-bit) +* ``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) [Future] + Devices ======== @@ -77,12 +87,28 @@ 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 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 *********************** 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_v8a.dts similarity index 97% 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_v8a.dts index f75be1130b389..8ea975b829572 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a.dts @@ -10,12 +10,12 @@ #include / { - model = "FVP Base RevC 2xAEMv8A"; + model = "FVP Base RevC 2xAEM ARMv8-A"; 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; 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_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml similarity index 57% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml index 47e6399c9e003..c464a1eeac4bc 100644 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.yaml +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp.yaml @@ -1,8 +1,8 @@ # Copyright (c) 2025 BayLibre SAS # SPDX-License-Identifier: Apache-2.0 -identifier: fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a/smp -name: FVP Emulation FVP_Base_RevC-2xAEMvA (SMP) +identifier: fvp_base_revc_2xaem/v8a/smp +name: FVP Base RevC 2xAEM ARMv8-A (SMP) arch: arm64 type: sim simulation: @@ -14,3 +14,11 @@ toolchain: 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_fvp_base_revc_2xaemv8a_smp_defconfig b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig similarity index 100% rename from boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp_defconfig rename to boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v8a_smp_defconfig 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_2xaemv8a/board.yml b/boards/arm/fvp_base_revc_2xaemv8a/board.yml deleted file mode 100644 index e09e8ea0470da..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: v8a - variants: - - name: smp - variants: - - name: ns diff --git a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml deleted file mode 100644 index 02a956dc62889..0000000000000 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2021 Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -identifier: fvp_base_revc_2xaemv8a -name: FVP Emulation FVP_Base_RevC-2xAEMvA -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_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts b/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts deleted file mode 100644 index 76a89c4aa5090..0000000000000 --- a/boards/arm/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_fvp_base_revc_2xaemv8a_smp.dts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2025 BayLibre SAS - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "fvp_base_revc_2xaemv8a.dts" diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 7ce2df1414994..12f2648f574da 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -102,6 +102,16 @@ 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 + * Bluetooth * Audio 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/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_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/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 From 48cc850225dfaa3cabe43257952f45f1cc0e7a64 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 06/18] boards: Add backward compatibility for renamed FVP boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add deprecated.cmake mappings to redirect old board names to new unified structure: - 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 This ensures existing build commands and documentation continue to work with deprecation warnings while transitioning to the new board structure. Signed-off-by: Nicolas Pitre --- boards/arm/fvp_base_revc_2xaem/doc/index.rst | 11 +++++++++++ boards/deprecated.cmake | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/boards/arm/fvp_base_revc_2xaem/doc/index.rst b/boards/arm/fvp_base_revc_2xaem/doc/index.rst index ae56982affaae..33a25b04fb17b 100644 --- a/boards/arm/fvp_base_revc_2xaem/doc/index.rst +++ b/boards/arm/fvp_base_revc_2xaem/doc/index.rst @@ -132,6 +132,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/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 +) From 8cf980a191edd774bfae2f3be1e08c47ceb50f73 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 07/18] arch: arm64: Add ARMv9-A architecture and Cortex-A510 CPU support Add ARMv9-A architecture support with Cortex-A510 CPU as the default processor for generic ARMv9-A targets. Signed-off-by: Nicolas Pitre --- arch/arm64/core/Kconfig | 23 +++++++++++++++++++ cmake/compiler/iar/iccarm-cpu.cmake | 2 ++ cmake/gcc-m-cpu.cmake | 2 ++ dts/arm64/armv9-a.dtsi | 16 +++++++++++++ dts/bindings/cpu/arm,cortex-a510.yaml | 8 +++++++ soc/arm/fvp_aem/Kconfig | 5 ++++ soc/arm/fvp_aem/Kconfig.soc | 5 ++++ soc/arm/soc.yml | 1 + .../grp/os_mgmt/include/os_mgmt_processor.h | 2 ++ 9 files changed, 64 insertions(+) create mode 100644 dts/arm64/armv9-a.dtsi create mode 100644 dts/bindings/cpu/arm,cortex-a510.yaml diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index a2368adc81240..1f0cc6f317a9a 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -79,6 +79,16 @@ 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_R82 bool select CPU_AARCH64_CORTEX_R @@ -223,6 +233,19 @@ 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 + 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 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..21d985ceea76e 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -115,6 +115,8 @@ 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_R82) set(GCC_M_CPU cortex-r82) endif() 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-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/soc/arm/fvp_aem/Kconfig b/soc/arm/fvp_aem/Kconfig index eca0da629d54a..a95d2dd7c5c4b 100644 --- a/soc/arm/fvp_aem/Kconfig +++ b/soc/arm/fvp_aem/Kconfig @@ -10,3 +10,8 @@ config SOC_FVP_V8A bool select ARM64 select CPU_CORTEX_A53 + +config SOC_FVP_V9A + bool + select ARM64 + select CPU_CORTEX_A510 diff --git a/soc/arm/fvp_aem/Kconfig.soc b/soc/arm/fvp_aem/Kconfig.soc index 935476d9f8d7f..f701f121ca8b0 100644 --- a/soc/arm/fvp_aem/Kconfig.soc +++ b/soc/arm/fvp_aem/Kconfig.soc @@ -9,8 +9,13 @@ config SOC_FVP_V8A bool select SOC_SERIES_FVP_AEM +config SOC_FVP_V9A + bool + select SOC_SERIES_FVP_AEM + config SOC default "v8a" if SOC_FVP_V8A + default "v9a" if SOC_FVP_V9A config SOC_SERIES default "fvp_aem" if SOC_SERIES_FVP_AEM diff --git a/soc/arm/soc.yml b/soc/arm/soc.yml index d112dc12a8b8a..23647e6446e62 100644 --- a/soc/arm/soc.yml +++ b/soc/arm/soc.yml @@ -32,6 +32,7 @@ family: - name: fvp_aem socs: - name: v8a + - name: v9a - 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 From 99bd605d64a58fb3af07f8b903ac8b310754b25b Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 6 Oct 2025 11:23:17 -0400 Subject: [PATCH 08/18] modules: trusted-firmware-a: Disable AArch32 context for ARMv9-A ARMv9-A is AArch64-only and does not support AArch32 execution states at EL1/EL2/EL3. Configure TF-A build to disable AArch32 register context (CTX_INCLUDE_AARCH32_REGS=0) when building for ARMv9-A platforms. This fixes TF-A boot failures on ARMv9-A non-secure variants where TF-A would panic with: ERROR: EL1 supports AArch64-only. Please set build flag CTX_INCLUDE_AARCH32_REGS = 0 Signed-off-by: Nicolas Pitre --- modules/trusted-firmware-a/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) 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() From ab8033d40bf5d39757379f89e07e3b31f08092ea Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:46 -0400 Subject: [PATCH 09/18] boards: arm: Add unified FVP ARMv9-A board support 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) Signed-off-by: Nicolas Pitre --- .../Kconfig.fvp_base_revc_2xaem | 9 +- boards/arm/fvp_base_revc_2xaem/board.cmake | 18 ++ boards/arm/fvp_base_revc_2xaem/board.yml | 5 + boards/arm/fvp_base_revc_2xaem/doc/index.rst | 14 +- .../fvp_base_revc_2xaem.dtsi | 177 +++++++++++++++++ .../fvp_base_revc_2xaem_v8a.dts | 181 ++---------------- .../fvp_base_revc_2xaem_v9a.dts | 29 +++ .../fvp_base_revc_2xaem_v9a.yaml | 16 ++ .../fvp_base_revc_2xaem_v9a_defconfig | 20 ++ .../fvp_base_revc_2xaem_v9a_smp.dts | 6 + .../fvp_base_revc_2xaem_v9a_smp.yaml | 16 ++ .../fvp_base_revc_2xaem_v9a_smp_defconfig | 31 +++ .../fvp_base_revc_2xaem_v9a_smp_ns.dts | 6 + .../fvp_base_revc_2xaem_v9a_smp_ns.yaml | 16 ++ .../fvp_base_revc_2xaem_v9a_smp_ns_defconfig | 33 ++++ doc/releases/release-notes-4.3.rst | 6 + 16 files changed, 411 insertions(+), 172 deletions(-) create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.dts create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a.yaml create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_defconfig create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.dts create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp.yaml create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_defconfig create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.dts create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns.yaml create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_v9a_smp_ns_defconfig 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 index 306d8c739ac47..4f21c85fe8448 100644 --- a/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem +++ b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem @@ -2,4 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_FVP_BASE_REVC_2XAEM - select SOC_FVP_V8A + 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" diff --git a/boards/arm/fvp_base_revc_2xaem/board.cmake b/boards/arm/fvp_base_revc_2xaem/board.cmake index eaf8ec44ab112..653834e665249 100644 --- a/boards/arm/fvp_base_revc_2xaem/board.cmake +++ b/boards/arm/fvp_base_revc_2xaem/board.cmake @@ -32,6 +32,24 @@ set(ARMFVP_FLAGS -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() + if(CONFIG_BUILD_WITH_TFA) set(TFA_PLAT "fvp") diff --git a/boards/arm/fvp_base_revc_2xaem/board.yml b/boards/arm/fvp_base_revc_2xaem/board.yml index 4b4ae06122241..473aebf7b443f 100644 --- a/boards/arm/fvp_base_revc_2xaem/board.yml +++ b/boards/arm/fvp_base_revc_2xaem/board.yml @@ -8,3 +8,8 @@ board: - name: smp variants: - name: ns + - name: v9a + variants: + - name: smp + variants: + - name: ns diff --git a/boards/arm/fvp_base_revc_2xaem/doc/index.rst b/boards/arm/fvp_base_revc_2xaem/doc/index.rst index 33a25b04fb17b..47a58e67833b0 100644 --- a/boards/arm/fvp_base_revc_2xaem/doc/index.rst +++ b/boards/arm/fvp_base_revc_2xaem/doc/index.rst @@ -43,10 +43,12 @@ Board Variants The following board targets are available: -* ``fvp_base_revc_2xaem/v8a`` - ARMv8-A (64-bit) +* ``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) [Future] +* ``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 Devices ======== @@ -93,6 +95,14 @@ ARM FVP emulated environment, for example, with the :zephyr:code-sample:`synchro 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 SMP variants: .. zephyr-app-commands:: diff --git a/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi new file mode 100644 index 0000000000000..49eeecd175520 --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem.dtsi @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2021 Carlo Caione + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* + * The SRAM node is actually located in the + * DRAM region of the FVP Base RevC 2xAEM. + */ + zephyr,sram = &dram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + reg = <0>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + reg = <0x100>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + reg = <0x200>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + reg = <0x300>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + uartclk: apb-pclk { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + + soc { + interrupt-parent = <&gic>; + + gic: interrupt-controller@2f000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0x2f000000 0x10000>, // GICD + <0x2f100000 0x200000>; // GICR + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + its: msi-controller@2f020000 { + compatible = "arm,gic-v3-its"; + reg = <0x2f020000 0x20000>; + status = "okay"; + }; + }; + + 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>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_5"; + clocks = <&uartclk>; + }; + + uart1: uart@1c0a0000 { + compatible = "arm,pl011"; + reg = <0x1c0a0000 0x1000>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_6"; + clocks = <&uartclk>; + }; + + uart2: uart@1c0b0000 { + compatible = "arm,pl011"; + reg = <0x1c0b0000 0x1000>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_7"; + clocks = <&uartclk>; + }; + + uart3: uart@1c0c0000 { + compatible = "arm,pl011"; + reg = <0x1c0c0000 0x1000>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_8"; + clocks = <&uartclk>; + }; + + ethernet@1a000000 { + reg = <0x1a000000 0x1000>; + + eth: ethernet { + compatible = "smsc,lan91c111"; + interrupts = ; + status = "disabled"; + + phy-handle = <&phy>; + }; + + mdio: mdio { + compatible = "smsc,lan91c111-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + status = "disabled"; + reg = <0>; + }; + }; + }; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 DT_SIZE_K(64)>; + }; + + dram0: memory@88000000 { + compatible = "mmio-dram"; + reg = <0x88000000 DT_SIZE_K(2048)>; + }; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; +}; 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 index 8ea975b829572..265bd8e0142ed 100644 --- 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 @@ -5,182 +5,25 @@ /dts-v1/; -#include #include -#include +#include "fvp_base_revc_2xaem.dtsi" / { model = "FVP Base RevC 2xAEM ARMv8-A"; +}; - chosen { - /* - * The SRAM node is actually located in the - * DRAM region of the FVP Base RevC 2xAEM. - */ - zephyr,sram = &dram0; - zephyr,flash = &flash0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - }; - - psci { - compatible = "arm,psci-0.2"; - method = "smc"; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a53"; - reg = <0>; - }; - - cpu@100 { - device_type = "cpu"; - compatible = "arm,cortex-a53"; - reg = <0x100>; - }; - - cpu@200 { - device_type = "cpu"; - compatible = "arm,cortex-a53"; - reg = <0x200>; - }; - - cpu@300 { - device_type = "cpu"; - compatible = "arm,cortex-a53"; - reg = <0x300>; - }; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupt-parent = <&gic>; - interrupts = , - , - , - ; - }; - - uartclk: apb-pclk { - compatible = "fixed-clock"; - clock-frequency = <24000000>; - #clock-cells = <0>; - }; - - soc { - interrupt-parent = <&gic>; - - gic: interrupt-controller@2f000000 { - compatible = "arm,gic-v3", "arm,gic"; - reg = <0x2f000000 0x10000>, // GICD - <0x2f100000 0x200000>; // GICR - interrupt-controller; - #interrupt-cells = <4>; - status = "okay"; - #address-cells = <1>; - #size-cells = <1>; - - its: msi-controller@2f020000 { - compatible = "arm,gic-v3-its"; - reg = <0x2f020000 0x20000>; - status = "okay"; - }; - }; - - 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>; - status = "disabled"; - interrupts = ; - interrupt-names = "irq_5"; - clocks = <&uartclk>; - }; - - uart1: uart@1c0a0000 { - compatible = "arm,pl011"; - reg = <0x1c0a0000 0x1000>; - status = "disabled"; - interrupts = ; - interrupt-names = "irq_6"; - clocks = <&uartclk>; - }; - - uart2: uart@1c0b0000 { - compatible = "arm,pl011"; - reg = <0x1c0b0000 0x1000>; - status = "disabled"; - interrupts = ; - interrupt-names = "irq_7"; - clocks = <&uartclk>; - }; - - uart3: uart@1c0c0000 { - compatible = "arm,pl011"; - reg = <0x1c0c0000 0x1000>; - status = "disabled"; - interrupts = ; - interrupt-names = "irq_8"; - clocks = <&uartclk>; - }; - - ethernet@1a000000 { - reg = <0x1a000000 0x1000>; - - eth: ethernet { - compatible = "smsc,lan91c111"; - interrupts = ; - status = "disabled"; - - phy-handle = <&phy>; - }; - - mdio: mdio { - compatible = "smsc,lan91c111-mdio"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - - phy: ethernet-phy@0 { - compatible = "ethernet-phy"; - status = "disabled"; - reg = <0>; - }; - }; - }; +&cpu0 { + compatible = "arm,cortex-a53"; +}; - flash0: flash@0 { - compatible = "soc-nv-flash"; - reg = <0x0 DT_SIZE_K(64)>; - }; +&cpu1 { + compatible = "arm,cortex-a53"; +}; - dram0: memory@88000000 { - compatible = "mmio-dram"; - reg = <0x88000000 DT_SIZE_K(2048)>; - }; - }; +&cpu2 { + compatible = "arm,cortex-a53"; }; -&uart0 { - status = "okay"; - current-speed = <115200>; +&cpu3 { + compatible = "arm,cortex-a53"; }; 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/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 12f2648f574da..2ad8c176c4704 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -112,6 +112,12 @@ New APIs and options * 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) + * Bluetooth * Audio From e397c0ca93432ec131af928ae436d9d125c10d97 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:47 -0400 Subject: [PATCH 10/18] boards: arm: fvp: Add Cortex-A320 board variant support Add Cortex-A320 support to the unified FVP board structure with ARMv9.2-A specific configuration parameters. New board target: - fvp_base_revc_2xaem/a320 Signed-off-by: Nicolas Pitre --- arch/arm64/core/Kconfig | 10 +++ .../Kconfig.fvp_base_revc_2xaem | 1 + boards/arm/fvp_base_revc_2xaem/board.cmake | 81 +++++++++++++++++++ boards/arm/fvp_base_revc_2xaem/board.yml | 1 + boards/arm/fvp_base_revc_2xaem/doc/index.rst | 23 +++++- .../fvp_base_revc_2xaem_a320.dts | 29 +++++++ .../fvp_base_revc_2xaem_a320.yaml | 16 ++++ .../fvp_base_revc_2xaem_a320_defconfig | 20 +++++ cmake/gcc-m-cpu.cmake | 6 ++ doc/releases/release-notes-4.3.rst | 1 + dts/bindings/cpu/arm,cortex-a320.yaml | 8 ++ soc/arm/fvp_aem/Kconfig | 5 ++ soc/arm/fvp_aem/Kconfig.soc | 5 ++ soc/arm/soc.yml | 1 + 14 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.dts create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml create mode 100644 boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320_defconfig create mode 100644 dts/bindings/cpu/arm,cortex-a320.yaml diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index 1f0cc6f317a9a..c4bb6fb6a6806 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -89,6 +89,16 @@ config CPU_CORTEX_A510 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 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 index 4f21c85fe8448..49d3908e33959 100644 --- a/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem +++ b/boards/arm/fvp_base_revc_2xaem/Kconfig.fvp_base_revc_2xaem @@ -10,3 +10,4 @@ config BOARD_FVP_BASE_REVC_2XAEM 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 index 653834e665249..25612fb71099d 100644 --- a/boards/arm/fvp_base_revc_2xaem/board.cmake +++ b/boards/arm/fvp_base_revc_2xaem/board.cmake @@ -50,6 +50,87 @@ if(CONFIG_ARMV9_A) 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") diff --git a/boards/arm/fvp_base_revc_2xaem/board.yml b/boards/arm/fvp_base_revc_2xaem/board.yml index 473aebf7b443f..d0c8c71d5bf07 100644 --- a/boards/arm/fvp_base_revc_2xaem/board.yml +++ b/boards/arm/fvp_base_revc_2xaem/board.yml @@ -13,3 +13,4 @@ board: - name: smp variants: - name: ns + - name: a320 diff --git a/boards/arm/fvp_base_revc_2xaem/doc/index.rst b/boards/arm/fvp_base_revc_2xaem/doc/index.rst index 47a58e67833b0..c6e74bff8f380 100644 --- a/boards/arm/fvp_base_revc_2xaem/doc/index.rst +++ b/boards/arm/fvp_base_revc_2xaem/doc/index.rst @@ -41,7 +41,7 @@ The kernel currently does not support other hardware features on this platform. Board Variants ============== -The following board targets are available: +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) @@ -49,6 +49,19 @@ The following board targets are available: * ``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 ======== @@ -103,6 +116,14 @@ For ARMv9-A variants: :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:: 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_2xaem/fvp_base_revc_2xaem_a320.yaml b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml new file mode 100644 index 0000000000000..76b773904193e --- /dev/null +++ b/boards/arm/fvp_base_revc_2xaem/fvp_base_revc_2xaem_a320.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 BayLibre SAS +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_base_revc_2xaem/a320 +name: FVP Emulation FVP_Base_RevC-2xAEMv9A (Cortex-A320) +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_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/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index 21d985ceea76e..e495aeccd8cc1 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -117,6 +117,12 @@ elseif("${ARCH}" STREQUAL "arm64") 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 2ad8c176c4704..4b3f631a8b2c2 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -117,6 +117,7 @@ New APIs and options * 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 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/soc/arm/fvp_aem/Kconfig b/soc/arm/fvp_aem/Kconfig index a95d2dd7c5c4b..14e0c8317ad58 100644 --- a/soc/arm/fvp_aem/Kconfig +++ b/soc/arm/fvp_aem/Kconfig @@ -15,3 +15,8 @@ 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_aem/Kconfig.soc b/soc/arm/fvp_aem/Kconfig.soc index f701f121ca8b0..4f675398b4318 100644 --- a/soc/arm/fvp_aem/Kconfig.soc +++ b/soc/arm/fvp_aem/Kconfig.soc @@ -13,9 +13,14 @@ 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/soc.yml b/soc/arm/soc.yml index 23647e6446e62..8bea602a50370 100644 --- a/soc/arm/soc.yml +++ b/soc/arm/soc.yml @@ -33,6 +33,7 @@ family: socs: - name: v8a - name: v9a + - name: a320 - name: fvp_aemv8r socs: - name: fvp_aemv8r_aarch64 From 924b9f42df913c357c73d6cc3ff162402f11d5a0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2025 06:46:47 -0400 Subject: [PATCH 11/18] tests: arm64: Add comprehensive ARM architecture feature detection test Add comprehensive test to validate ARM64 architectural feature detection across ARMv8.1 through ARMv9-A implementations, providing runtime verification of processor capabilities and security features. Core architecture features tested: - Exception Level (EL) support detection (EL0-EL3) - SVE (Scalable Vector Extension) presence and capabilities - Advanced SIMD (NEON) and Floating Point implementation levels - Architecture version classification (ARMv8 vs ARMv9-A) ARMv8.1-A+ features: - LSE (Large System Extensions) atomic operations with level detection - Pointer Authentication (PAC) with comprehensive variant analysis: * API/APA (Address), GPI/GPA (Generic) authentication * Enhanced PAC levels (1, 3, 4, 5) with FPACCOMBINE detection * QARMA3 algorithm support (GPA3/APA3) ARMv8.5-A+ security and performance features: - Branch Target Identification (BTI) for control flow integrity - Memory Tagging Extensions (MTE) with level classification - Random Number Generation (RNDR) hardware entropy - Speculative Store Bypass Safe (SSBS) side-channel mitigation ARMv8.7-A+ advanced features: - WFxT (Wait with Timeout) enhanced synchronization - RPRES (Reciprocal Precision) optimized math operations ARMv8.8-A+ features: - MOPS (Memory Copy/Set) optimized memory operations - BC (Branch Consistency) advanced branch handling Signed-off-by: Nicolas Pitre --- include/zephyr/arch/arm64/cpu.h | 6 + include/zephyr/arch/arm64/lib_helpers.h | 9 + .../arm64/arm64_isa_features/CMakeLists.txt | 7 + tests/arch/arm64/arm64_isa_features/prj.conf | 2 + .../arch/arm64/arm64_isa_features/src/main.c | 229 ++++++++++++++++++ .../arm64/arm64_isa_features/testcase.yaml | 8 + 6 files changed, 261 insertions(+) create mode 100644 tests/arch/arm64/arm64_isa_features/CMakeLists.txt create mode 100644 tests/arch/arm64/arm64_isa_features/prj.conf create mode 100644 tests/arch/arm64/arm64_isa_features/src/main.c create mode 100644 tests/arch/arm64/arm64_isa_features/testcase.yaml diff --git a/include/zephyr/arch/arm64/cpu.h b/include/zephyr/arch/arm64/cpu.h index 076f2d9b0257e..12addcaa84d5a 100644 --- a/include/zephyr/arch/arm64/cpu.h +++ b/include/zephyr/arch/arm64/cpu.h @@ -113,6 +113,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) diff --git a/include/zephyr/arch/arm64/lib_helpers.h b/include/zephyr/arch/arm64/lib_helpers.h index e720808dbb09a..0b5930052bf38 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) @@ -199,6 +203,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/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..3db105eef54eb --- /dev/null +++ b/tests/arch/arm64/arm64_isa_features/src/main.c @@ -0,0 +1,229 @@ +/* + * 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"); + + /* 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 From 4837005f6f1cd54dbbaa7b102b2c17636c48afd4 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 3 Oct 2025 07:04:47 -0400 Subject: [PATCH 12/18] arch: arm64: Implement SVE context switching for ARMv9-A Implement Scalable Vector Extension (SVE) context switching support, enabling threads to use SVE instructions with lazy context preservation across task switches. The implementation is incremental: if only FPU instructions are used then only the NEON access is granted and preserved to minimize context switching overhead. If SVE is used then the NEON context is upgraded to SVE and then full SVE access is granted and preserved from that point onwards. Signed-off-by: Nicolas Pitre --- arch/arm64/core/Kconfig | 24 +++ arch/arm64/core/fatal.c | 2 +- arch/arm64/core/fpu.S | 183 +++++++++++++++++- arch/arm64/core/fpu.c | 135 +++++++++++-- arch/arm64/core/offsets/offsets.c | 15 ++ arch/arm64/core/reset.c | 48 ++++- arch/arm64/core/switch.S | 11 +- cmake/compiler/gcc/target_arm64.cmake | 10 + include/zephyr/arch/arm64/cpu.h | 15 +- include/zephyr/arch/arm64/lib_helpers.h | 1 + include/zephyr/arch/arm64/thread.h | 22 ++- .../arch/arm64/arm64_isa_features/src/main.c | 17 ++ 12 files changed, 446 insertions(+), 37 deletions(-) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index c4bb6fb6a6806..c8b7f286b86f6 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -249,6 +249,7 @@ config ARMV9_A 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. @@ -413,4 +414,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/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/include/zephyr/arch/arm64/cpu.h b/include/zephyr/arch/arm64/cpu.h index 12addcaa84d5a..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) @@ -138,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 0b5930052bf38..f73813ea81694 100644 --- a/include/zephyr/arch/arm64/lib_helpers.h +++ b/include/zephyr/arch/arm64/lib_helpers.h @@ -95,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 */ 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/tests/arch/arm64/arm64_isa_features/src/main.c b/tests/arch/arm64/arm64_isa_features/src/main.c index 3db105eef54eb..92ea0e63228d3 100644 --- a/tests/arch/arm64/arm64_isa_features/src/main.c +++ b/tests/arch/arm64/arm64_isa_features/src/main.c @@ -28,6 +28,23 @@ ZTEST(arm64_isa_features, test_arm64_feature_detection) 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)); From e726a5023559aea8b95ff9258bbef7526b24a85a Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 3 Oct 2025 07:04:47 -0400 Subject: [PATCH 13/18] tests: arm64: Add SVE context switching validation test Add test to validate SVE (Scalable Vector Extension) context switching implementation, ensuring proper register preservation across thread switches in multi-threaded environments. Signed-off-by: Nicolas Pitre --- tests/arch/arm64/arm64_sve_ctx/CMakeLists.txt | 7 + tests/arch/arm64/arm64_sve_ctx/prj.conf | 5 + tests/arch/arm64/arm64_sve_ctx/src/main.c | 322 ++++++++++++++++++ tests/arch/arm64/arm64_sve_ctx/testcase.yaml | 10 + 4 files changed, 344 insertions(+) create mode 100644 tests/arch/arm64/arm64_sve_ctx/CMakeLists.txt create mode 100644 tests/arch/arm64/arm64_sve_ctx/prj.conf create mode 100644 tests/arch/arm64/arm64_sve_ctx/src/main.c create mode 100644 tests/arch/arm64/arm64_sve_ctx/testcase.yaml 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..e73d555c0028e --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/prj.conf @@ -0,0 +1,5 @@ +CONFIG_ZTEST=y +CONFIG_FPU=y +CONFIG_FPU_SHARING=y +CONFIG_ARM64_SVE=y +CONFIG_ARM64_SVE_VL_MAX=256 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..3c9e452ce7330 --- /dev/null +++ b/tests/arch/arm64/arm64_sve_ctx/src/main.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2025 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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 1024 +#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; + +/* Test data for validation */ +static volatile bool thread1_sve_ok; +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) +{ + /* because of "static" this can be used by only one thread at a time */ + static 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 void *sve_ctx_setup(void) +{ + k_sem_init(&sync_sem, 0, 1); + k_sem_init(&done_sem, 0, 1); + return NULL; +} + +ZTEST(arm64_sve_ctx, test_sve_context_switching) +{ + /* Reset test results */ + thread1_sve_ok = false; + thread2_sve_ok = false; + + /* Create 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_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_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, "Thread 1 SVE context was corrupted"); + zassert_true(thread2_sve_ok, "Thread 2 SVE context was corrupted"); +} + +ZTEST_SUITE(arm64_sve_ctx, NULL, sve_ctx_setup, NULL, 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 From daff7ed6f4c4fd532a78de64dc41ec60ee7c47d6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 3 Oct 2025 07:04:47 -0400 Subject: [PATCH 14/18] tests: arm64: SVE: context switching test across different privileges Expand the SVE context switching test to cover all thread privilege combinations with validation of SVE state preservation across different contexts. Test Coverage: - Privileged vs Privileged threads (kernel mode) - User vs User threads (userspace with memory domains) - User vs Privileged threads (mixed privilege levels) Signed-off-by: Nicolas Pitre --- tests/arch/arm64/arm64_sve_ctx/prj.conf | 5 + tests/arch/arm64/arm64_sve_ctx/src/main.c | 122 +++++++++++++++++++--- 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/tests/arch/arm64/arm64_sve_ctx/prj.conf b/tests/arch/arm64/arm64_sve_ctx/prj.conf index e73d555c0028e..362628190122e 100644 --- a/tests/arch/arm64/arm64_sve_ctx/prj.conf +++ b/tests/arch/arm64/arm64_sve_ctx/prj.conf @@ -3,3 +3,8 @@ 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 index 3c9e452ce7330..151c064121def 100644 --- a/tests/arch/arm64/arm64_sve_ctx/src/main.c +++ b/tests/arch/arm64/arm64_sve_ctx/src/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include /* Helper function for SVE vector length */ @@ -47,7 +48,7 @@ ZTEST(arm64_sve_ctx, test_sve_basic_instructions) } } -#define STACK_SIZE 1024 +#define STACK_SIZE 4096 #define THREAD_PRIORITY 1 K_THREAD_STACK_DEFINE(thread1_stack, STACK_SIZE); @@ -60,9 +61,10 @@ static struct k_thread thread2_data; static struct k_sem sync_sem; static struct k_sem done_sem; -/* Test data for validation */ -static volatile bool thread1_sve_ok; -static volatile bool thread2_sve_ok; +/* 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) @@ -121,8 +123,8 @@ static inline void sve_set_predicate_pattern(uint32_t thread_id) /* Verify SVE Z register patterns */ static inline bool sve_verify_z_pattern(uint32_t thread_id) { - /* because of "static" this can be used by only one thread at a time */ - static uint32_t actual_buffer[8 * 256/4] __aligned(8); + /* 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); @@ -283,29 +285,121 @@ static void sve_test_thread2(void *arg1, void *arg2, void *arg3) /* * 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; } -ZTEST(arm64_sve_ctx, test_sve_context_switching) +static void sve_ctx_before(void *fixture) { - /* Reset test results */ + /* 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 threads that will use SVE */ + /* 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_thread1"); + 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_thread2"); + 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); @@ -315,8 +409,8 @@ ZTEST(arm64_sve_ctx, test_sve_context_switching) k_thread_join(&thread2_data, K_FOREVER); /* Verify both threads maintained their SVE context */ - zassert_true(thread1_sve_ok, "Thread 1 SVE context was corrupted"); - zassert_true(thread2_sve_ok, "Thread 2 SVE context was corrupted"); + 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, NULL, NULL, NULL); +ZTEST_SUITE(arm64_sve_ctx, NULL, sve_ctx_setup, sve_ctx_before, NULL, NULL); From e582fa95e31b0d7ec495ed9160e24bfaee8999b4 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 6 Oct 2025 00:15:19 -0400 Subject: [PATCH 15/18] cmake: fix style conformance that makes CI fail This fixes the following: CMakeStyle File:cmake/gcc-m-cpu.cmake Line:7 Column:Remove space before '(' in if() statements CMakeStyle File:cmake/gcc-m-cpu.cmake Line:22 Column:Remove space before '(' in if() statements CMakeStyle File:cmake/gcc-m-cpu.cmake Line:28 Column:Remove space before '(' in if() statements CMakeStyle File:cmake/gcc-m-cpu.cmake Line:38 Column:Remove space before '(' in if() statements CMakeStyle File:cmake/gcc-m-cpu.cmake Line:48 Column:Remove space before '(' in if() statements Signed-off-by: Nicolas Pitre --- cmake/gcc-m-cpu.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index e495aeccd8cc1..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) From 8afcbb70a25e9384b51c2fa264237d092e83df31 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 6 Oct 2025 18:05:32 -0400 Subject: [PATCH 16/18] arch: arm64: Increase stack sizes for userspace with FPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase ARM64 stack sizes to accommodate deeper call stacks in userspace and SMP configurations when FPU_SHARING is enabled: - PRIVILEGED_STACK_SIZE: 1024 → 4096 bytes (with FPU_SHARING) - TEST_EXTRA_STACK_SIZE: 2048 → 4096 bytes (with FPU_SHARING) The default 1KB privileged stack is insufficient for ARM64 userspace syscalls when FPU context switching is enabled. Symptom: Userspace tests crash with Data Abort (EC 0x24) near stack boundaries during syscalls, particularly on SMP configurations where multiple threads exercise FPU lazy switching. Fixes previously failing CI test on fvp_base_revc_2xaem SMP variants: - kernel.threads.dynamic - Multiple userspace tests with FPU_SHARING enabled Signed-off-by: Nicolas Pitre --- arch/arm64/core/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index c8b7f286b86f6..0b28d33d7052e 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -121,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 From 4b8f2e61058c62946d5b0438abb83d48d92347ef Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 7 Oct 2025 20:14:04 -0400 Subject: [PATCH 17/18] arch: arm64: Increase MAX_XLAT_TABLES for userspace tests Memory protection and userspace tests require more MMU translation tables than the default. Without this increase, tests fail with: E: CONFIG_MAX_XLAT_TABLES too small ASSERTION FAIL [ret == 0] @ arch/arm64/core/mmu.c:1244 privatize_page_range() returned -12 Increase defaults when both USERSPACE and TEST are enabled: - 32 tables for SMP configurations (matching qemu_cortex_a53 SMP) - 24 tables for non-SMP configurations (matching qemu_cortex_a53) This fixes: - sample.kernel.memory_protection.shared_mem (all platforms) - rtio.api.userspace (v8a, v9a) - rtio.api.userspace.submit_sem (v8a, v9a) Signed-off-by: Nicolas Pitre --- arch/arm64/core/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index 0b28d33d7052e..66f77e9f19fe7 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -387,6 +387,8 @@ config ARM64_PA_BITS config MAX_XLAT_TABLES int "Maximum numbers of translation tables" + default 32 if USERSPACE && TEST && SMP + default 24 if USERSPACE && TEST default 20 if USERSPACE && (ARM64_VA_BITS >= 40) default 16 if USERSPACE default 12 if (ARM64_VA_BITS >= 40) From 718306609a1b0ac706b9dc7cd18d16a18d16f82f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 7 Oct 2025 22:53:40 -0400 Subject: [PATCH 18/18] arch: arm64: Fix SMP TLB invalidation on SMP systems Use Inner Shareable (IS) TLB invalidation instructions in SMP configurations to broadcast TLB invalidations to all CPUs. Use TLBI VMALLE1IS instead of VMALLE1 in invalidate_tlb_all(). While at it, implement proper page-specific invalidation using TLBI VAE1IS in invalidate_tlb_page() instead of falling back to full invalidation. This fixes many SMP test failures with userspace enabled. Signed-off-by: Nicolas Pitre --- arch/arm64/core/mmu.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/arm64/core/mmu.c b/arch/arm64/core/mmu.c index a914916d605e7..9c8a4731d8e2f 100644 --- a/arch/arm64/core/mmu.c +++ b/arch/arm64/core/mmu.c @@ -778,15 +778,30 @@ static void remove_map(struct arm_mmu_ptables *ptables, const char *name, static void invalidate_tlb_all(void) { +#ifdef CONFIG_SMP + /* Use IS variant to broadcast to all CPUs in Inner Shareable domain */ + __asm__ volatile ( + "dsb ishst; tlbi vmalle1is; dsb ish; isb" + : : : "memory"); +#else __asm__ volatile ( "dsb ishst; tlbi vmalle1; dsb ish; isb" : : : "memory"); +#endif } static inline void invalidate_tlb_page(uintptr_t virt) { - /* to be refined */ - invalidate_tlb_all(); +#ifdef CONFIG_SMP + /* Use IS variant to broadcast to all CPUs in Inner Shareable domain */ + __asm__ volatile ( + "dsb ishst; tlbi vae1is, %0; dsb ish; isb" + : : "r" (virt >> PAGE_SIZE_SHIFT) : "memory"); +#else + __asm__ volatile ( + "dsb ishst; tlbi vae1, %0; dsb ish; isb" + : : "r" (virt >> PAGE_SIZE_SHIFT) : "memory"); +#endif } /* zephyr execution regions with appropriate attributes */