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