Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions cmake/linker_script/common/common-rom.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ zephyr_linker_section_obj_level(SECTION init LEVEL APPLICATION)
zephyr_linker_section_obj_level(SECTION init LEVEL SMP)

zephyr_iterable_section(NAME device NUMERIC KVMA RAM_REGION GROUP RODATA_REGION)
zephyr_iterable_section(NAME service NUMERIC KVMA RAM_REGION GROUP RODATA_REGION)

if(CONFIG_GEN_SW_ISR_TABLE AND NOT CONFIG_SRAM_SW_ISR_TABLE)
# ld align has been changed to subalign to provide identical behavior scatter vs. ld.
Expand Down Expand Up @@ -201,36 +202,36 @@ if(CONFIG_SYMTAB)
zephyr_linker_section_configure(SECTION symtab INPUT ".gnu.linkonce.symtab*")
endif()

if (CONFIG_DEVICE_DEPS)
if(CONFIG_DEVICE_DEPS)
zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16)
zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1)
zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1)
endif()

zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION)

if (CONFIG_BT_IAS)
if(CONFIG_BT_IAS)
zephyr_iterable_section(NAME bt_ias_cb KVMA RAM_REGION GROUP RODATA_REGION)
endif()

if (CONFIG_LOG)
if(CONFIG_LOG)
zephyr_iterable_section(NAME log_link KVMA RAM_REGION GROUP RODATA_REGION)
zephyr_iterable_section(NAME log_backend KVMA RAM_REGION GROUP RODATA_REGION)
endif()

if (CONFIG_MULTI_LEVEL_INTERRUPTS)
if(CONFIG_MULTI_LEVEL_INTERRUPTS)
zephyr_iterable_section(NAME intc_table KVMA RAM_REGION GROUP RODATA_REGION)
endif()

if (CONFIG_HTTP_SERVER)
if(CONFIG_HTTP_SERVER)
zephyr_iterable_section(NAME http_service_desc KVMA RAM_REGION GROUP RODATA_REGION)
endif()

if (CONFIG_COAP_SERVER)
if(CONFIG_COAP_SERVER)
zephyr_iterable_section(NAME coap_service KVMA RAM_REGION GROUP RODATA_REGION)
endif()

if (CONFIG_NET_MGMT)
if(CONFIG_NET_MGMT)
zephyr_iterable_section(NAME net_mgmt_event_static_handler KVMA RAM_REGION GROUP RODATA_REGION)
endif()

Expand Down
3 changes: 1 addition & 2 deletions include/zephyr/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -1263,8 +1263,7 @@ device_get_dt_nodelabels(const struct device *dev)
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 = NULL, \
.dev = (const struct device *)&DEVICE_NAME_GET(dev_id), \
.init_obj = { .dev = (const struct device *)&DEVICE_NAME_GET(dev_id) } \
}

/**
Expand Down
24 changes: 15 additions & 9 deletions include/zephyr/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <zephyr/sys/util.h>
#include <zephyr/toolchain.h>

#include <zephyr/service.h>

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -65,15 +67,14 @@ struct device;
*/
struct init_entry {
/**
* If the init function belongs to a SYS_INIT, this field stored the
* initialization function, otherwise it is set to NULL.
*/
int (*init_fn)(void);
/**
* If the init entry belongs to a device, this fields stores a
* reference to it, otherwise it is set to NULL.
* An init entry can be about a device or a service, _obj will
* be used to differentiate depending on relative sections.
*/
const struct device *dev;
union {
const void *_obj;
const struct device *dev;
const struct service *srv;
} init_obj;
};

/** @cond INTERNAL_HIDDEN */
Expand Down Expand Up @@ -164,9 +165,14 @@ struct init_entry {
* @see SYS_INIT()
*/
#define SYS_INIT_NAMED(name, init_fn_, level, prio) \
Z_SERVICE_DEFINE(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 = (init_fn_), .dev = NULL} \
Z_INIT_ENTRY_NAME(name) = { \
.init_obj = { \
.srv = (const struct service *)&Z_SERVICE_NAME_GET(name) \
} \
}

/** @} */

Expand Down
2 changes: 2 additions & 0 deletions include/zephyr/linker/common-rom/common-rom-kernel-devices.ld
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: Apache-2.0 */

Check warning on line 1 in include/zephyr/linker/common-rom/common-rom-kernel-devices.ld

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Copyright missing

include/zephyr/linker/common-rom/common-rom-kernel-devices.ld:1 File has no SPDX-FileCopyrightText header, consider adding one.

#include <zephyr/linker/iterable_sections.h>

Expand All @@ -22,6 +22,8 @@

ITERABLE_SECTION_ROM_NUMERIC(device, Z_LINK_ITERABLE_SUBALIGN)

ITERABLE_SECTION_ROM_NUMERIC(service, Z_LINK_ITERABLE_SUBALIGN)

#if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_SHARED_INTERRUPTS)
/* since z_shared_isr() is not referenced anywhere when
* zephyr_pre0.elf is built, the linker will end up dropping it.
Expand Down
92 changes: 92 additions & 0 deletions include/zephyr/service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2024 Tomasz Bursztyka.
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SERVICE_H_
#define ZEPHYR_INCLUDE_SERVICE_H_

#include <zephyr/sys/iterable_sections.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup service System service
* @ingroup os_services
*
* A system service is a one-shot initialized software component, instantiated
* via SYS_INIT() or SYS_INIT_NAMED(). It does not provide any public API.
*
* @{
*/

/**
* @brief Structure to store service instance
*
* This will be defined through SYS_INIT/SYS_INIT_NAMED
*/
struct service {
/**
* Initialization function
*/
int (*init)(void);
};

/** @cond INTERNAL_HIDDEN */

/**
* @brief Expands to the name of a global service object
*
* @param name Service name.
*
* @return The full name of the service object defined by the service
* definition macro.
*/
#define Z_SERVICE_NAME_GET(name) _CONCAT(__service_, name)

/**
* @brief Initializer for @ref service
*
* @param init_fn Initialization function (mandatory).
*/
#define Z_SERVICE_INIT(init_fn) \
{ \
.init = (init_fn) \
}

/**
* @brief Service section name (used for sorting purposes).
*
* @param level Initialization level.
* @param prio Initialization priority.
*/
#define Z_SERVICE_SECTION_NAME(level, prio) \
_CONCAT(INIT_LEVEL_ORD(level), _##prio)

/**
* @brief Define a @ref service
*
* @param name Service name.
* @param init_fn Initialization function.
* @param level Initialization level.
* @param prio Initialization priority.
*/
#define Z_SERVICE_DEFINE(name, init_fn, level, prio) \
static const \
STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \
service, service, \
Z_SERVICE_SECTION_NAME(level, prio), \
Z_SERVICE_NAME_GET(name)) = Z_SERVICE_INIT(init_fn)

/** @endcond */

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_SERVICE_H_ */
33 changes: 29 additions & 4 deletions kernel/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ enum init_level {
extern const struct init_entry __init_SMP_start[];
#endif /* CONFIG_SMP */

TYPE_SECTION_START_EXTERN(struct service, service);
TYPE_SECTION_END_EXTERN(struct service, service);

/*
* storage space for the interrupt stack
*
Expand Down Expand Up @@ -206,6 +209,19 @@ static void z_device_state_init(void)
}
}

/**
* @brief Check if the init_entry is for a service or not
*
* @param a pointer (see struct init_entry's init_obj._obj attribute)
*
* @return True if it's a service, false otherwise
*/
static inline bool is_entry_about_service(const void *obj)
{
return (obj >= (void *)_service_list_start &&
obj < (void *)_service_list_end);
}

/**
* @brief Execute all the init entry initialization functions at a given level
*
Expand Down Expand Up @@ -234,17 +250,26 @@ static void z_sys_init_run_level(enum init_level level)
const struct init_entry *entry;

for (entry = levels[level]; entry < levels[level+1]; entry++) {
const struct device *dev = entry->dev;
int result = 0;

if (unlikely(entry->init_obj._obj == NULL)) {
continue;
}

sys_trace_sys_init_enter(entry, level);
if (dev != NULL) {

if (is_entry_about_service(entry->init_obj._obj)) {
const struct service *srv = entry->init_obj.srv;

result = srv->init();
} else {
const struct device *dev = entry->init_obj.dev;

if ((dev->flags & DEVICE_FLAG_INIT_DEFERRED) == 0U) {
result = do_device_init(dev);
}
} else {
result = entry->init_fn();
}

sys_trace_sys_init_exit(entry, level, result);
}
}
Expand Down
27 changes: 16 additions & 11 deletions scripts/build/check_init_priorities.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@

# The offset of the init pointer in "struct device", in number of pointers.
DEVICE_INIT_OFFSET = 5
# The offset of the init pointer in "struct service", in number of pointers.
SERVICE_INIT_OFFSET = 0

class Priority:
"""Parses and holds a device initialization priority.
Expand Down Expand Up @@ -207,20 +209,23 @@ def _process_initlevels(self):
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))
obj_name = self._object_name(self._initlevel_pointer(addr, 0, shidx))
if obj_name != "unknown":
obj_addr = self._object_addr[obj_name]
_, _, shidx = self._objects[obj_addr]

ordinal = self._device_ord_from_name(arg1_name)
if ordinal:
dev_addr = self._object_addr[arg1_name]
_, _, shidx = self._objects[dev_addr]
arg0_name = self._object_name(self._initlevel_pointer(
dev_addr, DEVICE_INIT_OFFSET, shidx))
ordinal = self._device_ord_from_name(obj_name)
if ordinal:
init_fn_name = self._object_name(self._initlevel_pointer(
obj_addr, DEVICE_INIT_OFFSET, shidx))

prio = Priority(level, priority)
self.devices[ordinal] = (prio, arg0_name)
prio = Priority(level, priority)
self.devices[ordinal] = (prio, init_fn_name)
else:
init_fn_name = self._object_name(self._initlevel_pointer(
obj_addr, SERVICE_INIT_OFFSET, shidx))

self.initlevels[level].append(f"{obj}: {arg0_name}({arg1_name})")
self.initlevels[level].append(f"{obj}: {init_fn_name}({obj_name})")

addr += size
priority += 1
Expand Down
19 changes: 12 additions & 7 deletions scripts/build/check_init_priorities_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,24 +209,29 @@ def test_process_initlevels(self, mock_zilinit, mock_ip, mock_on):
0x00: ("a", 4, 0),
0x04: ("b", 4, 0),
0x08: ("c", 4, 0),
0x0a: ("d", 4, 0),
}
obj._object_addr = {
"__device_dts_ord_11": 0x00,
"__device_dts_ord_22": 0x04,
"__service_foo" : 0x0a,
}

mock_ip.side_effect = lambda *args: args

def mock_obj_name(*args):
if args[0] == (0, 5, 0):
return "i0"
elif args[0] == (0, 1, 0):
if args[0] == (0, 0, 0):
return "__device_dts_ord_11"
elif args[0] == (4, 0, 0):
return "__device_dts_ord_22"
elif args[0] == (8, 0, 0):
return "__service_foo"
elif args[0] == (10, 0, 0):
return "foo_init_fn"
elif args[0] == (0, 5, 0):
return "i0"
elif args[0] == (4, 5, 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

obj._process_initlevels()
Expand All @@ -235,7 +240,7 @@ def mock_obj_name(*args):
"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)"],
"POST_KERNEL": ["c: foo_init_fn(__service_foo)"],
"APPLICATION": [],
"SMP": [],
})
Expand Down
2 changes: 1 addition & 1 deletion subsys/net/lib/sockets/sockets_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static K_CONDVAR_DEFINE(wait_start);
STRUCT_SECTION_START_EXTERN(net_socket_service_desc);
STRUCT_SECTION_END_EXTERN(net_socket_service_desc);

static struct service {
static struct service_context {
struct zsock_pollfd events[CONFIG_ZVFS_POLL_MAX];
int count;
} ctx;
Expand Down
Loading
Loading