Compare commits
4 Commits
v4.0.0-rc1
...
collab-ini
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ff30a149d | ||
|
|
db747c085f | ||
|
|
c55650c200 | ||
|
|
dac81a202f |
@@ -10,7 +10,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/linker/sections.h>
|
||||
#include <zephyr/sys/device_mmio.h>
|
||||
#include <zephyr/sys/iterable_sections.h>
|
||||
@@ -51,9 +50,7 @@ extern "C" {
|
||||
* than a pointer. The device.h API mainly uses handles to store lists of
|
||||
* multiple devices in a compact way.
|
||||
*
|
||||
* The extreme values and zero have special significance. Negative values
|
||||
* identify functionality that does not correspond to a Zephyr device, such as
|
||||
* the system clock or a SYS_INIT() function.
|
||||
* The negative, extreme values and zero have special significance.
|
||||
*
|
||||
* @see device_handle_get()
|
||||
* @see device_from_handle()
|
||||
@@ -323,25 +320,6 @@ typedef int16_t device_handle_t;
|
||||
#define DEVICE_DECLARE(dev_id) \
|
||||
static const struct device DEVICE_NAME_GET(dev_id)
|
||||
|
||||
/**
|
||||
* @brief Get a @ref init_entry reference from a devicetree node.
|
||||
*
|
||||
* @param node_id A devicetree node identifier
|
||||
*
|
||||
* @return A pointer to the @ref init_entry object created for that node
|
||||
*/
|
||||
#define DEVICE_INIT_DT_GET(node_id) \
|
||||
(&Z_INIT_ENTRY_NAME(DEVICE_DT_NAME_GET(node_id)))
|
||||
|
||||
/**
|
||||
* @brief Get a @ref init_entry reference from a device identifier.
|
||||
*
|
||||
* @param dev_id Device identifier.
|
||||
*
|
||||
* @return A pointer to the init_entry object created for that device
|
||||
*/
|
||||
#define DEVICE_INIT_GET(dev_id) (&Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)))
|
||||
|
||||
/**
|
||||
* @brief Runtime device dynamic structure (in RAM) per driver instance
|
||||
*
|
||||
@@ -388,6 +366,8 @@ struct device {
|
||||
struct device_state *state;
|
||||
/** Address of the device instance private data */
|
||||
void *data;
|
||||
/** Initialization function */
|
||||
int (*init)(const struct device *dev);
|
||||
#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* Optional pointer to dependencies associated with the device.
|
||||
@@ -848,17 +828,6 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
|
||||
#endif /* CONFIG_DEVICE_DEPS */
|
||||
|
||||
/**
|
||||
* @brief Init sub-priority of the device
|
||||
*
|
||||
* The sub-priority is defined by the devicetree ordinal, which ensures that
|
||||
* multiple drivers running at the same priority level run in an order that
|
||||
* respects the devicetree dependencies.
|
||||
*/
|
||||
#define Z_DEVICE_INIT_SUB_PRIO(node_id) \
|
||||
COND_CODE_1(DT_NODE_EXISTS(node_id), \
|
||||
(DT_DEP_ORD_STR_SORTABLE(node_id)), (0))
|
||||
|
||||
/**
|
||||
* @brief Maximum device name length.
|
||||
*
|
||||
@@ -880,6 +849,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
* @brief Initializer for @ref device.
|
||||
*
|
||||
* @param name_ Name of the device.
|
||||
* @param init_ Device init function.
|
||||
* @param pm_ Reference to @ref pm_device (optional).
|
||||
* @param data_ Reference to device data.
|
||||
* @param config_ Reference to device config.
|
||||
@@ -887,9 +857,10 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
* @param state_ Reference to device state.
|
||||
* @param deps_ Reference to device dependencies.
|
||||
*/
|
||||
#define Z_DEVICE_INIT(name_, pm_, data_, config_, api_, state_, deps_) \
|
||||
#define Z_DEVICE_INIT(name_, init_, pm_, data_, config_, api_, state_, deps_) \
|
||||
{ \
|
||||
.name = name_, \
|
||||
.init = init_, \
|
||||
.config = (config_), \
|
||||
.api = (api_), \
|
||||
.state = (state_), \
|
||||
@@ -904,8 +875,10 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
* @param level Initialization level
|
||||
* @param prio Initialization priority
|
||||
*/
|
||||
#define Z_DEVICE_SECTION_NAME(level, prio) \
|
||||
_CONCAT(INIT_LEVEL_ORD(level), _##prio)
|
||||
#define Z_DEVICE_SECTION_NAME(node_id, level, prio) \
|
||||
_CONCAT(level##_##prio##_, \
|
||||
COND_CODE_1(DT_NODE_EXISTS(node_id), \
|
||||
(DT_DEP_ORD_STR_SORTABLE(node_id)), (0)))
|
||||
|
||||
/**
|
||||
* @brief Define a @ref device
|
||||
@@ -914,6 +887,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
* software device).
|
||||
* @param dev_id Device identifier (used to name the defined @ref device).
|
||||
* @param name Name of the device.
|
||||
* @param init_fn Device init function.
|
||||
* @param pm Reference to @ref pm_device associated with the device.
|
||||
* (optional).
|
||||
* @param data Reference to device data.
|
||||
@@ -923,32 +897,13 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
* @param api Reference to device API.
|
||||
* @param ... Optional dependencies, manually specified.
|
||||
*/
|
||||
#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \
|
||||
prio, api, state, deps) \
|
||||
#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, pm, data, config, \
|
||||
level, prio, api, state, deps) \
|
||||
COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \
|
||||
const STRUCT_SECTION_ITERABLE_NAMED(device, \
|
||||
Z_DEVICE_SECTION_NAME(level, prio), \
|
||||
Z_DEVICE_SECTION_NAME(node_id, level, prio), \
|
||||
DEVICE_NAME_GET(dev_id)) = \
|
||||
Z_DEVICE_INIT(name, pm, data, config, api, state, deps)
|
||||
|
||||
/**
|
||||
* @brief Define the init entry for a device.
|
||||
*
|
||||
* @param node_id Devicetree node id for the device (DT_INVALID_NODE if a
|
||||
* software device).
|
||||
* @param dev_id Device identifier.
|
||||
* @param init_fn_ Device init function.
|
||||
* @param level Initialization level.
|
||||
* @param prio Initialization priority.
|
||||
*/
|
||||
#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \
|
||||
static const Z_DECL_ALIGN(struct init_entry) __used __noasan \
|
||||
Z_INIT_ENTRY_SECTION(level, prio, \
|
||||
Z_DEVICE_INIT_SUB_PRIO(node_id)) \
|
||||
Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \
|
||||
.init_fn = {.dev = (init_fn_)}, \
|
||||
.dev = &DEVICE_NAME_GET(dev_id), \
|
||||
}
|
||||
Z_DEVICE_INIT(name, init_fn, pm, data, config, api, state, deps)
|
||||
|
||||
/**
|
||||
* @brief Define a @ref device and all other required objects.
|
||||
@@ -978,10 +933,9 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
|
||||
IF_ENABLED(CONFIG_DEVICE_DEPS, \
|
||||
(Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__);)) \
|
||||
\
|
||||
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \
|
||||
prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \
|
||||
\
|
||||
Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio)
|
||||
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, pm, data, config, \
|
||||
level, prio, api, state, \
|
||||
Z_DEVICE_DEPS_NAME(dev_id))
|
||||
|
||||
#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
|
||||
@@ -42,81 +42,14 @@ extern "C" {
|
||||
* SMP.
|
||||
*
|
||||
* Initialization priority can take a value in the range of 0 to 99.
|
||||
*
|
||||
* @note The same infrastructure is used by devices.
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct device;
|
||||
|
||||
/**
|
||||
* @brief Initialization function for init entries.
|
||||
*
|
||||
* Init entries support both the system initialization and the device
|
||||
* APIs. Each API has its own init function signature; hence, we have a
|
||||
* union to cover both.
|
||||
*/
|
||||
union init_function {
|
||||
/**
|
||||
* System initialization function.
|
||||
*
|
||||
* @retval 0 On success
|
||||
* @retval -errno If init fails.
|
||||
*/
|
||||
int (*sys)(void);
|
||||
/**
|
||||
* Device initialization function.
|
||||
*
|
||||
* @param dev Device instance.
|
||||
*
|
||||
* @retval 0 On success
|
||||
* @retval -errno If device initialization fails.
|
||||
*/
|
||||
int (*dev)(const struct device *dev);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure to store initialization entry information.
|
||||
*
|
||||
* @internal
|
||||
* Init entries need to be defined following these rules:
|
||||
*
|
||||
* - Their name must be set using Z_INIT_ENTRY_NAME().
|
||||
* - They must be placed in a special init section, given by
|
||||
* Z_INIT_ENTRY_SECTION().
|
||||
* - They must be aligned, e.g. using Z_DECL_ALIGN().
|
||||
*
|
||||
* See SYS_INIT_NAMED() for an example.
|
||||
* @endinternal
|
||||
*/
|
||||
struct init_entry {
|
||||
/** Initialization function. */
|
||||
union init_function init_fn;
|
||||
/**
|
||||
* If the init entry belongs to a device, this fields stores a
|
||||
* reference to it, otherwise it is set to NULL.
|
||||
*/
|
||||
const struct device *dev;
|
||||
};
|
||||
/** System initialization function. */
|
||||
typedef int (*sys_init_fn_t)(void);
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
|
||||
/* Helper definitions to evaluate level equality */
|
||||
#define Z_INIT_EARLY_EARLY 1
|
||||
#define Z_INIT_PRE_KERNEL_1_PRE_KERNEL_1 1
|
||||
#define Z_INIT_PRE_KERNEL_2_PRE_KERNEL_2 1
|
||||
#define Z_INIT_POST_KERNEL_POST_KERNEL 1
|
||||
#define Z_INIT_APPLICATION_APPLICATION 1
|
||||
#define Z_INIT_SMP_SMP 1
|
||||
|
||||
/* Init level ordinals */
|
||||
#define Z_INIT_ORD_EARLY 0
|
||||
#define Z_INIT_ORD_PRE_KERNEL_1 1
|
||||
#define Z_INIT_ORD_PRE_KERNEL_2 2
|
||||
#define Z_INIT_ORD_POST_KERNEL 3
|
||||
#define Z_INIT_ORD_APPLICATION 4
|
||||
#define Z_INIT_ORD_SMP 5
|
||||
|
||||
/**
|
||||
* @brief Obtain init entry name.
|
||||
*
|
||||
@@ -131,29 +64,12 @@ struct init_entry {
|
||||
* linker scripts to sort them according to the specified
|
||||
* level/priority/sub-priority.
|
||||
*/
|
||||
#define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \
|
||||
__attribute__((__section__( \
|
||||
".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_")))
|
||||
#define Z_INIT_ENTRY_SECTION(level, prio) \
|
||||
__attribute__( \
|
||||
(__section__(".z_init_" #level STRINGIFY(prio)"_")))
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Obtain the ordinal for an init level.
|
||||
*
|
||||
* @param level Init level (EARLY, PRE_KERNEL_1, PRE_KERNEL_2, POST_KERNEL,
|
||||
* APPLICATION, SMP).
|
||||
*
|
||||
* @return Init level ordinal.
|
||||
*/
|
||||
#define INIT_LEVEL_ORD(level) \
|
||||
COND_CODE_1(Z_INIT_EARLY_##level, (Z_INIT_ORD_EARLY), \
|
||||
(COND_CODE_1(Z_INIT_PRE_KERNEL_1_##level, (Z_INIT_ORD_PRE_KERNEL_1), \
|
||||
(COND_CODE_1(Z_INIT_PRE_KERNEL_2_##level, (Z_INIT_ORD_PRE_KERNEL_2), \
|
||||
(COND_CODE_1(Z_INIT_POST_KERNEL_##level, (Z_INIT_ORD_POST_KERNEL), \
|
||||
(COND_CODE_1(Z_INIT_APPLICATION_##level, (Z_INIT_ORD_APPLICATION), \
|
||||
(COND_CODE_1(Z_INIT_SMP_##level, (Z_INIT_ORD_SMP), \
|
||||
(ZERO_OR_COMPILE_ERROR(0)))))))))))))
|
||||
|
||||
/**
|
||||
* @brief Register an initialization function.
|
||||
*
|
||||
@@ -180,19 +96,16 @@ struct init_entry {
|
||||
* same init function.
|
||||
*
|
||||
* @param name Unique name for SYS_INIT entry.
|
||||
* @param init_fn_ See SYS_INIT().
|
||||
* @param init_fn See SYS_INIT().
|
||||
* @param level See SYS_INIT().
|
||||
* @param prio See SYS_INIT().
|
||||
*
|
||||
* @see SYS_INIT()
|
||||
*/
|
||||
#define SYS_INIT_NAMED(name, init_fn_, level, prio) \
|
||||
static const Z_DECL_ALIGN(struct init_entry) \
|
||||
Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \
|
||||
Z_INIT_ENTRY_NAME(name) = { \
|
||||
.init_fn = {.sys = (init_fn_)}, \
|
||||
.dev = NULL, \
|
||||
}
|
||||
#define SYS_INIT_NAMED(name, init_fn, level, prio) \
|
||||
static const Z_DECL_ALIGN(sys_init_fn_t) \
|
||||
Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \
|
||||
Z_INIT_ENTRY_NAME(name) = init_fn
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -20,7 +20,30 @@
|
||||
__init_end = .;
|
||||
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
|
||||
ITERABLE_SECTION_ROM_NUMERIC(device, 4)
|
||||
/* HACK: needs a new iterable "sub-section" API */
|
||||
SECTION_PROLOGUE(device_area,,)
|
||||
{
|
||||
_device_list_start = .;
|
||||
_device_list_EARLY_start = .;
|
||||
KEEP(*(SORT(._device.static.EARLY_?_*)));
|
||||
KEEP(*(SORT(._device.static.EARLY_??_*)));
|
||||
_device_list_PRE_KERNEL_1_start = .;
|
||||
KEEP(*(SORT(._device.static.PRE_KERNEL_1_?_*)));
|
||||
KEEP(*(SORT(._device.static.PRE_KERNEL_1_??_*)));
|
||||
_device_list_PRE_KERNEL_2_start = .;
|
||||
KEEP(*(SORT(._device.static.PRE_KERNEL_2_?_*)));
|
||||
KEEP(*(SORT(._device.static.PRE_KERNEL_2_??_*)));
|
||||
_device_list_POST_KERNEL_start = .;
|
||||
KEEP(*(SORT(._device.static.POST_KERNEL_?_*)));
|
||||
KEEP(*(SORT(._device.static.POST_KERNEL_??_*)));
|
||||
_device_list_APPLICATION_start = .;
|
||||
KEEP(*(SORT(._device.static.APPLICATION_?_*)));
|
||||
KEEP(*(SORT(._device.static.APPLICATION_??_*)));
|
||||
_device_list_SMP_start = .;
|
||||
KEEP(*(SORT(._device.static.SMP_?_*)));
|
||||
KEEP(*(SORT(._device.static.SMP_??_*)));
|
||||
_device_list_end = .;
|
||||
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
|
||||
#if defined(CONFIG_GEN_SW_ISR_TABLE) && !defined(CONFIG_DYNAMIC_INTERRUPTS)
|
||||
SECTION_PROLOGUE(sw_isr_table,,)
|
||||
|
||||
107
kernel/init.c
107
kernel/init.c
@@ -61,13 +61,21 @@ static K_KERNEL_PINNED_STACK_ARRAY_DEFINE(z_idle_stacks,
|
||||
CONFIG_IDLE_STACK_SIZE);
|
||||
#endif /* CONFIG_MULTITHREADING */
|
||||
|
||||
extern const struct init_entry __init_start[];
|
||||
extern const struct init_entry __init_EARLY_start[];
|
||||
extern const struct init_entry __init_PRE_KERNEL_1_start[];
|
||||
extern const struct init_entry __init_PRE_KERNEL_2_start[];
|
||||
extern const struct init_entry __init_POST_KERNEL_start[];
|
||||
extern const struct init_entry __init_APPLICATION_start[];
|
||||
extern const struct init_entry __init_end[];
|
||||
extern const sys_init_fn_t __init_start[];
|
||||
extern const sys_init_fn_t __init_EARLY_start[];
|
||||
extern const sys_init_fn_t __init_PRE_KERNEL_1_start[];
|
||||
extern const sys_init_fn_t __init_PRE_KERNEL_2_start[];
|
||||
extern const sys_init_fn_t __init_POST_KERNEL_start[];
|
||||
extern const sys_init_fn_t __init_APPLICATION_start[];
|
||||
extern const sys_init_fn_t __init_end[];
|
||||
|
||||
extern const struct device _device_list_EARLY_start[];
|
||||
extern const struct device _device_list_PRE_KERNEL_1_start[];
|
||||
extern const struct device _device_list_PRE_KERNEL_2_start[];
|
||||
extern const struct device _device_list_POST_KERNEL_start[];
|
||||
extern const struct device _device_list_APPLICATION_start[];
|
||||
/* FIXME: iterable sections used in device.h do not use const? */
|
||||
extern struct device _device_list_end[];
|
||||
|
||||
enum init_level {
|
||||
INIT_LEVEL_EARLY = 0,
|
||||
@@ -81,7 +89,9 @@ enum init_level {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern const struct init_entry __init_SMP_start[];
|
||||
extern const sys_init_fn_t __init_SMP_start[];
|
||||
|
||||
extern const struct device _device_list_SMP_start[];
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -230,19 +240,33 @@ __pinned_bss
|
||||
bool z_sys_post_kernel;
|
||||
|
||||
/**
|
||||
* @brief Execute all the init entry initialization functions at a given level
|
||||
* @brief Execute all devices and init entry initialization functions at a given
|
||||
* level
|
||||
*
|
||||
* @details Invokes the initialization routine for each init entry object
|
||||
* created by the INIT_ENTRY_DEFINE() macro using the specified level.
|
||||
* The linker script places the init entry objects in memory in the order
|
||||
* they need to be invoked, with symbols indicating where one level leaves
|
||||
* off and the next one begins.
|
||||
* @details Invokes the initialization routine for each device and init entry
|
||||
* object created by the SYS_INIT() macro using the specified level. Devices are
|
||||
* initialized first, then init entry objects. The linker script places the init
|
||||
* entry objects in memory in the order they need to be invoked, with symbols
|
||||
* indicating where one level leaves off and the next one begins.
|
||||
*
|
||||
* @param level init level to run.
|
||||
*/
|
||||
static void z_sys_init_run_level(enum init_level level)
|
||||
{
|
||||
static const struct init_entry *levels[] = {
|
||||
static const struct device *dev_levels[] = {
|
||||
_device_list_EARLY_start,
|
||||
_device_list_PRE_KERNEL_1_start,
|
||||
_device_list_PRE_KERNEL_2_start,
|
||||
_device_list_POST_KERNEL_start,
|
||||
_device_list_APPLICATION_start,
|
||||
#ifdef CONFIG_SMP
|
||||
_device_list_SMP_start,
|
||||
#endif
|
||||
/* End marker */
|
||||
_device_list_end,
|
||||
};
|
||||
|
||||
static const sys_init_fn_t *levels[] = {
|
||||
__init_EARLY_start,
|
||||
__init_PRE_KERNEL_1_start,
|
||||
__init_PRE_KERNEL_2_start,
|
||||
@@ -254,39 +278,36 @@ static void z_sys_init_run_level(enum init_level level)
|
||||
/* End marker */
|
||||
__init_end,
|
||||
};
|
||||
const struct init_entry *entry;
|
||||
|
||||
for (entry = levels[level]; entry < levels[level+1]; entry++) {
|
||||
const struct device *dev = entry->dev;
|
||||
for (const struct device *dev = dev_levels[level]; dev < dev_levels[level+1]; dev++) {
|
||||
int rc = 0;
|
||||
|
||||
if (dev != NULL) {
|
||||
int rc = 0;
|
||||
|
||||
if (entry->init_fn.dev != NULL) {
|
||||
rc = entry->init_fn.dev(dev);
|
||||
/* Mark device initialized. If initialization
|
||||
* failed, record the error condition.
|
||||
*/
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
rc = -rc;
|
||||
}
|
||||
if (rc > UINT8_MAX) {
|
||||
rc = UINT8_MAX;
|
||||
}
|
||||
dev->state->init_res = rc;
|
||||
if (dev->init != NULL) {
|
||||
rc = dev->init(dev);
|
||||
/* Mark device initialized. If initialization failed,
|
||||
* record the error condition.
|
||||
*/
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
rc = -rc;
|
||||
}
|
||||
if (rc > UINT8_MAX) {
|
||||
rc = UINT8_MAX;
|
||||
}
|
||||
dev->state->init_res = rc;
|
||||
}
|
||||
|
||||
dev->state->initialized = true;
|
||||
|
||||
if (rc == 0) {
|
||||
/* Run automatic device runtime enablement */
|
||||
(void)pm_device_runtime_auto_enable(dev);
|
||||
}
|
||||
} else {
|
||||
(void)entry->init_fn.sys();
|
||||
}
|
||||
|
||||
dev->state->initialized = true;
|
||||
|
||||
if (rc == 0) {
|
||||
/* Run automatic device runtime enablement */
|
||||
(void)pm_device_runtime_auto_enable(dev);
|
||||
}
|
||||
}
|
||||
|
||||
for (const sys_init_fn_t *entry = levels[level]; entry < levels[level+1]; entry++) {
|
||||
(void)(*entry)();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,8 +105,14 @@ class ZephyrInitLevels:
|
||||
def __init__(self, file_path):
|
||||
self.file_path = file_path
|
||||
self._elf = ELFFile(open(file_path, "rb"))
|
||||
|
||||
self.initlevels = {}
|
||||
for level in _DEVICE_INIT_LEVELS:
|
||||
self.initlevels[level] = []
|
||||
|
||||
self._load_objects()
|
||||
self._load_level_addr()
|
||||
self._process_devices()
|
||||
self._process_initlevels()
|
||||
|
||||
def _load_objects(self):
|
||||
@@ -124,27 +130,37 @@ class ZephyrInitLevels:
|
||||
self._objects[sym.entry.st_value] = (
|
||||
sym.name, sym.entry.st_size, sym.entry.st_shndx)
|
||||
|
||||
def _load_level_addr(self):
|
||||
def _find_level_addr(self, prefix, levels):
|
||||
"""Find the address associated with known init levels."""
|
||||
self._init_level_addr = {}
|
||||
addrs = {}
|
||||
end = None
|
||||
|
||||
for section in self._elf.iter_sections():
|
||||
if not isinstance(section, SymbolTableSection):
|
||||
continue
|
||||
|
||||
for sym in section.iter_symbols():
|
||||
for level in _DEVICE_INIT_LEVELS:
|
||||
name = f"__init_{level}_start"
|
||||
for level in levels:
|
||||
name = f"{prefix}_{level}_start"
|
||||
if sym.name == name:
|
||||
self._init_level_addr[level] = sym.entry.st_value
|
||||
elif sym.name == "__init_end":
|
||||
self._init_level_end = sym.entry.st_value
|
||||
addrs[level] = sym.entry.st_value
|
||||
elif sym.name == f"{prefix}_end":
|
||||
end = sym.entry.st_value
|
||||
|
||||
if len(self._init_level_addr) != len(_DEVICE_INIT_LEVELS):
|
||||
raise ValueError(f"Missing init symbols, found: {self._init_level_addr}")
|
||||
if len(addrs) != len(levels):
|
||||
raise ValueError(f"Missing level symbols, found: {addrs}")
|
||||
|
||||
if not self._init_level_end:
|
||||
raise ValueError(f"Missing init section end symbol")
|
||||
if not end:
|
||||
raise ValueError(f"Missing level section end symbol")
|
||||
|
||||
return addrs, end
|
||||
|
||||
def _load_level_addr(self):
|
||||
"""Load the address level for both init and device sections."""
|
||||
self._init_level_addr, self._init_level_end = self._find_level_addr(
|
||||
"__init", _DEVICE_INIT_LEVELS)
|
||||
self._device_level_addr, self._device_level_end = self._find_level_addr(
|
||||
"_device_list", _DEVICE_INIT_LEVELS)
|
||||
|
||||
def _device_ord_from_name(self, sym_name):
|
||||
"""Find a device ordinal from a symbol name."""
|
||||
@@ -185,19 +201,16 @@ class ZephyrInitLevels:
|
||||
|
||||
return int.from_bytes(data[start:stop], byteorder="little")
|
||||
|
||||
def _process_initlevels(self):
|
||||
"""Process the init level and find the init functions and devices."""
|
||||
def _process_devices(self):
|
||||
"""Process the init level and find the devices."""
|
||||
self.devices = {}
|
||||
self.initlevels = {}
|
||||
|
||||
for i, level in enumerate(_DEVICE_INIT_LEVELS):
|
||||
start = self._init_level_addr[level]
|
||||
start = self._device_level_addr[level]
|
||||
if i + 1 == len(_DEVICE_INIT_LEVELS):
|
||||
stop = self._init_level_end
|
||||
stop = self._device_level_end
|
||||
else:
|
||||
stop = self._init_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
|
||||
|
||||
self.initlevels[level] = []
|
||||
stop = self._device_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
|
||||
|
||||
priority = 0
|
||||
addr = start
|
||||
@@ -206,12 +219,11 @@ class ZephyrInitLevels:
|
||||
raise ValueError(f"no symbol at addr {addr:08x}")
|
||||
obj, size, shidx = self._objects[addr]
|
||||
|
||||
arg0_name = self._object_name(self._initlevel_pointer(addr, 0, shidx))
|
||||
arg1_name = self._object_name(self._initlevel_pointer(addr, 1, shidx))
|
||||
init_name = self._object_name(self._initlevel_pointer(addr, 5, shidx))
|
||||
|
||||
self.initlevels[level].append(f"{obj}: {arg0_name}({arg1_name})")
|
||||
self.initlevels[level].append(f"DEVICE {init_name}({obj})")
|
||||
|
||||
ordinal = self._device_ord_from_name(arg1_name)
|
||||
ordinal = self._device_ord_from_name(obj)
|
||||
if ordinal:
|
||||
prio = Priority(level, priority)
|
||||
self.devices[ordinal] = prio
|
||||
@@ -219,6 +231,27 @@ class ZephyrInitLevels:
|
||||
addr += size
|
||||
priority += 1
|
||||
|
||||
def _process_initlevels(self):
|
||||
"""Process the init level and find the init functions."""
|
||||
for i, level in enumerate(_DEVICE_INIT_LEVELS):
|
||||
start = self._init_level_addr[level]
|
||||
if i + 1 == len(_DEVICE_INIT_LEVELS):
|
||||
stop = self._init_level_end
|
||||
else:
|
||||
stop = self._init_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
|
||||
|
||||
addr = start
|
||||
while addr < stop:
|
||||
if addr not in self._objects:
|
||||
raise ValueError(f"no symbol at addr {addr:08x}")
|
||||
_, size, shidx = self._objects[addr]
|
||||
|
||||
init_name = self._object_name(self._initlevel_pointer(addr, 0, shidx))
|
||||
|
||||
self.initlevels[level].append(f"SYS_INIT {init_name}()")
|
||||
|
||||
addr += size
|
||||
|
||||
class Validator():
|
||||
"""Validates the initialization priorities.
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ class testZephyrInitLevels(unittest.TestCase):
|
||||
self.assertDictEqual(obj._objects, {0xaa: ("a", 4, 1), 0xbb: ("b", 8, 2)})
|
||||
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
|
||||
def test_load_level_addr(self, mock_zilinit):
|
||||
def test_find_level_addr(self, mock_zilinit):
|
||||
mock_elf = mock.Mock()
|
||||
|
||||
sts = mock.Mock(spec=SymbolTableSection)
|
||||
@@ -97,40 +97,40 @@ class testZephyrInitLevels(unittest.TestCase):
|
||||
mock_elf.iter_sections.return_value = [sts, rel]
|
||||
|
||||
s0 = mock.Mock()
|
||||
s0.name = "__init_EARLY_start"
|
||||
s0.name = "prefix_EARLY_start"
|
||||
s0.entry.st_value = 0x00
|
||||
|
||||
s1 = mock.Mock()
|
||||
s1.name = "__init_PRE_KERNEL_1_start"
|
||||
s1.name = "prefix_PRE_KERNEL_1_start"
|
||||
s1.entry.st_value = 0x11
|
||||
|
||||
s2 = mock.Mock()
|
||||
s2.name = "__init_PRE_KERNEL_2_start"
|
||||
s2.name = "prefix_PRE_KERNEL_2_start"
|
||||
s2.entry.st_value = 0x22
|
||||
|
||||
s3 = mock.Mock()
|
||||
s3.name = "__init_POST_KERNEL_start"
|
||||
s3.name = "prefix_POST_KERNEL_start"
|
||||
s3.entry.st_value = 0x33
|
||||
|
||||
s4 = mock.Mock()
|
||||
s4.name = "__init_APPLICATION_start"
|
||||
s4.name = "prefix_APPLICATION_start"
|
||||
s4.entry.st_value = 0x44
|
||||
|
||||
s5 = mock.Mock()
|
||||
s5.name = "__init_SMP_start"
|
||||
s5.name = "prefix_SMP_start"
|
||||
s5.entry.st_value = 0x55
|
||||
|
||||
s6 = mock.Mock()
|
||||
s6.name = "__init_end"
|
||||
s6.name = "prefix_end"
|
||||
s6.entry.st_value = 0x66
|
||||
|
||||
sts.iter_symbols.return_value = [s0, s1, s2, s3, s4, s5, s6]
|
||||
|
||||
obj = check_init_priorities.ZephyrInitLevels("")
|
||||
obj._elf = mock_elf
|
||||
obj._load_level_addr()
|
||||
addrs, end = obj._find_level_addr("prefix", check_init_priorities._DEVICE_INIT_LEVELS)
|
||||
|
||||
self.assertDictEqual(obj._init_level_addr, {
|
||||
self.assertDictEqual(addrs, {
|
||||
"EARLY": 0x00,
|
||||
"PRE_KERNEL_1": 0x11,
|
||||
"PRE_KERNEL_2": 0x22,
|
||||
@@ -138,7 +138,7 @@ class testZephyrInitLevels(unittest.TestCase):
|
||||
"APPLICATION": 0x44,
|
||||
"SMP": 0x55,
|
||||
})
|
||||
self.assertEqual(obj._init_level_end, 0x66)
|
||||
self.assertEqual(end, 0x66)
|
||||
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
|
||||
def test_device_ord_from_name(self, mock_zilinit):
|
||||
@@ -191,11 +191,59 @@ class testZephyrInitLevels(unittest.TestCase):
|
||||
self.assertEqual(obj._initlevel_pointer(0x108, 0, 0), 2)
|
||||
self.assertEqual(obj._initlevel_pointer(0x108, 1, 0), 3)
|
||||
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels._object_name")
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer")
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
|
||||
def test_process_devices(self, mock_zilinit, mock_ip, mock_on):
|
||||
obj = check_init_priorities.ZephyrInitLevels("")
|
||||
obj.initlevels = {
|
||||
"PRE_KERNEL_2": [],
|
||||
"POST_KERNEL": [],
|
||||
}
|
||||
obj._device_level_addr = {
|
||||
"EARLY": 0x00,
|
||||
"PRE_KERNEL_1": 0x00,
|
||||
"PRE_KERNEL_2": 0x00,
|
||||
"POST_KERNEL": 0x08,
|
||||
"APPLICATION": 0x0c,
|
||||
"SMP": 0x0c,
|
||||
}
|
||||
obj._device_level_end = 0x0c
|
||||
obj._objects = {
|
||||
0x00: ("__device_dts_ord_11", 4, 0),
|
||||
0x04: ("__device_dts_ord_22", 4, 0),
|
||||
0x08: ("__device_dts_ord_33", 4, 0),
|
||||
}
|
||||
|
||||
mock_ip.side_effect = lambda *args: args
|
||||
mock_on.side_effect = lambda *args: f"dev_init_fn_{args[0][0]}"
|
||||
|
||||
obj._process_devices()
|
||||
|
||||
self.assertDictEqual(obj.initlevels, {
|
||||
"PRE_KERNEL_2": [
|
||||
"DEVICE dev_init_fn_0(__device_dts_ord_11)",
|
||||
"DEVICE dev_init_fn_4(__device_dts_ord_22)",
|
||||
],
|
||||
"POST_KERNEL": [
|
||||
"DEVICE dev_init_fn_8(__device_dts_ord_33)",
|
||||
],
|
||||
})
|
||||
self.assertDictEqual(obj.devices, {
|
||||
11: check_init_priorities.Priority("PRE_KERNEL_2", 0),
|
||||
22: check_init_priorities.Priority("PRE_KERNEL_2", 1),
|
||||
33: check_init_priorities.Priority("POST_KERNEL", 0),
|
||||
})
|
||||
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels._object_name")
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer")
|
||||
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
|
||||
def test_process_initlevels(self, mock_zilinit, mock_ip, mock_on):
|
||||
obj = check_init_priorities.ZephyrInitLevels("")
|
||||
obj.initlevels = {
|
||||
"PRE_KERNEL_2": [],
|
||||
"POST_KERNEL": [],
|
||||
}
|
||||
obj._init_level_addr = {
|
||||
"EARLY": 0x00,
|
||||
"PRE_KERNEL_1": 0x00,
|
||||
@@ -212,32 +260,18 @@ class testZephyrInitLevels(unittest.TestCase):
|
||||
}
|
||||
|
||||
mock_ip.side_effect = lambda *args: args
|
||||
|
||||
def mock_obj_name(*args):
|
||||
if args[0] == (0, 0, 0):
|
||||
return "i0"
|
||||
elif args[0] == (0, 1, 0):
|
||||
return "__device_dts_ord_11"
|
||||
elif args[0] == (4, 0, 0):
|
||||
return "i1"
|
||||
elif args[0] == (4, 1, 0):
|
||||
return "__device_dts_ord_22"
|
||||
return f"name_{args[0][0]}_{args[0][1]}"
|
||||
mock_on.side_effect = mock_obj_name
|
||||
mock_on.side_effect = lambda *args: f"init_fn_{args[0][0]}"
|
||||
|
||||
obj._process_initlevels()
|
||||
|
||||
self.assertDictEqual(obj.initlevels, {
|
||||
"EARLY": [],
|
||||
"PRE_KERNEL_1": [],
|
||||
"PRE_KERNEL_2": ["a: i0(__device_dts_ord_11)", "b: i1(__device_dts_ord_22)"],
|
||||
"POST_KERNEL": ["c: name_8_0(name_8_1)"],
|
||||
"APPLICATION": [],
|
||||
"SMP": [],
|
||||
})
|
||||
self.assertDictEqual(obj.devices, {
|
||||
11: check_init_priorities.Priority("PRE_KERNEL_2", 0),
|
||||
22: check_init_priorities.Priority("PRE_KERNEL_2", 1),
|
||||
"PRE_KERNEL_2": [
|
||||
"SYS_INIT init_fn_0()",
|
||||
"SYS_INIT init_fn_4()",
|
||||
],
|
||||
"POST_KERNEL": [
|
||||
"SYS_INIT init_fn_8()",
|
||||
],
|
||||
})
|
||||
|
||||
class testValidator(unittest.TestCase):
|
||||
|
||||
@@ -62,43 +62,6 @@ DEVICE_DT_DEFINE(TEST_NOLABEL, dev_init, NULL,
|
||||
#define DEV_HDL(node_id) device_handle_get(DEVICE_DT_GET(node_id))
|
||||
#define DEV_HDL_NAME(name) device_handle_get(DEVICE_GET(name))
|
||||
|
||||
ZTEST(devicetree_devices, test_init_get)
|
||||
{
|
||||
/* Check device pointers */
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIO)->dev,
|
||||
DEVICE_DT_GET(TEST_GPIO), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_I2C)->dev,
|
||||
DEVICE_DT_GET(TEST_I2C), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVA)->dev,
|
||||
DEVICE_DT_GET(TEST_DEVA), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVB)->dev,
|
||||
DEVICE_DT_GET(TEST_DEVB), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIOX)->dev,
|
||||
DEVICE_DT_GET(TEST_GPIOX), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVC)->dev,
|
||||
DEVICE_DT_GET(TEST_DEVC), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_PARTITION)->dev,
|
||||
DEVICE_DT_GET(TEST_PARTITION), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIO_INJECTED)->dev,
|
||||
DEVICE_DT_GET(TEST_GPIO_INJECTED), NULL);
|
||||
zassert_equal(DEVICE_INIT_GET(manual_dev)->dev,
|
||||
DEVICE_GET(manual_dev), NULL);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_NOLABEL)->dev,
|
||||
DEVICE_DT_GET(TEST_NOLABEL), NULL);
|
||||
|
||||
/* Check init functions */
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIO)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_I2C)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVA)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVB)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIOX)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_DEVC)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_PARTITION)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_GPIO_INJECTED)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_GET(manual_dev)->init_fn.dev, dev_init);
|
||||
zassert_equal(DEVICE_INIT_DT_GET(TEST_NOLABEL)->init_fn.dev, dev_init);
|
||||
}
|
||||
|
||||
ZTEST(devicetree_devices, test_init_order)
|
||||
{
|
||||
zassert_equal(init_order[0], DEV_HDL(TEST_GPIO));
|
||||
|
||||
Reference in New Issue
Block a user