Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
#define ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_

#include <sys/atomic.h>
#include <sys/util.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Log message API
 * @defgroup log_msg Log message API
 * @ingroup logger
 * @{
 */

/** @brief Log argument type.
 *
 * Should preferably be equivalent to a native word size.
 */
typedef unsigned long log_arg_t;

/** @brief Maximum number of arguments in the standard log entry.
 *
 * It is limited by 4 bit nargs field in the log message.
 */
#define LOG_MAX_NARGS 15

/** @brief Number of arguments in the log entry which fits in one chunk.*/
#ifdef CONFIG_64BIT
#define LOG_MSG_NARGS_SINGLE_CHUNK 4U
#else
#define LOG_MSG_NARGS_SINGLE_CHUNK 3U
#endif

/** @brief Number of arguments in the head of extended standard log message..*/
#define LOG_MSG_NARGS_HEAD_CHUNK \
	(LOG_MSG_NARGS_SINGLE_CHUNK - (sizeof(void *)/sizeof(log_arg_t)))

/** @brief Maximal amount of bytes in the hexdump entry which fits in one chunk.
 */
#define LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK \
	(LOG_MSG_NARGS_SINGLE_CHUNK * sizeof(log_arg_t))

/** @brief Number of bytes in the first chunk of hexdump message if message
 *         consists of more than one chunk.
 */
#define LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK \
	(LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK - sizeof(void *))

/** @brief Number of bytes that can be stored in chunks following head chunk
 *         in hexdump log message.
 */
#define HEXDUMP_BYTES_CONT_MSG \
	(sizeof(struct log_msg) - sizeof(void *))

#define ARGS_CONT_MSG (HEXDUMP_BYTES_CONT_MSG / sizeof(log_arg_t))

/** @brief Flag indicating standard log message. */
#define LOG_MSG_TYPE_STD 0U

/** @brief Flag indicating hexdump log message. */
#define LOG_MSG_TYPE_HEXDUMP 1

/** @brief Common part of log message header. */
#define COMMON_PARAM_HDR() \
	uint16_t type : 1;	   \
	uint16_t ext : 1

/** @brief Number of bits used for storing length of hexdump log message. */
#define LOG_MSG_HEXDUMP_LENGTH_BITS 14

/** @brief Maximum length of log hexdump message. */
#define LOG_MSG_HEXDUMP_MAX_LENGTH (BIT(LOG_MSG_HEXDUMP_LENGTH_BITS) - 1)

/** @brief Part of log message header identifying source and level. */
struct log_msg_ids {
	uint16_t level     : 3;    /*!< Severity. */
	uint16_t domain_id : 3;    /*!< Originating domain. */
	uint16_t source_id : 10;   /*!< Source ID. */
};

/** Part of log message header common to standard and hexdump log message. */
struct log_msg_generic_hdr {
	COMMON_PARAM_HDR();
	uint16_t reserved : 14;
};

/** Part of log message header specific to standard log message. */
struct log_msg_std_hdr {
	COMMON_PARAM_HDR();
	uint16_t reserved : 10;
	uint16_t nargs    : 4;
};

/** Part of log message header specific to hexdump log message. */
struct log_msg_hexdump_hdr {
	COMMON_PARAM_HDR();
	uint16_t length     : LOG_MSG_HEXDUMP_LENGTH_BITS;
};

/** Log message header structure */
struct log_msg_hdr {
	atomic_t ref_cnt; /*!< Reference counter for tracking message users. */
	union log_msg_hdr_params {
		struct log_msg_generic_hdr generic;
		struct log_msg_std_hdr std;
		struct log_msg_hexdump_hdr hexdump;
		uint16_t raw;
	} params;
	struct log_msg_ids ids; /*!< Identification part of the message.*/
	uint32_t timestamp;        /*!< Timestamp. */
};

/** @brief Data part of log message. */
union log_msg_head_data {
	log_arg_t args[LOG_MSG_NARGS_SINGLE_CHUNK];
	uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK];
};

/** @brief Data part of extended log message. */
struct log_msg_ext_head_data {
	struct log_msg_cont *next;
	union log_msg_ext_head_data_data {
		log_arg_t args[LOG_MSG_NARGS_HEAD_CHUNK];
		uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK];
	} data;
};

/** @brief Log message structure. */
struct log_msg {
	struct log_msg *next;   /*!< Used by logger core list.*/
	struct log_msg_hdr hdr; /*!< Message header. */
	const char *str;
	union log_msg_data {
		union log_msg_head_data single;
		struct log_msg_ext_head_data ext;
	} payload;                 /*!< Message data. */
};

/** @brief Chunks following message head when message is extended. */
struct log_msg_cont {
	struct log_msg_cont *next; /*!< Pointer to the next chunk. */
	union log_msg_cont_data {
		log_arg_t args[ARGS_CONT_MSG];
		uint8_t bytes[HEXDUMP_BYTES_CONT_MSG];
	} payload;
};

/** @brief Log message */
union log_msg_chunk {
	struct log_msg head;
	struct log_msg_cont cont;
};

/** @brief Function for initialization of the log message pool. */
void log_msg_pool_init(void);

/** @brief Function for indicating that message is in use.
 *
 *  @details Message can be used (read) by multiple users. Internal reference
 *           counter is atomically increased. See @ref log_msg_put.
 *
 *  @param msg Message.
 */
void log_msg_get(struct log_msg *msg);

/** @brief Function for indicating that message is no longer in use.
 *
 *  @details Internal reference counter is atomically decreased. If reference
 *           counter equals 0 message is freed.
 *
 *  @param msg Message.
 */
void log_msg_put(struct log_msg *msg);

/** @brief Get domain ID of the message.
 *
 * @param msg Message
 *
 * @return Domain ID.
 */
static inline uint32_t log_msg_domain_id_get(struct log_msg *msg)
{
	return msg->hdr.ids.domain_id;
}

/** @brief Get source ID (module or instance) of the message.
 *
 * @param msg Message
 *
 * @return Source ID.
 */
static inline uint32_t log_msg_source_id_get(struct log_msg *msg)
{
	return msg->hdr.ids.source_id;
}

/** @brief Get severity level of the message.
 *
 * @param msg Message
 *
 * @return Severity message.
 */
static inline uint32_t log_msg_level_get(struct log_msg *msg)
{
	return msg->hdr.ids.level;
}

/** @brief Get timestamp of the message.
 *
 * @param msg Message
 *
 * @return Timestamp value.
 */
static inline uint32_t log_msg_timestamp_get(struct log_msg *msg)
{
	return msg->hdr.timestamp;
}

/** @brief Check if message is of standard type.
 *
 * @param msg Message
 *
 * @retval true  Standard message.
 * @retval false Hexdump message.
 */
static inline bool log_msg_is_std(struct log_msg *msg)
{
	return  (msg->hdr.params.generic.type == LOG_MSG_TYPE_STD);
}

/** @brief Returns number of arguments in standard log message.
 *
 * @param msg Standard log message.
 *
 * @return Number of arguments.
 */
uint32_t log_msg_nargs_get(struct log_msg *msg);

/** @brief Gets argument from standard log message.
 *
 * @param msg		Standard log message.
 * @param arg_idx	Argument index.
 *
 * @return Argument value or 0 if arg_idx exceeds number of arguments in the
 *	   message.
 */
log_arg_t log_msg_arg_get(struct log_msg *msg, uint32_t arg_idx);


/** @brief Gets pointer to the unformatted string from standard log message.
 *
 * @param msg Standard log message.
 *
 * @return Pointer to the string.
 */
const char *log_msg_str_get(struct log_msg *msg);

/** @brief Allocates chunks for hexdump message and copies the data.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- length
 *
 *  @note Allocation and partial filling is combined for performance reasons.
 *
 * @param str		String.
 * @param data		Data.
 * @param length	Data length.
 *
 * @return Pointer to allocated head of the message or NULL
 */
struct log_msg *log_msg_hexdump_create(const char *str,
				       const uint8_t *data,
				       uint32_t length);

/** @brief Put data into hexdump log message.
 *
 * @param[in]		msg      Message.
 * @param[in]		data	 Data to be copied.
 * @param[in, out]	length   Input: requested amount. Output: actual amount.
 * @param[in]		offset   Offset.
 */
void log_msg_hexdump_data_put(struct log_msg *msg,
			      uint8_t *data,
			      size_t *length,
			      size_t offset);

/** @brief Get data from hexdump log message.
 *
 * @param[in]		msg      Message.
 * @param[in]		data	 Buffer for data.
 * @param[in, out]	length   Input: requested amount. Output: actual amount.
 * @param[in]		offset   Offset.
 */
void log_msg_hexdump_data_get(struct log_msg *msg,
			      uint8_t *data,
			      size_t *length,
			      size_t offset);

union log_msg_chunk *log_msg_no_space_handle(void);

/** @brief Allocate single chunk from the pool.
 *
 * @return Pointer to the allocated chunk or NULL if failed to allocate.
 */
union log_msg_chunk *log_msg_chunk_alloc(void);

/** @brief Allocate chunk for standard log message.
 *
 *  @return Allocated chunk of NULL.
 */
static inline struct log_msg *z_log_msg_std_alloc(void)
{
	struct  log_msg *msg = (struct  log_msg *)log_msg_chunk_alloc();

	if (msg != NULL) {
		/* all fields reset to 0, reference counter to 1 */
		msg->hdr.ref_cnt = 1;
		msg->hdr.params.raw = 0U;
		msg->hdr.params.std.type = LOG_MSG_TYPE_STD;

		if (IS_ENABLED(CONFIG_USERSPACE)) {
			/* it may be used in msg_free() function. */
			msg->hdr.ids.level = 0;
			msg->hdr.ids.domain_id = 0;
			msg->hdr.ids.source_id = 0;
		}
	}

	return msg;
}

/** @brief Create standard log message with no arguments.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- string pointer
 *
 *  @return Pointer to allocated head of the message or NULL.
 */
static inline struct log_msg *log_msg_create_0(const char *str)
{
	struct log_msg *msg = z_log_msg_std_alloc();

	if (msg != NULL) {
		msg->str = str;
	}

	return msg;
}

/** @brief Create standard log message with one argument.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- string pointer
 *		- number of arguments
 *		- argument
 *
 *  @param str  String.
 *  @param arg1 Argument.
 *
 *  @return Pointer to allocated head of the message or NULL.
 */
static inline struct log_msg *log_msg_create_1(const char *str,
					       log_arg_t arg1)
{
	struct  log_msg *msg = z_log_msg_std_alloc();

	if (msg != NULL) {
		msg->str = str;
		msg->hdr.params.std.nargs = 1U;
		msg->payload.single.args[0] = arg1;
	}

	return msg;
}

/** @brief Create standard log message with two arguments.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- string pointer
 *		- number of arguments
 *		- arguments
 *
 *  @param str  String.
 *  @param arg1 Argument 1.
 *  @param arg2 Argument 2.
 *
 *  @return Pointer to allocated head of the message or NULL.
 */
static inline struct log_msg *log_msg_create_2(const char *str,
					       log_arg_t arg1,
					       log_arg_t arg2)
{
	struct  log_msg *msg = z_log_msg_std_alloc();

	if (msg != NULL) {
		msg->str = str;
		msg->hdr.params.std.nargs = 2U;
		msg->payload.single.args[0] = arg1;
		msg->payload.single.args[1] = arg2;
	}

	return msg;
}

/** @brief Create standard log message with three arguments.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- string pointer
 *		- number of arguments
 *		- arguments
 *
 *  @param str  String.
 *  @param arg1 Argument 1.
 *  @param arg2 Argument 2.
 *  @param arg3 Argument 3.
 *
 *  @return Pointer to allocated head of the message or NULL.
 */
static inline struct log_msg *log_msg_create_3(const char *str,
					       log_arg_t arg1,
					       log_arg_t arg2,
					       log_arg_t arg3)
{
	struct  log_msg *msg = z_log_msg_std_alloc();

	if (msg != NULL) {
		msg->str = str;
		msg->hdr.params.std.nargs = 3U;
		msg->payload.single.args[0] = arg1;
		msg->payload.single.args[1] = arg2;
		msg->payload.single.args[2] = arg3;
	}

	return msg;
}

/** @brief Create standard log message with variable number of arguments.
 *
 *  @details Function resets header and sets following fields:
 *		- message type
 *		- string pointer
 *		- number of arguments
 *		- arguments
 *
 *  @param str   String.
 *  @param args  Array with arguments.
 *  @param nargs Number of arguments.
 *
 *  @return Pointer to allocated head of the message or NULL.
 */
struct log_msg *log_msg_create_n(const char *str,
				 log_arg_t *args,
				 uint32_t nargs);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_ */