device: perform dynamic device initialization during system startup

Initialize all device objects in a batch before invoking any code that
might try to reference data in them.  This eliminates a race condition
enabled by the ability to resolve a device structure at build time,
and reference it from one device's initialization routine before the
device itself has been initialized.

While the device is pulled from the sys_init records rather than
static devices, all in-tree init_entry records that are associated
with devices are produced via Z_DEVICE_DEFINE(), so there should be no
static devices that would be missed by instead iterating over the
device records.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2021-02-02 10:07:18 -06:00 committed by Anas Nashif
commit 1cadd8b305
3 changed files with 21 additions and 4 deletions

View file

@ -31,6 +31,22 @@ extern uint32_t __device_busy_end[];
#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
#endif
/**
* @brief Initialize state for all static devices.
*
* The state object is always zero-initialized, but this may not be
* sufficient.
*/
void z_device_state_init(void)
{
const struct device *dev = __device_start;
while (dev < __device_end) {
z_object_init(dev);
++dev;
}
}
/**
* @brief Execute all the init entry initialization functions at a given level
*
@ -60,10 +76,6 @@ void z_sys_init_run_level(int32_t level)
for (entry = levels[level]; entry < levels[level+1]; entry++) {
const struct device *dev = entry->dev;
if (dev != NULL) {
z_object_init(dev);
}
if ((entry->init(dev) != 0) && (dev != NULL)) {
/* Initialization failed.
* Set the init status bit so device is not declared ready.

View file

@ -37,6 +37,8 @@ static inline void z_data_copy(void)
#endif
FUNC_NORETURN void z_cstart(void);
void z_device_state_init(void);
extern FUNC_NORETURN void z_thread_entry(k_thread_entry_t entry,
void *p1, void *p2, void *p3);

View file

@ -386,6 +386,9 @@ FUNC_NORETURN void z_cstart(void)
#if defined(CONFIG_MMU) && defined(CONFIG_USERSPACE)
z_kernel_map_fixup();
#endif
/* do any necessary initialization of static devices */
z_device_state_init();
/* perform basic hardware initialization */
z_sys_init_run_level(_SYS_INIT_LEVEL_PRE_KERNEL_1);
z_sys_init_run_level(_SYS_INIT_LEVEL_PRE_KERNEL_2);