1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <logging/log_core.h>
7 #include <logging/log_ctrl.h>
8 #include <syscall_handler.h>
9 
10 /* Implementation of functions related to controlling logging sources and backends:
11  * - getting/setting source details like name, filtering
12  * - controlling backends filtering
13  */
14 
z_log_runtime_filters_init(void)15 void z_log_runtime_filters_init(void)
16 {
17 	/*
18 	 * Initialize aggregated runtime filter levels (no backends are
19 	 * attached yet, so leave backend slots in each dynamic filter set
20 	 * alone for now).
21 	 *
22 	 * Each log source's aggregated runtime level is set to match its
23 	 * compile-time level. When backends are attached later on in
24 	 * log_init(), they'll be initialized to the same value.
25 	 */
26 	for (int i = 0; i < log_sources_count(); i++) {
27 		uint32_t *filters = log_dynamic_filters_get(i);
28 		uint8_t level = log_compiled_level_get(i);
29 
30 		LOG_FILTER_SLOT_SET(filters,
31 				    LOG_FILTER_AGGR_SLOT_IDX,
32 				    level);
33 	}
34 }
35 
log_src_cnt_get(uint32_t domain_id)36 uint32_t log_src_cnt_get(uint32_t domain_id)
37 {
38 	return log_sources_count();
39 }
40 
log_source_name_get(uint32_t domain_id,uint32_t src_id)41 const char *log_source_name_get(uint32_t domain_id, uint32_t src_id)
42 {
43 	return src_id < log_sources_count() ? log_name_get(src_id) : NULL;
44 }
45 
max_filter_get(uint32_t filters)46 static uint32_t max_filter_get(uint32_t filters)
47 {
48 	uint32_t max_filter = LOG_LEVEL_NONE;
49 	int first_slot = LOG_FILTER_FIRST_BACKEND_SLOT_IDX;
50 	int i;
51 
52 	for (i = first_slot; i < LOG_FILTERS_NUM_OF_SLOTS; i++) {
53 		uint32_t tmp_filter = LOG_FILTER_SLOT_GET(&filters, i);
54 
55 		if (tmp_filter > max_filter) {
56 			max_filter = tmp_filter;
57 		}
58 	}
59 
60 	return max_filter;
61 }
62 
z_impl_log_filter_set(struct log_backend const * const backend,uint32_t domain_id,int16_t source_id,uint32_t level)63 uint32_t z_impl_log_filter_set(struct log_backend const *const backend,
64 			       uint32_t domain_id, int16_t source_id,
65 			       uint32_t level)
66 {
67 	__ASSERT_NO_MSG(source_id < log_sources_count());
68 
69 	if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
70 		uint32_t new_aggr_filter;
71 
72 		uint32_t *filters = log_dynamic_filters_get(source_id);
73 
74 		if (backend == NULL) {
75 			struct log_backend const *iter_backend;
76 			uint32_t max = 0U;
77 			uint32_t current;
78 
79 			for (int i = 0; i < log_backend_count_get(); i++) {
80 				iter_backend = log_backend_get(i);
81 				current = log_filter_set(iter_backend,
82 							 domain_id,
83 							 source_id, level);
84 				max = MAX(current, max);
85 			}
86 
87 			level = max;
88 		} else {
89 			uint32_t max = log_filter_get(backend, domain_id,
90 						      source_id, false);
91 
92 			level = MIN(level, max);
93 
94 			LOG_FILTER_SLOT_SET(filters,
95 					    log_backend_id_get(backend),
96 					    level);
97 
98 			/* Once current backend filter is updated recalculate
99 			 * aggregated maximal level
100 			 */
101 			new_aggr_filter = max_filter_get(*filters);
102 
103 			LOG_FILTER_SLOT_SET(filters,
104 					    LOG_FILTER_AGGR_SLOT_IDX,
105 					    new_aggr_filter);
106 		}
107 	}
108 
109 	return level;
110 }
111 
112 #ifdef CONFIG_USERSPACE
z_vrfy_log_filter_set(struct log_backend const * const backend,uint32_t domain_id,int16_t src_id,uint32_t level)113 uint32_t z_vrfy_log_filter_set(struct log_backend const *const backend,
114 			    uint32_t domain_id,
115 			    int16_t src_id,
116 			    uint32_t level)
117 {
118 	Z_OOPS(Z_SYSCALL_VERIFY_MSG(backend == NULL,
119 		"Setting per-backend filters from user mode is not supported"));
120 	Z_OOPS(Z_SYSCALL_VERIFY_MSG(domain_id == CONFIG_LOG_DOMAIN_ID,
121 		"Invalid log domain_id"));
122 	Z_OOPS(Z_SYSCALL_VERIFY_MSG(src_id < log_sources_count(),
123 		"Invalid log source id"));
124 	Z_OOPS(Z_SYSCALL_VERIFY_MSG(
125 		(level <= LOG_LEVEL_DBG),
126 		"Invalid log level"));
127 
128 	return z_impl_log_filter_set(NULL, domain_id, src_id, level);
129 }
130 #include <syscalls/log_filter_set_mrsh.c>
131 #endif
132 
backend_filter_set(struct log_backend const * const backend,uint32_t level)133 static void backend_filter_set(struct log_backend const *const backend,
134 			       uint32_t level)
135 {
136 	if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
137 		for (int i = 0; i < log_sources_count(); i++) {
138 			log_filter_set(backend, CONFIG_LOG_DOMAIN_ID, i, level);
139 		}
140 	}
141 }
142 
log_backend_enable(struct log_backend const * const backend,void * ctx,uint32_t level)143 void log_backend_enable(struct log_backend const *const backend,
144 			void *ctx,
145 			uint32_t level)
146 {
147 	/* As first slot in filtering mask is reserved, backend ID has offset.*/
148 	uint32_t id = LOG_FILTER_FIRST_BACKEND_SLOT_IDX;
149 
150 	id += backend - log_backend_get(0);
151 
152 	log_backend_id_set(backend, id);
153 	backend_filter_set(backend, level);
154 	log_backend_activate(backend, ctx);
155 
156 	z_log_notify_backend_enabled();
157 }
158 
log_backend_disable(struct log_backend const * const backend)159 void log_backend_disable(struct log_backend const *const backend)
160 {
161 	log_backend_deactivate(backend);
162 	backend_filter_set(backend, LOG_LEVEL_NONE);
163 }
164 
log_filter_get(struct log_backend const * const backend,uint32_t domain_id,int16_t source_id,bool runtime)165 uint32_t log_filter_get(struct log_backend const *const backend,
166 			uint32_t domain_id, int16_t source_id, bool runtime)
167 {
168 	__ASSERT_NO_MSG(source_id < log_sources_count());
169 
170 	if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) && runtime) {
171 		if (source_id < 0) {
172 			return LOG_LEVEL_DBG;
173 		}
174 
175 		uint32_t *filters = log_dynamic_filters_get(source_id);
176 
177 		return LOG_FILTER_SLOT_GET(filters,
178 					   log_backend_id_get(backend));
179 	}
180 
181 	return log_compiled_level_get(source_id);
182 }
183