152 lines
4.6 KiB
C
152 lines
4.6 KiB
C
#ifndef ZEPHYR_INCLUDE_APP_MEMORY_APP_MEMDOMAIN_H_
|
|
#define ZEPHYR_INCLUDE_APP_MEMORY_APP_MEMDOMAIN_H_
|
|
|
|
#include <linker/linker-defs.h>
|
|
#include <misc/dlist.h>
|
|
#include <kernel.h>
|
|
|
|
#if defined(CONFIG_X86)
|
|
#define MEM_DOMAIN_ALIGN_SIZE _STACK_BASE_ALIGN
|
|
#elif defined(STACK_ALIGN)
|
|
#define MEM_DOMAIN_ALIGN_SIZE STACK_ALIGN
|
|
#else
|
|
#error "Not implemented for this architecture"
|
|
#endif
|
|
|
|
/*
|
|
* There has got to be a better way of doing this. This
|
|
* tries to ensure that a) each subsection has a
|
|
* data_smem_#id_b part and b) that each k_mem_partition
|
|
* matches the page size or MPU region. If there is no
|
|
* data_smem_#id_b subsection, then the size calculations
|
|
* will fail. Additionally, if each k_mem_partition does
|
|
* not match the page size or MPU region, then the
|
|
* partition will fail to be created.
|
|
* checkpatch.pl complains that __aligned(size) is
|
|
* preferred, but, if implemented, then complains about
|
|
* complex macro without parentheses.
|
|
*/
|
|
#define _app_dmem_pad(id) \
|
|
__attribute__((aligned(MEM_DOMAIN_ALIGN_SIZE), \
|
|
section("data_smem_" #id)))
|
|
|
|
#define _app_bmem_pad(id) \
|
|
__attribute__((aligned(MEM_DOMAIN_ALIGN_SIZE), \
|
|
section("data_smem_" #id "b")))
|
|
|
|
/*
|
|
* Qualifier to collect any object preceded with _app
|
|
* and place into section "data_smem_".
|
|
* _app_dmem(#) is for variables meant to be stored in .data .
|
|
* _app_bmem(#) is intended for static variables that are
|
|
* initialized to zero.
|
|
*/
|
|
#define _app_dmem(id) \
|
|
__attribute__((section("data_smem_" #id)))
|
|
|
|
#define _app_bmem(id) \
|
|
__attribute__((section("data_smem_" #id "b")))
|
|
|
|
/*
|
|
* Creation of a struct to save start addresses, sizes, and
|
|
* a pointer to a k_mem_partition. It also adds a linked
|
|
* list node.
|
|
*/
|
|
struct app_region {
|
|
char *dmem_start;
|
|
char *bmem_start;
|
|
#ifdef CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
|
|
char *smem_size;
|
|
#else
|
|
u32_t smem_size;
|
|
#endif /* CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
|
u32_t dmem_size;
|
|
u32_t bmem_size;
|
|
struct k_mem_partition *partition;
|
|
sys_dnode_t lnode;
|
|
};
|
|
|
|
/*
|
|
* Declares a partition and provides a function to add the
|
|
* partition to the linke dlist and initialize the partition.
|
|
*/
|
|
#ifdef CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
|
|
/* For power of 2 MPUs linker provides support to help us
|
|
* calculate the region sizes.
|
|
*/
|
|
#define smem_size_declare(name) extern char data_smem_##name##_size[]
|
|
#define smem_size_assign(name) name.smem_size = data_smem_##name##_size
|
|
#else
|
|
#define smem_size_declare(name)
|
|
#define smem_size_assign(name)
|
|
#endif /* CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
|
|
|
#define appmem_partition(name) \
|
|
extern char *data_smem_##name; \
|
|
extern char *data_smem_##name##b; \
|
|
smem_size_declare(name); \
|
|
_app_dmem_pad(name) char name##_dmem_pad; \
|
|
_app_bmem_pad(name) char name##_bmem_pad; \
|
|
__kernel struct k_mem_partition mem_domain_##name; \
|
|
__kernel struct app_region name; \
|
|
static inline void appmem_init_part_##name(void) \
|
|
{ \
|
|
name.dmem_start = (char *)&data_smem_##name; \
|
|
name.bmem_start = (char *)&data_smem_##name##b; \
|
|
smem_size_assign(name); \
|
|
sys_dlist_append(&app_mem_list, &name.lnode); \
|
|
mem_domain_##name.start = (u32_t) name.dmem_start; \
|
|
mem_domain_##name.attr = K_MEM_PARTITION_P_RW_U_RW; \
|
|
name.partition = &mem_domain_##name; \
|
|
}
|
|
|
|
/*
|
|
* A wrapper around the k_mem_domain_* functions. Goal here was
|
|
* to a) differentiate these operations from the k_mem_domain*
|
|
* functions, and b) to simply the usage and handling of data
|
|
* types (i.e. app_region, k_mem_domain, etc).
|
|
*/
|
|
#define appmem_domain(name) \
|
|
__kernel struct k_mem_domain domain_##name; \
|
|
static inline void appmem_add_thread_##name(k_tid_t thread) \
|
|
{ \
|
|
k_mem_domain_add_thread(&domain_##name, thread); \
|
|
} \
|
|
static inline void appmem_rm_thread_##name(k_tid_t thread) \
|
|
{ \
|
|
k_mem_domain_remove_thread(thread); \
|
|
} \
|
|
static inline void appmem_add_part_##name(struct app_region region) \
|
|
{ \
|
|
k_mem_domain_add_partition(&domain_##name, \
|
|
®ion.partition[0]); \
|
|
} \
|
|
static inline void appmem_rm_part_##name(struct app_region region) \
|
|
{ \
|
|
k_mem_domain_remove_partition(&domain_##name, \
|
|
®ion.partition[0]); \
|
|
} \
|
|
static inline void appmem_init_domain_##name(struct app_region region) \
|
|
{ \
|
|
k_mem_domain_init(&domain_##name, 1, ®ion.partition); \
|
|
}
|
|
|
|
/*
|
|
* The following allows the FOR_EACH macro to call each partition's
|
|
* appmem_init_part_##name . Note: semicolon needed or else compiler
|
|
* complains as semicolon needed for function call once expanded by
|
|
* macro.
|
|
*/
|
|
#define appmem_init_part(name) \
|
|
appmem_init_part_##name();
|
|
|
|
extern sys_dlist_t app_mem_list;
|
|
|
|
extern void app_bss_zero(void);
|
|
|
|
extern void app_calc_size(void);
|
|
|
|
extern void appmem_init_app_memory(void);
|
|
|
|
#endif /* ZEPHYR_INCLUDE_APP_MEMORY_APP_MEMDOMAIN_H_ */
|