From 6fd1691b9416838990422c0958f34661cdd5706c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 7 Nov 2018 23:40:43 +0100 Subject: [PATCH] kernel: Add a "nocache" read-write memory section Add a "nocache" read-write memory section that is configured to not be cached. This memory section can be used to perform DMA transfers when cache coherence issues are not optimal or can not be solved using cache maintenance operations. This is currently only supported on ARM Cortex M7 with MPU. Fixes #2927 Signed-off-by: Aurelien Jarno --- arch/Kconfig | 15 +++++++++++ arch/arm/core/Kconfig | 1 + arch/arm/core/cortex_m/mpu/arm_mpu.c | 25 ++++++++++++++++--- .../core/cortex_m/mpu/arm_mpu_v7_internal.h | 25 +++++++++++++++++-- .../arch/arm/cortex_m/mpu/arm_core_mpu_dev.h | 3 +++ include/arch/arm/cortex_m/scripts/linker.ld | 15 ++++++++++- include/linker/linker-defs.h | 13 ++++++++++ include/linker/section_tags.h | 4 +++ include/linker/sections.h | 3 +++ 9 files changed, 98 insertions(+), 6 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index cbe09680f7c..93f17b82859 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -202,6 +202,18 @@ config SIMPLE_FATAL_ERROR_HANDLER for footprint-concerned systems. Only enable this option if you do not want debug capabilities in case of system fatal error. +if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + +config NOCACHE_MEMORY + bool "Support for uncached memory" + help + Add a "nocache" read-write memory section that is configured to + not be cached. This memory section can be used to perform DMA + transfers when cache coherence issues are not optimal or can not + be solved using cache maintenance operations. + +endif # ARCH_HAS_NOCACHE_MEMORY_SUPPORT + menu "Interrupt Configuration" # # Interrupt related configs @@ -281,6 +293,9 @@ config ARCH_HAS_USERSPACE config ARCH_HAS_EXECUTABLE_PAGE_BIT bool +config ARCH_HAS_NOCACHE_MEMORY_SUPPORT + bool + # # Other architecture related options # diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 3f67329e61a..3f988744752 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -22,6 +22,7 @@ config CPU_CORTEX_M select ARCH_HAS_TRUSTED_EXECUTION if ARM_TRUSTZONE_M select ARCH_HAS_STACK_PROTECTION if ARM_MPU || CPU_CORTEX_M_HAS_SPLIM select ARCH_HAS_USERSPACE if ARM_MPU + select ARCH_HAS_NOCACHE_MEMORY_SUPPORT if ARM_MPU && CPU_HAS_ARM_MPU && CPU_CORTEX_M7 help This option signifies the use of a CPU of the Cortex-M family. diff --git a/arch/arm/core/cortex_m/mpu/arm_mpu.c b/arch/arm/core/cortex_m/mpu/arm_mpu.c index 1e36220e7ea..06cb82305a5 100644 --- a/arch/arm/core/cortex_m/mpu/arm_mpu.c +++ b/arch/arm/core/cortex_m/mpu/arm_mpu.c @@ -80,7 +80,7 @@ void arm_core_mpu_disable(void) } #if defined(CONFIG_USERSPACE) || defined(CONFIG_MPU_STACK_GUARD) || \ - defined(CONFIG_APPLICATION_MEMORY) + defined(CONFIG_APPLICATION_MEMORY) || defined(CONFIG_NOCACHE_MEMORY) /** * This internal function is utilized by the MPU driver to parse the intent @@ -93,6 +93,11 @@ static inline int _get_region_attr_by_type(arm_mpu_region_attr_t *p_attr, u32_t type, u32_t base, u32_t size) { switch (type) { +#ifdef CONFIG_NOCACHE_MEMORY + case NOCACHE_MEMORY_REGION: + _get_mpu_ram_nocache_region_attr(p_attr, P_RW_U_NA, base, size); + return 0; +#endif #ifdef CONFIG_USERSPACE case THREAD_STACK_REGION: _get_mpu_ram_region_attr(p_attr, P_RW_U_RW, base, size); @@ -313,7 +318,7 @@ int arm_core_mpu_buffer_validate(void *addr, size_t size, int write) return _mpu_buffer_validate(addr, size, write); } #endif /* CONFIG_USERSPACE */ -#endif /* USERSPACE || MPU_STACK_GUARD || APPLICATION_MEMORY */ +#endif /* USERSPACE || MPU_STACK_GUARD || APPLICATION_MEMORY || NOCACHE_MEMORY */ /* ARM MPU Driver Initial Setup */ @@ -354,10 +359,24 @@ static int arm_mpu_init(struct device *arg) _region_init(r_index, &mpu_config.mpu_regions[r_index]); } -#if defined(CONFIG_APPLICATION_MEMORY) +#if defined(CONFIG_NOCACHE_MEMORY) || defined(CONFIG_APPLICATION_MEMORY) u32_t index, size; struct arm_mpu_region region_conf; +#endif +#if defined(CONFIG_NOCACHE_MEMORY) + /* configure non-cached memory */ + index = _get_region_index_by_type(NOCACHE_MEMORY_REGION); + size = (u32_t)&_nocache_ram_end - (u32_t)&_nocache_ram_start; + _get_region_attr_by_type(®ion_conf.attr, NOCACHE_MEMORY_REGION, + (u32_t)&_nocache_ram_start, size); + region_conf.base = (u32_t)&_nocache_ram_start; + if (size > 0) { + _region_init(index, ®ion_conf); + } +#endif /* CONFIG_NOCACHE_MEMORY */ + +#if defined(CONFIG_APPLICATION_MEMORY) /* configure app data portion */ index = _get_region_index_by_type(THREAD_APP_DATA_REGION); size = (u32_t)&__app_ram_end - (u32_t)&__app_ram_start; diff --git a/arch/arm/core/cortex_m/mpu/arm_mpu_v7_internal.h b/arch/arm/core/cortex_m/mpu/arm_mpu_v7_internal.h index a237ad6a810..d92fb6d640f 100644 --- a/arch/arm/core/cortex_m/mpu/arm_mpu_v7_internal.h +++ b/arch/arm/core/cortex_m/mpu/arm_mpu_v7_internal.h @@ -36,7 +36,7 @@ static void _region_init(u32_t index, const struct arm_mpu_region *region_conf) } #if defined(CONFIG_USERSPACE) || defined(CONFIG_MPU_STACK_GUARD) || \ - defined(CONFIG_APPLICATION_MEMORY) + defined(CONFIG_APPLICATION_MEMORY) || defined(CONFIG_NOCACHE_MEMORY) static inline u8_t _get_num_regions(void); static inline u32_t _get_region_index_by_type(u32_t type); @@ -90,6 +90,8 @@ static inline u32_t _get_region_attr(u32_t xn, u32_t ap, u32_t tex, | (size)); } +#if defined(CONFIG_USERSPACE) || defined(CONFIG_MPU_STACK_GUARD) || \ + defined(CONFIG_APPLICATION_MEMORY) /** * This internal function allocates default RAM cache-ability, share-ability, * and execution allowance attributes along with the requested access @@ -105,6 +107,24 @@ static inline void _get_mpu_ram_region_attr(arm_mpu_region_attr_t *p_attr, p_attr->rasr = _get_region_attr(1, ap, 1, 1, 1, 0, 0, size); } +#endif /* USERSPACE || MPU_STACK_GUARD || APPLICATION_MEMORY */ + +#if defined(CONFIG_NOCACHE_MEMORY) +/** + * This internal function allocates non-cached, shareable, non-executable + * memory along with the requested access permissions ans size. + */ +static inline void _get_mpu_ram_nocache_region_attr(arm_mpu_region_attr_t *p_attr, + u32_t ap, u32_t base, u32_t size) +{ + /* in ARMv7-M MPU the base address is not required + * to determine region attributes. + */ + (void) base; + + p_attr->rasr = _get_region_attr(1, ap, 1, 0, 0, 1, 0, size); +} +#endif /* CONFIG_NO_CACHE_MEMORY */ /** * This internal function is utilized by the MPU driver to combine a given @@ -233,6 +253,7 @@ static inline int _mpu_buffer_validate(void *addr, size_t size, int write) } #endif /* CONFIG_USERSPACE */ -#endif /* USERSPACE || MPU_STACK_GUARD || APPLICATION_MEMORY */ +#endif /* USERSPACE || MPU_STACK_GUARD || APPLICATION_MEMORY + || NOCACHE_MEMORY */ #endif /* ZEPHYR_ARCH_ARM_CORE_CORTEX_M_MPU_ARM_MPU_V7_INTERNAL_H_ */ diff --git a/include/arch/arm/cortex_m/mpu/arm_core_mpu_dev.h b/include/arch/arm/cortex_m/mpu/arm_core_mpu_dev.h index 5f36b0fb1e2..a5f746a2e7b 100644 --- a/include/arch/arm/cortex_m/mpu/arm_core_mpu_dev.h +++ b/include/arch/arm/cortex_m/mpu/arm_core_mpu_dev.h @@ -32,6 +32,9 @@ extern "C" { * */ enum { +#ifdef CONFIG_NOCACHE_MEMORY + NOCACHE_MEMORY_REGION, +#endif #ifdef CONFIG_APPLICATION_MEMORY THREAD_APP_DATA_REGION, #endif diff --git a/include/arch/arm/cortex_m/scripts/linker.ld b/include/arch/arm/cortex_m/scripts/linker.ld index 6dc8d2224f6..6c3d23717c9 100644 --- a/include/arch/arm/cortex_m/scripts/linker.ld +++ b/include/arch/arm/cortex_m/scripts/linker.ld @@ -348,6 +348,20 @@ SECTIONS __app_ram_size = __app_ram_end - __app_ram_start; #endif /* CONFIG_APPLICATION_MEMORY */ +#if defined(CONFIG_NOCACHE_MEMORY) + /* Non-cached region of RAM */ + SECTION_PROLOGUE(_NOCACHE_SECTION_NAME,(NOLOAD),) + { + MPU_ALIGN(_nocache_ram_size); + _nocache_ram_start = .; + KERNEL_INPUT_SECTION(.nocache) + KERNEL_INPUT_SECTION(".nocache.*") + MPU_ALIGN(_nocache_ram_size); + _nocache_ram_end = .; + } GROUP_LINK_IN(RAMABLE_REGION) + _nocache_ram_size = _nocache_ram_end - _nocache_ram_start; +#endif /* CONFIG_NOCACHE_MEMORY */ + #if defined(CONFIG_APP_SHARED_MEM) #define APP_SHARED_ALIGN . = ALIGN(_region_min_align); #if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) @@ -371,7 +385,6 @@ SECTIONS _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); #endif /* CONFIG_APP_SHARED_MEM */ - SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) { /* diff --git a/include/linker/linker-defs.h b/include/linker/linker-defs.h index c915139e0c8..f7a96898bdf 100644 --- a/include/linker/linker-defs.h +++ b/include/linker/linker-defs.h @@ -270,6 +270,19 @@ extern char __sg_end[]; extern char __sg_size[]; #endif /* CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS */ +/* + * Non-cached kernel memory region, currently only available on ARM Cortex-M7 + * with a MPU. Start and end will be aligned for memory management/protection + * hardware for the target architecture. + * + * All the functions with '__nocache' keyword will be placed into this + * section. + */ +#ifdef CONFIG_NOCACHE_MEMORY +extern char _nocache_ram_start[]; +extern char _nocache_ram_end[]; +extern char _nocache_ram_size[]; +#endif /* CONFIG_NOCACHE_MEMORY */ #endif /* ! _ASMLANGUAGE */ diff --git a/include/linker/section_tags.h b/include/linker/section_tags.h index a132c64e35b..ddc7061e698 100644 --- a/include/linker/section_tags.h +++ b/include/linker/section_tags.h @@ -25,6 +25,10 @@ #define __ccm_noinit_section _GENERIC_SECTION(_CCM_NOINIT_SECTION_NAME) #endif /* CONFIG_ARM */ +#if defined(CONFIG_NOCACHE_MEMORY) +#define __nocache __in_section_unique(_NOCACHE_SECTION_NAME) +#endif /* CONFIG_NOCACHE_MEMORY */ + #endif /* !_ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_LINKER_SECTION_TAGS_H_ */ diff --git a/include/linker/sections.h b/include/linker/sections.h index 468999d899a..9a351ccc6ca 100644 --- a/include/linker/sections.h +++ b/include/linker/sections.h @@ -56,7 +56,10 @@ #define _CCM_DATA_SECTION_NAME .ccm_data #define _CCM_BSS_SECTION_NAME .ccm_bss #define _CCM_NOINIT_SECTION_NAME .ccm_noinit +#endif +#ifdef CONFIG_NOCACHE_MEMORY +#define _NOCACHE_SECTION_NAME nocache #endif #include