1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
7 #define ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
8 
9 #include <sys/atomic.h>
10 #include <sys/util.h>
11 #include <string.h>
12 #include <logging/log_msg2.h>
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 /**
19  * @brief Log message API
20  * @defgroup log_msg Log message API
21  * @ingroup logger
22  * @{
23  */
24 
25 /** @brief Log argument type.
26  *
27  * Should preferably be equivalent to a native word size.
28  */
29 typedef unsigned long log_arg_t;
30 
31 /** @brief Maximum number of arguments in the standard log entry.
32  *
33  * It is limited by 4 bit nargs field in the log message.
34  */
35 #define LOG_MAX_NARGS 15
36 
37 /** @brief Number of arguments in the log entry which fits in one chunk.*/
38 #ifdef CONFIG_64BIT
39 #define LOG_MSG_NARGS_SINGLE_CHUNK 4U
40 #else
41 #define LOG_MSG_NARGS_SINGLE_CHUNK 3U
42 #endif
43 
44 /** @brief Number of arguments in the head of extended standard log message..*/
45 #define LOG_MSG_NARGS_HEAD_CHUNK \
46 	(LOG_MSG_NARGS_SINGLE_CHUNK - (sizeof(void *)/sizeof(log_arg_t)))
47 
48 /** @brief Maximal amount of bytes in the hexdump entry which fits in one chunk.
49  */
50 #define LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK \
51 	(LOG_MSG_NARGS_SINGLE_CHUNK * sizeof(log_arg_t))
52 
53 /** @brief Number of bytes in the first chunk of hexdump message if message
54  *         consists of more than one chunk.
55  */
56 #define LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK \
57 	(LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK - sizeof(void *))
58 
59 /** @brief Number of bytes that can be stored in chunks following head chunk
60  *         in hexdump log message.
61  */
62 #define HEXDUMP_BYTES_CONT_MSG \
63 	(sizeof(struct log_msg) - sizeof(void *))
64 
65 #define ARGS_CONT_MSG (HEXDUMP_BYTES_CONT_MSG / sizeof(log_arg_t))
66 
67 /** @brief Flag indicating standard log message. */
68 #define LOG_MSG_TYPE_STD 0U
69 
70 /** @brief Flag indicating hexdump log message. */
71 #define LOG_MSG_TYPE_HEXDUMP 1
72 
73 /** @brief Common part of log message header. */
74 #define COMMON_PARAM_HDR() \
75 	uint16_t type : 1;	   \
76 	uint16_t ext : 1
77 
78 /** @brief Number of bits used for storing length of hexdump log message. */
79 #define LOG_MSG_HEXDUMP_LENGTH_BITS 14
80 
81 /** @brief Maximum length of log hexdump message. */
82 #define LOG_MSG_HEXDUMP_MAX_LENGTH (BIT(LOG_MSG_HEXDUMP_LENGTH_BITS) - 1)
83 
84 /** @brief Part of log message header identifying source and level. */
85 struct log_msg_ids {
86 	uint16_t level     : 3;    /*!< Severity. */
87 	uint16_t domain_id : 3;    /*!< Originating domain. */
88 	uint16_t source_id : 10;   /*!< Source ID. */
89 };
90 
91 /** Part of log message header common to standard and hexdump log message. */
92 struct log_msg_generic_hdr {
93 	COMMON_PARAM_HDR();
94 	uint16_t reserved : 14;
95 };
96 
97 /** Part of log message header specific to standard log message. */
98 struct log_msg_std_hdr {
99 	COMMON_PARAM_HDR();
100 	uint16_t reserved : 10;
101 	uint16_t nargs    : 4;
102 };
103 
104 /** Part of log message header specific to hexdump log message. */
105 struct log_msg_hexdump_hdr {
106 	COMMON_PARAM_HDR();
107 	uint16_t length     : LOG_MSG_HEXDUMP_LENGTH_BITS;
108 };
109 
110 /** Log message header structure */
111 struct log_msg_hdr {
112 	atomic_t ref_cnt; /*!< Reference counter for tracking message users. */
113 	union log_msg_hdr_params {
114 		struct log_msg_generic_hdr generic;
115 		struct log_msg_std_hdr std;
116 		struct log_msg_hexdump_hdr hexdump;
117 		uint16_t raw;
118 	} params;
119 	struct log_msg_ids ids; /*!< Identification part of the message.*/
120 	uint32_t timestamp;        /*!< Timestamp. */
121 };
122 
123 /** @brief Data part of log message. */
124 union log_msg_head_data {
125 	log_arg_t args[LOG_MSG_NARGS_SINGLE_CHUNK];
126 	uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK];
127 };
128 
129 /** @brief Data part of extended log message. */
130 struct log_msg_ext_head_data {
131 	struct log_msg_cont *next;
132 	union log_msg_ext_head_data_data {
133 		log_arg_t args[LOG_MSG_NARGS_HEAD_CHUNK];
134 		uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK];
135 	} data;
136 };
137 
138 /** @brief Log message structure. */
139 struct log_msg {
140 	struct log_msg *next;   /*!< Used by logger core list.*/
141 	struct log_msg_hdr hdr; /*!< Message header. */
142 	const char *str;
143 	union log_msg_data {
144 		union log_msg_head_data single;
145 		struct log_msg_ext_head_data ext;
146 	} payload;                 /*!< Message data. */
147 };
148 
149 /** @brief Chunks following message head when message is extended. */
150 struct log_msg_cont {
151 	struct log_msg_cont *next; /*!< Pointer to the next chunk. */
152 	union log_msg_cont_data {
153 		log_arg_t args[ARGS_CONT_MSG];
154 		uint8_t bytes[HEXDUMP_BYTES_CONT_MSG];
155 	} payload;
156 };
157 
158 /** @brief Log message */
159 union log_msg_chunk {
160 	struct log_msg head;
161 	struct log_msg_cont cont;
162 };
163 
164 /** @brief Function for initialization of the log message pool. */
165 void log_msg_pool_init(void);
166 
167 /** @brief Function for indicating that message is in use.
168  *
169  *  @details Message can be used (read) by multiple users. Internal reference
170  *           counter is atomically increased. See @ref log_msg_put.
171  *
172  *  @param msg Message.
173  */
174 void log_msg_get(struct log_msg *msg);
175 
176 /** @brief Function for indicating that message is no longer in use.
177  *
178  *  @details Internal reference counter is atomically decreased. If reference
179  *           counter equals 0 message is freed.
180  *
181  *  @param msg Message.
182  */
183 void log_msg_put(struct log_msg *msg);
184 
185 /** @brief Get domain ID of the message.
186  *
187  * @param msg Message
188  *
189  * @return Domain ID.
190  */
log_msg_domain_id_get(struct log_msg * msg)191 static inline uint32_t log_msg_domain_id_get(struct log_msg *msg)
192 {
193 	return msg->hdr.ids.domain_id;
194 }
195 
196 /** @brief Get source ID (module or instance) of the message.
197  *
198  * @param msg Message
199  *
200  * @return Source ID.
201  */
log_msg_source_id_get(struct log_msg * msg)202 static inline uint32_t log_msg_source_id_get(struct log_msg *msg)
203 {
204 	return msg->hdr.ids.source_id;
205 }
206 
207 /** @brief Get severity level of the message.
208  *
209  * @param msg Message
210  *
211  * @return Severity message.
212  */
log_msg_level_get(struct log_msg * msg)213 static inline uint32_t log_msg_level_get(struct log_msg *msg)
214 {
215 	return msg->hdr.ids.level;
216 }
217 
218 /** @brief Get timestamp of the message.
219  *
220  * @param msg Message
221  *
222  * @return Timestamp value.
223  */
log_msg_timestamp_get(struct log_msg * msg)224 static inline uint32_t log_msg_timestamp_get(struct log_msg *msg)
225 {
226 	return msg->hdr.timestamp;
227 }
228 
229 /** @brief Check if message is of standard type.
230  *
231  * @param msg Message
232  *
233  * @retval true  Standard message.
234  * @retval false Hexdump message.
235  */
log_msg_is_std(struct log_msg * msg)236 static inline bool log_msg_is_std(struct log_msg *msg)
237 {
238 	return  (msg->hdr.params.generic.type == LOG_MSG_TYPE_STD);
239 }
240 
241 /** @brief Returns number of arguments in standard log message.
242  *
243  * @param msg Standard log message.
244  *
245  * @return Number of arguments.
246  */
247 uint32_t log_msg_nargs_get(struct log_msg *msg);
248 
249 /** @brief Gets argument from standard log message.
250  *
251  * @param msg		Standard log message.
252  * @param arg_idx	Argument index.
253  *
254  * @return Argument value or 0 if arg_idx exceeds number of arguments in the
255  *	   message.
256  */
257 log_arg_t log_msg_arg_get(struct log_msg *msg, uint32_t arg_idx);
258 
259 
260 /** @brief Gets pointer to the unformatted string from standard log message.
261  *
262  * @param msg Standard log message.
263  *
264  * @return Pointer to the string.
265  */
266 const char *log_msg_str_get(struct log_msg *msg);
267 
268 /** @brief Allocates chunks for hexdump message and copies the data.
269  *
270  *  @details Function resets header and sets following fields:
271  *		- message type
272  *		- length
273  *
274  *  @note Allocation and partial filling is combined for performance reasons.
275  *
276  * @param str		String.
277  * @param data		Data.
278  * @param length	Data length.
279  *
280  * @return Pointer to allocated head of the message or NULL
281  */
282 struct log_msg *log_msg_hexdump_create(const char *str,
283 				       const uint8_t *data,
284 				       uint32_t length);
285 
286 /** @brief Put data into hexdump log message.
287  *
288  * @param[in]		msg      Message.
289  * @param[in]		data	 Data to be copied.
290  * @param[in, out]	length   Input: requested amount. Output: actual amount.
291  * @param[in]		offset   Offset.
292  */
293 void log_msg_hexdump_data_put(struct log_msg *msg,
294 			      uint8_t *data,
295 			      size_t *length,
296 			      size_t offset);
297 
298 /** @brief Get data from hexdump log message.
299  *
300  * @param[in]		msg      Message.
301  * @param[in]		data	 Buffer for data.
302  * @param[in, out]	length   Input: requested amount. Output: actual amount.
303  * @param[in]		offset   Offset.
304  */
305 void log_msg_hexdump_data_get(struct log_msg *msg,
306 			      uint8_t *data,
307 			      size_t *length,
308 			      size_t offset);
309 
310 union log_msg_chunk *log_msg_no_space_handle(void);
311 
312 /** @brief Allocate single chunk from the pool.
313  *
314  * @return Pointer to the allocated chunk or NULL if failed to allocate.
315  */
316 union log_msg_chunk *log_msg_chunk_alloc(void);
317 
318 /** @brief Allocate chunk for standard log message.
319  *
320  *  @return Allocated chunk of NULL.
321  */
z_log_msg_std_alloc(void)322 static inline struct log_msg *z_log_msg_std_alloc(void)
323 {
324 	struct  log_msg *msg = (struct  log_msg *)log_msg_chunk_alloc();
325 
326 	if (msg != NULL) {
327 		/* all fields reset to 0, reference counter to 1 */
328 		msg->hdr.ref_cnt = 1;
329 		msg->hdr.params.raw = 0U;
330 		msg->hdr.params.std.type = LOG_MSG_TYPE_STD;
331 
332 		if (IS_ENABLED(CONFIG_USERSPACE)) {
333 			/* it may be used in msg_free() function. */
334 			msg->hdr.ids.level = 0;
335 			msg->hdr.ids.domain_id = 0;
336 			msg->hdr.ids.source_id = 0;
337 		}
338 	}
339 
340 	return msg;
341 }
342 
343 /** @brief Create standard log message with no arguments.
344  *
345  *  @details Function resets header and sets following fields:
346  *		- message type
347  *		- string pointer
348  *
349  *  @return Pointer to allocated head of the message or NULL.
350  */
log_msg_create_0(const char * str)351 static inline struct log_msg *log_msg_create_0(const char *str)
352 {
353 	struct log_msg *msg = z_log_msg_std_alloc();
354 
355 	if (msg != NULL) {
356 		msg->str = str;
357 	}
358 
359 	return msg;
360 }
361 
362 /** @brief Create standard log message with one argument.
363  *
364  *  @details Function resets header and sets following fields:
365  *		- message type
366  *		- string pointer
367  *		- number of arguments
368  *		- argument
369  *
370  *  @param str  String.
371  *  @param arg1 Argument.
372  *
373  *  @return Pointer to allocated head of the message or NULL.
374  */
log_msg_create_1(const char * str,log_arg_t arg1)375 static inline struct log_msg *log_msg_create_1(const char *str,
376 					       log_arg_t arg1)
377 {
378 	struct  log_msg *msg = z_log_msg_std_alloc();
379 
380 	if (msg != NULL) {
381 		msg->str = str;
382 		msg->hdr.params.std.nargs = 1U;
383 		msg->payload.single.args[0] = arg1;
384 	}
385 
386 	return msg;
387 }
388 
389 /** @brief Create standard log message with two arguments.
390  *
391  *  @details Function resets header and sets following fields:
392  *		- message type
393  *		- string pointer
394  *		- number of arguments
395  *		- arguments
396  *
397  *  @param str  String.
398  *  @param arg1 Argument 1.
399  *  @param arg2 Argument 2.
400  *
401  *  @return Pointer to allocated head of the message or NULL.
402  */
log_msg_create_2(const char * str,log_arg_t arg1,log_arg_t arg2)403 static inline struct log_msg *log_msg_create_2(const char *str,
404 					       log_arg_t arg1,
405 					       log_arg_t arg2)
406 {
407 	struct  log_msg *msg = z_log_msg_std_alloc();
408 
409 	if (msg != NULL) {
410 		msg->str = str;
411 		msg->hdr.params.std.nargs = 2U;
412 		msg->payload.single.args[0] = arg1;
413 		msg->payload.single.args[1] = arg2;
414 	}
415 
416 	return msg;
417 }
418 
419 /** @brief Create standard log message with three arguments.
420  *
421  *  @details Function resets header and sets following fields:
422  *		- message type
423  *		- string pointer
424  *		- number of arguments
425  *		- arguments
426  *
427  *  @param str  String.
428  *  @param arg1 Argument 1.
429  *  @param arg2 Argument 2.
430  *  @param arg3 Argument 3.
431  *
432  *  @return Pointer to allocated head of the message or NULL.
433  */
log_msg_create_3(const char * str,log_arg_t arg1,log_arg_t arg2,log_arg_t arg3)434 static inline struct log_msg *log_msg_create_3(const char *str,
435 					       log_arg_t arg1,
436 					       log_arg_t arg2,
437 					       log_arg_t arg3)
438 {
439 	struct  log_msg *msg = z_log_msg_std_alloc();
440 
441 	if (msg != NULL) {
442 		msg->str = str;
443 		msg->hdr.params.std.nargs = 3U;
444 		msg->payload.single.args[0] = arg1;
445 		msg->payload.single.args[1] = arg2;
446 		msg->payload.single.args[2] = arg3;
447 	}
448 
449 	return msg;
450 }
451 
452 /** @brief Create standard log message with variable number of arguments.
453  *
454  *  @details Function resets header and sets following fields:
455  *		- message type
456  *		- string pointer
457  *		- number of arguments
458  *		- arguments
459  *
460  *  @param str   String.
461  *  @param args  Array with arguments.
462  *  @param nargs Number of arguments.
463  *
464  *  @return Pointer to allocated head of the message or NULL.
465  */
466 struct log_msg *log_msg_create_n(const char *str,
467 				 log_arg_t *args,
468 				 uint32_t nargs);
469 
470 /**
471  * @brief Get number of free blocks from the log mem pool
472  */
473 uint32_t log_msg_mem_get_free(void);
474 
475 /**
476  * @brief Get number of used blocks from the log mem pool
477  */
478 uint32_t log_msg_mem_get_used(void);
479 
480 /**
481  * @brief Get max used blocks from the log mem pool
482  */
483 uint32_t log_msg_mem_get_max_used(void);
484 
485 
486 /**
487  * @}
488  */
489 
490 #ifdef __cplusplus
491 }
492 #endif
493 
494 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_ */
495