1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ipc/ipc_service.h>
9 #include <zephyr/logging/log_multidomain_helper.h>
10 #include <zephyr/logging/log_core.h>
11 #include <zephyr/logging/log_backend.h>
12 #include <zephyr/logging/log_ctrl.h>
13
process(const struct log_backend * const backend,union log_msg_generic * msg)14 static void process(const struct log_backend *const backend,
15 union log_msg_generic *msg)
16 {
17 int err;
18 struct log_multidomain_backend *backend_remote = backend->cb->ctx;
19 uint32_t dlen = msg->log.hdr.desc.data_len;
20 int fsc_plen;
21
22 if (backend_remote->panic) {
23 return;
24 }
25
26 fsc_plen = cbprintf_fsc_package(msg->log.data,
27 msg->log.hdr.desc.package_len,
28 NULL,
29 0);
30 if (fsc_plen < 0) {
31 __ASSERT_NO_MSG(false);
32 return;
33 }
34
35 /* Need to ensure that package is aligned to a pointer size even though
36 * it is in the packed structured.
37 */
38 uint32_t msg_len = Z_LOG_MSG_LEN(fsc_plen, dlen);
39 uint8_t buf[msg_len + sizeof(void *)] __aligned(sizeof(void *));
40 size_t msg_offset = offsetof(struct log_multidomain_msg, data);
41 struct log_multidomain_msg *out_msg =
42 (struct log_multidomain_msg *)&buf[sizeof(void *) - msg_offset];
43 uintptr_t out_log_msg_ptr = (uintptr_t)out_msg->data.log_msg.data;
44 struct log_msg *out_log_msg = (struct log_msg *)out_log_msg_ptr;
45
46 /* Set ipc message id. */
47 out_msg->id = Z_LOG_MULTIDOMAIN_ID_MSG;
48 out_msg->status = Z_LOG_MULTIDOMAIN_STATUS_OK;
49 /* Copy log message header. */
50 memcpy(&out_log_msg->hdr, &msg->log.hdr, sizeof(struct log_msg_hdr));
51 /* Update package len field in the message descriptor. */
52 out_log_msg->hdr.desc.package_len = fsc_plen;
53
54 out_log_msg->hdr.source = out_log_msg->hdr.source ?
55 (const void *)(IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ?
56 log_dynamic_source_id((void *)out_log_msg->hdr.source) :
57 log_const_source_id((void *)out_log_msg->hdr.source)) :
58 (const void *)-1;
59
60 /* Fill new package. */
61 fsc_plen = cbprintf_fsc_package(msg->log.data, msg->log.hdr.desc.package_len,
62 out_log_msg->data, fsc_plen);
63 if (fsc_plen < 0) {
64 __ASSERT_NO_MSG(false);
65 return;
66 }
67
68 /* Copy data */
69 if (dlen) {
70 memcpy(&out_log_msg->data[fsc_plen],
71 &msg->log.data[msg->log.hdr.desc.package_len],
72 dlen);
73 }
74
75 err = backend_remote->transport_api->send(backend_remote, out_msg, msg_len + msg_offset);
76 if (err < 0) {
77 __ASSERT(false, "Unexpected error: %d\n", err);
78 return;
79 }
80 }
81
log_multidomain_backend_on_started(struct log_multidomain_backend * backend_remote,int err)82 void log_multidomain_backend_on_started(struct log_multidomain_backend *backend_remote, int err)
83 {
84 backend_remote->status = err;
85
86 k_sem_give(&backend_remote->rdy_sem);
87 }
88
log_multidomain_backend_on_error(struct log_multidomain_backend * backend_remote,int err)89 void log_multidomain_backend_on_error(struct log_multidomain_backend *backend_remote, int err)
90 {
91 backend_remote->status = err;
92 }
93
get_name_response(struct log_multidomain_backend * backend_remote,uint8_t domain_id,uint16_t source_id,bool domain_name)94 static void get_name_response(struct log_multidomain_backend *backend_remote,
95 uint8_t domain_id, uint16_t source_id,
96 bool domain_name)
97 {
98 const char *name = domain_name ?
99 log_domain_name_get(domain_id) :
100 log_source_name_get(domain_id, source_id);
101 size_t slen = strlen(name);
102 size_t msg_offset = offsetof(struct log_multidomain_msg, data);
103 size_t msg_size = slen + 1 + msg_offset +
104 (domain_name ? sizeof(struct log_multidomain_domain_name) :
105 sizeof(struct log_multidomain_source_name));
106 uint8_t msg_buf[msg_size];
107 struct log_multidomain_msg *outmsg = (struct log_multidomain_msg *)msg_buf;
108 char *dst = domain_name ?
109 outmsg->data.domain_name.name :
110 outmsg->data.source_name.name;
111 int err;
112
113 outmsg->id = domain_name ? Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME :
114 Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME;
115 outmsg->status = Z_LOG_MULTIDOMAIN_STATUS_OK;
116 memcpy(dst, name, slen);
117 dst[slen] = '\0';
118
119 if (domain_name) {
120 outmsg->data.domain_name.domain_id = domain_id;
121 } else {
122 outmsg->data.source_name.domain_id = domain_id;
123 outmsg->data.source_name.source_id = source_id;
124 }
125
126 err = backend_remote->transport_api->send(backend_remote, outmsg, msg_size);
127 __ASSERT_NO_MSG(err >= 0);
128 }
129
log_multidomain_backend_on_recv_cb(struct log_multidomain_backend * backend_remote,const void * data,size_t len)130 void log_multidomain_backend_on_recv_cb(struct log_multidomain_backend *backend_remote,
131 const void *data, size_t len)
132 {
133 struct log_multidomain_msg *msg = (struct log_multidomain_msg *)data;
134 struct log_multidomain_msg outmsg = {
135 .id = msg->id,
136 .status = Z_LOG_MULTIDOMAIN_STATUS_OK
137 };
138 int err;
139
140 memcpy(&outmsg, msg, sizeof(struct log_multidomain_msg));
141
142 switch (msg->id) {
143 case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_CNT:
144 outmsg.data.domain_cnt.count = log_domains_count();
145 break;
146
147 case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_CNT:
148 outmsg.data.source_cnt.count =
149 log_src_cnt_get(msg->data.source_cnt.domain_id);
150 break;
151
152 case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME:
153 get_name_response(backend_remote,
154 msg->data.domain_name.domain_id,
155 0, true);
156 return;
157
158 case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME:
159 get_name_response(backend_remote,
160 msg->data.source_name.domain_id,
161 msg->data.source_name.source_id,
162 false);
163 return;
164
165 case Z_LOG_MULTIDOMAIN_ID_GET_LEVELS:
166 outmsg.data.levels.level =
167 log_filter_get(backend_remote->log_backend,
168 outmsg.data.levels.domain_id,
169 outmsg.data.levels.source_id,
170 false);
171 outmsg.data.levels.runtime_level =
172 log_filter_get(backend_remote->log_backend,
173 outmsg.data.levels.domain_id,
174 outmsg.data.levels.source_id,
175 true);
176 break;
177 case Z_LOG_MULTIDOMAIN_ID_SET_RUNTIME_LEVEL:
178 outmsg.data.set_rt_level.runtime_level =
179 log_filter_set(backend_remote->log_backend,
180 outmsg.data.set_rt_level.domain_id,
181 outmsg.data.set_rt_level.source_id,
182 outmsg.data.set_rt_level.runtime_level);
183 break;
184 case Z_LOG_MULTIDOMAIN_ID_READY:
185 backend_remote->ready = true;
186 break;
187 default:
188 __ASSERT(0, "Unexpected message");
189 break;
190 }
191
192 err = backend_remote->transport_api->send(backend_remote, &outmsg, sizeof(outmsg));
193 __ASSERT_NO_MSG(err >= 0);
194 }
195
init(struct log_backend const * const backend)196 static void init(struct log_backend const *const backend)
197 {
198 struct log_multidomain_backend *backend_remote = backend->cb->ctx;
199 int err;
200
201 backend_remote->log_backend = backend;
202 k_sem_init(&backend_remote->rdy_sem, 0, 1);
203
204 err = backend_remote->transport_api->init(backend_remote);
205 __ASSERT_NO_MSG(err >= 0);
206
207 err = k_sem_take(&backend_remote->rdy_sem, K_MSEC(4000));
208 __ASSERT_NO_MSG(err >= 0);
209 }
210
is_ready(struct log_backend const * const backend)211 static int is_ready(struct log_backend const *const backend)
212 {
213 struct log_multidomain_backend *backend_remote = backend->cb->ctx;
214
215 return backend_remote->ready ? 0 : -EINPROGRESS;
216 }
217
panic(struct log_backend const * const backend)218 static void panic(struct log_backend const *const backend)
219 {
220 struct log_multidomain_backend *backend_remote = backend->cb->ctx;
221
222 backend_remote->panic = true;
223 }
224
dropped(const struct log_backend * const backend,uint32_t cnt)225 static void dropped(const struct log_backend *const backend, uint32_t cnt)
226 {
227 struct log_multidomain_backend *backend_remote = backend->cb->ctx;
228 int err;
229 struct log_multidomain_msg msg = {
230 .id = Z_LOG_MULTIDOMAIN_ID_DROPPED,
231 .status = Z_LOG_MULTIDOMAIN_STATUS_OK,
232 .data = {
233 .dropped = {
234 .dropped = cnt
235 }
236 }
237 };
238
239 err = backend_remote->transport_api->send(backend_remote, &msg, sizeof(msg));
240 __ASSERT_NO_MSG(err >= 0);
241 }
242
243 const struct log_backend_api log_multidomain_backend_api = {
244 .process = process,
245 .panic = panic,
246 .dropped = dropped,
247 .init = init,
248 .is_ready = is_ready
249 };
250