diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 8906da2f62725..b9e0574ba3694 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -195,6 +195,11 @@ target_link_libraries(kernel zephyr_interface) endif() +# Optionally build kernel sources without LTO +if(CONFIG_KERNEL_NO_LTO) + include(${CMAKE_CURRENT_LIST_DIR}/kernel_no_lto.cmake) +endif() + add_dependencies(kernel zephyr_generated_headers) unset(libkernel) diff --git a/kernel/Kconfig b/kernel/Kconfig index 9e3be0b12abe4..09b3233fbb295 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -1138,6 +1138,28 @@ endif # BOOTARGS endmenu +config KERNEL_NO_LTO + bool "Build selected kernel core files without LTO" + depends on LTO + help + Some SoCs require kernel code to be placed in RAM, which makes link-time + optimization (LTO) unsuitable for these files (-fno-lto). Disabling LTO + allows the affected code to be linked as separate objects and placed in + specific memory regions. + + Running kernel code from RAM can improve execution performance, especially + for timing-critical routines or context switch paths. + +if KERNEL_NO_LTO +config KERNEL_LTO_ALLOWLIST + string "List of kernel source files to keep LTO" + help + List of kernel source filenames that should retain LTO even when + CONFIG_KERNEL_NO_LTO is enabled. + Example: CONFIG_KERNEL_LTO_ALLOWLIST="init.c errno.c fatal.c" + +endif # KERNEL_NO_LTO + rsource "Kconfig.device" rsource "Kconfig.vm" rsource "Kconfig.init" diff --git a/kernel/kernel_no_lto.cmake b/kernel/kernel_no_lto.cmake new file mode 100644 index 0000000000000..6a0a7346203f9 --- /dev/null +++ b/kernel/kernel_no_lto.cmake @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Optional script to disable LTO for kernel files + +message(STATUS "[no-LTO] Building kernel files without LTO") + +# Retrieve all source files from the kernel library target +if(TARGET kernel) + get_property(KERNEL_SRCS TARGET kernel PROPERTY SOURCES) +else() + message(WARNING "[no-LTO] kernel target not found, skipping") + return() +endif() + +# Split allowlist string into list +if(DEFINED CONFIG_KERNEL_LTO_ALLOWLIST) + separate_arguments(LTO_ALLOWLIST NATIVE_COMMAND "${CONFIG_KERNEL_LTO_ALLOWLIST}") +endif() + +# Apply -fno-lto to all C source files, except for some initialization files +# (e.g. init.c, errno.c, fatal.c) and those that are less critical to be +# placed in RAM. These files can be excluded from -fno-lto by using +# CONFIG_KERNEL_LTO_ALLOWLIST. +foreach(src ${KERNEL_SRCS}) + if(src MATCHES "\\.c$") + + # Skip if filename matches any in allowlist + set(skip FALSE) + foreach(allow ${LTO_ALLOWLIST}) + get_filename_component(basename ${src} NAME) + if("${basename}" STREQUAL "${allow}") + set(skip TRUE) + break() + endif() + endforeach() + + if(NOT skip) + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS "-fno-lto -g") + endif() + + endif() +endforeach() diff --git a/soc/ite/ec/it8xxx2/Kconfig b/soc/ite/ec/it8xxx2/Kconfig index 5531371682b57..a520104126ff9 100644 --- a/soc/ite/ec/it8xxx2/Kconfig +++ b/soc/ite/ec/it8xxx2/Kconfig @@ -228,6 +228,7 @@ config SOC_IT8XXX2_KERNEL_IN_RAM bool "Place kernel handling code in RAM" select SOC_IT8XXX2_USE_ILM select SOC_IT8XXX2_LIBRARY_TO_RAM + select KERNEL_NO_LTO if LTO help Place kernel handling code in ILM. This can significantly improve performance.