1 /*
2  * Copyright (c) 2019 Intel corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* Disable syscall tracing for all calls from this compilation unit to avoid
8  * undefined symbols as the macros are not expanded recursively
9  */
10 #define DISABLE_SYSCALL_TRACING
11 
12 #include <zephyr/init.h>
13 #include <string.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/sys/atomic.h>
17 #include <tracing_core.h>
18 #include <tracing_buffer.h>
19 #include <tracing_backend.h>
20 
21 #define TRACING_CMD_ENABLE  "enable"
22 #define TRACING_CMD_DISABLE "disable"
23 
24 enum tracing_state {
25 	TRACING_DISABLE = 0,
26 	TRACING_ENABLE
27 };
28 
29 static atomic_t tracing_state;
30 static atomic_t tracing_packet_drop_num;
31 static struct tracing_backend *working_backend;
32 
33 #ifdef CONFIG_TRACING_ASYNC
34 #define TRACING_THREAD_NAME "tracing_thread"
35 
36 static k_tid_t tracing_thread_tid;
37 static struct k_thread tracing_thread;
38 static struct k_timer tracing_thread_timer;
39 static K_SEM_DEFINE(tracing_thread_sem, 0, 1);
40 static K_THREAD_STACK_DEFINE(tracing_thread_stack,
41 			CONFIG_TRACING_THREAD_STACK_SIZE);
42 
tracing_thread_func(void * dummy1,void * dummy2,void * dummy3)43 static void tracing_thread_func(void *dummy1, void *dummy2, void *dummy3)
44 {
45 	uint8_t *transferring_buf;
46 	uint32_t transferring_length, tracing_buffer_max_length;
47 
48 	tracing_thread_tid = k_current_get();
49 
50 	tracing_buffer_max_length = tracing_buffer_capacity_get();
51 
52 	while (true) {
53 		if (tracing_buffer_is_empty()) {
54 			k_sem_take(&tracing_thread_sem, K_FOREVER);
55 		} else {
56 			transferring_length =
57 				tracing_buffer_get_claim(
58 						&transferring_buf,
59 						tracing_buffer_max_length);
60 			tracing_buffer_handle(transferring_buf,
61 					      transferring_length);
62 			tracing_buffer_get_finish(transferring_length);
63 		}
64 	}
65 }
66 
tracing_thread_timer_expiry_fn(struct k_timer * timer)67 static void tracing_thread_timer_expiry_fn(struct k_timer *timer)
68 {
69 	k_sem_give(&tracing_thread_sem);
70 }
71 #endif
72 
tracing_set_state(enum tracing_state state)73 static void tracing_set_state(enum tracing_state state)
74 {
75 	atomic_set(&tracing_state, state);
76 }
77 
tracing_init(void)78 static int tracing_init(void)
79 {
80 
81 	tracing_buffer_init();
82 
83 	working_backend = tracing_backend_get(CONFIG_TRACING_BACKEND_NAME);
84 	tracing_backend_init(working_backend);
85 
86 	atomic_set(&tracing_packet_drop_num, 0);
87 
88 	if (IS_ENABLED(CONFIG_TRACING_HANDLE_HOST_CMD)) {
89 		tracing_set_state(TRACING_DISABLE);
90 	} else {
91 		tracing_set_state(TRACING_ENABLE);
92 	}
93 
94 #ifdef CONFIG_TRACING_ASYNC
95 	k_timer_init(&tracing_thread_timer,
96 		     tracing_thread_timer_expiry_fn, NULL);
97 
98 	k_thread_create(&tracing_thread, tracing_thread_stack,
99 			K_THREAD_STACK_SIZEOF(tracing_thread_stack),
100 			tracing_thread_func, NULL, NULL, NULL,
101 			K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT);
102 	k_thread_name_set(&tracing_thread, TRACING_THREAD_NAME);
103 #endif
104 
105 	return 0;
106 }
107 
108 SYS_INIT(tracing_init, APPLICATION, 0);
109 
110 #ifdef CONFIG_TRACING_ASYNC
tracing_trigger_output(bool before_put_is_empty)111 void tracing_trigger_output(bool before_put_is_empty)
112 {
113 	if (before_put_is_empty) {
114 		k_timer_start(&tracing_thread_timer,
115 			      K_MSEC(CONFIG_TRACING_THREAD_WAIT_THRESHOLD),
116 			      K_NO_WAIT);
117 	}
118 }
119 
is_tracing_thread(void)120 bool is_tracing_thread(void)
121 {
122 	return (!k_is_in_isr() && (k_current_get() == tracing_thread_tid));
123 }
124 #endif
125 
is_tracing_enabled(void)126 bool is_tracing_enabled(void)
127 {
128 	return atomic_get(&tracing_state) == TRACING_ENABLE;
129 }
130 
tracing_cmd_handle(uint8_t * buf,uint32_t length)131 void tracing_cmd_handle(uint8_t *buf, uint32_t length)
132 {
133 	if (strncmp(buf, TRACING_CMD_ENABLE, length) == 0) {
134 		tracing_set_state(TRACING_ENABLE);
135 	} else if (strncmp(buf, TRACING_CMD_DISABLE, length) == 0) {
136 		tracing_set_state(TRACING_DISABLE);
137 	}
138 }
139 
tracing_buffer_handle(uint8_t * data,uint32_t length)140 void tracing_buffer_handle(uint8_t *data, uint32_t length)
141 {
142 	tracing_backend_output(working_backend, data, length);
143 }
144 
tracing_packet_drop_handle(void)145 void tracing_packet_drop_handle(void)
146 {
147 	atomic_inc(&tracing_packet_drop_num);
148 }
149