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 = (const void *)(out_log_msg->hdr.source ?
55 				log_source_id(out_log_msg->hdr.source) : -1);
56 
57 	/* Fill new package. */
58 	fsc_plen = cbprintf_fsc_package(msg->log.data, msg->log.hdr.desc.package_len,
59 					out_log_msg->data, fsc_plen);
60 	if (fsc_plen < 0) {
61 		__ASSERT_NO_MSG(false);
62 		return;
63 	}
64 
65 	/* Copy data */
66 	if (dlen) {
67 		memcpy(&out_log_msg->data[fsc_plen],
68 		       &msg->log.data[msg->log.hdr.desc.package_len],
69 		       dlen);
70 	}
71 
72 	err = backend_remote->transport_api->send(backend_remote, out_msg, msg_len + msg_offset);
73 	if (err < 0) {
74 		__ASSERT(false, "Unexpected error: %d\n", err);
75 		return;
76 	}
77 }
78 
log_multidomain_backend_on_started(struct log_multidomain_backend * backend_remote,int err)79 void log_multidomain_backend_on_started(struct log_multidomain_backend *backend_remote, int err)
80 {
81 	backend_remote->status = err;
82 
83 	k_sem_give(&backend_remote->rdy_sem);
84 }
85 
log_multidomain_backend_on_error(struct log_multidomain_backend * backend_remote,int err)86 void log_multidomain_backend_on_error(struct log_multidomain_backend *backend_remote, int err)
87 {
88 	backend_remote->status = err;
89 }
90 
get_name_response(struct log_multidomain_backend * backend_remote,uint8_t domain_id,uint16_t source_id,bool domain_name)91 static void get_name_response(struct log_multidomain_backend *backend_remote,
92 			      uint8_t domain_id, uint16_t source_id,
93 			      bool domain_name)
94 {
95 	const char *name = domain_name ?
96 			log_domain_name_get(domain_id) :
97 			log_source_name_get(domain_id, source_id);
98 	size_t slen = strlen(name);
99 	size_t msg_offset = offsetof(struct log_multidomain_msg, data);
100 	size_t msg_size = slen + 1 + msg_offset +
101 		(domain_name ? sizeof(struct log_multidomain_domain_name) :
102 				sizeof(struct log_multidomain_source_name));
103 	uint8_t msg_buf[msg_size];
104 	struct log_multidomain_msg *outmsg = (struct log_multidomain_msg *)msg_buf;
105 	char *dst = domain_name ?
106 			outmsg->data.domain_name.name :
107 			outmsg->data.source_name.name;
108 	int err;
109 
110 	outmsg->id = domain_name ? Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME :
111 				Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME;
112 	outmsg->status = Z_LOG_MULTIDOMAIN_STATUS_OK;
113 	memcpy(dst, name, slen);
114 	dst[slen] = '\0';
115 
116 	if (domain_name) {
117 		outmsg->data.domain_name.domain_id = domain_id;
118 	} else {
119 		outmsg->data.source_name.domain_id = domain_id;
120 		outmsg->data.source_name.source_id = source_id;
121 	}
122 
123 	err = backend_remote->transport_api->send(backend_remote, outmsg, msg_size);
124 	__ASSERT_NO_MSG(err >= 0);
125 }
126 
log_multidomain_backend_on_recv_cb(struct log_multidomain_backend * backend_remote,const void * data,size_t len)127 void log_multidomain_backend_on_recv_cb(struct log_multidomain_backend *backend_remote,
128 				   const void *data, size_t len)
129 {
130 	struct log_multidomain_msg *msg = (struct log_multidomain_msg *)data;
131 	struct log_multidomain_msg outmsg = {
132 		.id = msg->id,
133 		.status = Z_LOG_MULTIDOMAIN_STATUS_OK
134 	};
135 	int err;
136 
137 	memcpy(&outmsg, msg, sizeof(struct log_multidomain_msg));
138 
139 	switch (msg->id) {
140 	case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_CNT:
141 		outmsg.data.domain_cnt.count = log_domains_count();
142 		break;
143 
144 	case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_CNT:
145 		outmsg.data.source_cnt.count =
146 			log_src_cnt_get(msg->data.source_cnt.domain_id);
147 		break;
148 
149 	case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME:
150 		get_name_response(backend_remote,
151 				  msg->data.domain_name.domain_id,
152 				  0, true);
153 		return;
154 
155 	case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME:
156 		get_name_response(backend_remote,
157 				  msg->data.source_name.domain_id,
158 				  msg->data.source_name.source_id,
159 				  false);
160 		return;
161 
162 	case Z_LOG_MULTIDOMAIN_ID_GET_LEVELS:
163 		outmsg.data.levels.level =
164 			log_filter_get(backend_remote->log_backend,
165 				       outmsg.data.levels.domain_id,
166 				       outmsg.data.levels.source_id,
167 				       false);
168 		outmsg.data.levels.runtime_level =
169 			log_filter_get(backend_remote->log_backend,
170 				       outmsg.data.levels.domain_id,
171 				       outmsg.data.levels.source_id,
172 				       true);
173 		break;
174 	case Z_LOG_MULTIDOMAIN_ID_SET_RUNTIME_LEVEL:
175 		outmsg.data.set_rt_level.runtime_level =
176 			log_filter_set(backend_remote->log_backend,
177 				       outmsg.data.set_rt_level.domain_id,
178 				       outmsg.data.set_rt_level.source_id,
179 				       outmsg.data.set_rt_level.runtime_level);
180 		break;
181 	case Z_LOG_MULTIDOMAIN_ID_READY:
182 		backend_remote->ready = true;
183 		break;
184 	default:
185 		__ASSERT(0, "Unexpected message");
186 		break;
187 	}
188 
189 	err = backend_remote->transport_api->send(backend_remote, &outmsg, sizeof(outmsg));
190 	__ASSERT_NO_MSG(err >= 0);
191 }
192 
init(struct log_backend const * const backend)193 static void init(struct log_backend const *const backend)
194 {
195 	struct log_multidomain_backend *backend_remote = backend->cb->ctx;
196 	int err;
197 
198 	backend_remote->log_backend = backend;
199 	k_sem_init(&backend_remote->rdy_sem, 0, 1);
200 
201 	err = backend_remote->transport_api->init(backend_remote);
202 	__ASSERT_NO_MSG(err >= 0);
203 
204 	err = k_sem_take(&backend_remote->rdy_sem, K_MSEC(4000));
205 	__ASSERT_NO_MSG(err >= 0);
206 }
207 
is_ready(struct log_backend const * const backend)208 static int is_ready(struct log_backend const *const backend)
209 {
210 	struct log_multidomain_backend *backend_remote = backend->cb->ctx;
211 
212 	return backend_remote->ready ? 0 : -EINPROGRESS;
213 }
214 
panic(struct log_backend const * const backend)215 static void panic(struct log_backend const *const backend)
216 {
217 	struct log_multidomain_backend *backend_remote = backend->cb->ctx;
218 
219 	backend_remote->panic = true;
220 }
221 
dropped(const struct log_backend * const backend,uint32_t cnt)222 static void dropped(const struct log_backend *const backend, uint32_t cnt)
223 {
224 	struct log_multidomain_backend *backend_remote = backend->cb->ctx;
225 	int err;
226 	struct log_multidomain_msg msg = {
227 		.id = Z_LOG_MULTIDOMAIN_ID_DROPPED,
228 		.status = Z_LOG_MULTIDOMAIN_STATUS_OK,
229 		.data = {
230 			.dropped = {
231 				.dropped = cnt
232 			}
233 		}
234 	};
235 
236 	err = backend_remote->transport_api->send(backend_remote, &msg, sizeof(msg));
237 	__ASSERT_NO_MSG(err >= 0);
238 }
239 
240 const struct log_backend_api log_multidomain_backend_api = {
241 	.process = process,
242 	.panic = panic,
243 	.dropped = dropped,
244 	.init = init,
245 	.is_ready = is_ready
246 };
247