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 #ifdef CONFIG_TRACING_BACKEND_UART
25 #define TRACING_BACKEND_NAME "tracing_backend_uart"
26 #elif defined CONFIG_TRACING_BACKEND_USB
27 #define TRACING_BACKEND_NAME "tracing_backend_usb"
28 #elif defined CONFIG_TRACING_BACKEND_POSIX
29 #define TRACING_BACKEND_NAME "tracing_backend_posix"
30 #elif defined CONFIG_TRACING_BACKEND_RAM
31 #define TRACING_BACKEND_NAME "tracing_backend_ram"
32 #elif defined CONFIG_TRACING_BACKEND_ADSP_MEMORY_WINDOW
33 #define TRACING_BACKEND_NAME "tracing_backend_adsp_memory_window"
34 #else
35 #define TRACING_BACKEND_NAME ""
36 #endif
37 
38 enum tracing_state {
39 	TRACING_DISABLE = 0,
40 	TRACING_ENABLE
41 };
42 
43 static atomic_t tracing_state;
44 static atomic_t tracing_packet_drop_num;
45 static struct tracing_backend *working_backend;
46 
47 #ifdef CONFIG_TRACING_ASYNC
48 #define TRACING_THREAD_NAME "tracing_thread"
49 
50 static k_tid_t tracing_thread_tid;
51 static struct k_thread tracing_thread;
52 static struct k_timer tracing_thread_timer;
53 static K_SEM_DEFINE(tracing_thread_sem, 0, 1);
54 static K_THREAD_STACK_DEFINE(tracing_thread_stack,
55 			CONFIG_TRACING_THREAD_STACK_SIZE);
56 
tracing_thread_func(void * dummy1,void * dummy2,void * dummy3)57 static void tracing_thread_func(void *dummy1, void *dummy2, void *dummy3)
58 {
59 	uint8_t *transferring_buf;
60 	uint32_t transferring_length, tracing_buffer_max_length;
61 
62 	tracing_thread_tid = k_current_get();
63 
64 	tracing_buffer_max_length = tracing_buffer_capacity_get();
65 
66 	while (true) {
67 		if (tracing_buffer_is_empty()) {
68 			k_sem_take(&tracing_thread_sem, K_FOREVER);
69 		} else {
70 			transferring_length =
71 				tracing_buffer_get_claim(
72 						&transferring_buf,
73 						tracing_buffer_max_length);
74 			tracing_buffer_handle(transferring_buf,
75 					      transferring_length);
76 			tracing_buffer_get_finish(transferring_length);
77 		}
78 	}
79 }
80 
tracing_thread_timer_expiry_fn(struct k_timer * timer)81 static void tracing_thread_timer_expiry_fn(struct k_timer *timer)
82 {
83 	k_sem_give(&tracing_thread_sem);
84 }
85 #endif
86 
tracing_set_state(enum tracing_state state)87 static void tracing_set_state(enum tracing_state state)
88 {
89 	atomic_set(&tracing_state, state);
90 }
91 
tracing_init(void)92 static int tracing_init(void)
93 {
94 
95 	tracing_buffer_init();
96 
97 	working_backend = tracing_backend_get(TRACING_BACKEND_NAME);
98 	tracing_backend_init(working_backend);
99 
100 	atomic_set(&tracing_packet_drop_num, 0);
101 
102 	if (IS_ENABLED(CONFIG_TRACING_HANDLE_HOST_CMD)) {
103 		tracing_set_state(TRACING_DISABLE);
104 	} else {
105 		tracing_set_state(TRACING_ENABLE);
106 	}
107 
108 #ifdef CONFIG_TRACING_ASYNC
109 	k_timer_init(&tracing_thread_timer,
110 		     tracing_thread_timer_expiry_fn, NULL);
111 
112 	k_thread_create(&tracing_thread, tracing_thread_stack,
113 			K_THREAD_STACK_SIZEOF(tracing_thread_stack),
114 			tracing_thread_func, NULL, NULL, NULL,
115 			K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT);
116 	k_thread_name_set(&tracing_thread, TRACING_THREAD_NAME);
117 #endif
118 
119 	return 0;
120 }
121 
122 SYS_INIT(tracing_init, APPLICATION, 0);
123 
124 #ifdef CONFIG_TRACING_ASYNC
tracing_trigger_output(bool before_put_is_empty)125 void tracing_trigger_output(bool before_put_is_empty)
126 {
127 	if (before_put_is_empty) {
128 		k_timer_start(&tracing_thread_timer,
129 			      K_MSEC(CONFIG_TRACING_THREAD_WAIT_THRESHOLD),
130 			      K_NO_WAIT);
131 	}
132 }
133 
is_tracing_thread(void)134 bool is_tracing_thread(void)
135 {
136 	return (!k_is_in_isr() && (k_current_get() == tracing_thread_tid));
137 }
138 #endif
139 
is_tracing_enabled(void)140 bool is_tracing_enabled(void)
141 {
142 	return atomic_get(&tracing_state) == TRACING_ENABLE;
143 }
144 
tracing_cmd_handle(uint8_t * buf,uint32_t length)145 void tracing_cmd_handle(uint8_t *buf, uint32_t length)
146 {
147 	if (strncmp(buf, TRACING_CMD_ENABLE, length) == 0) {
148 		tracing_set_state(TRACING_ENABLE);
149 	} else if (strncmp(buf, TRACING_CMD_DISABLE, length) == 0) {
150 		tracing_set_state(TRACING_DISABLE);
151 	}
152 }
153 
tracing_buffer_handle(uint8_t * data,uint32_t length)154 void tracing_buffer_handle(uint8_t *data, uint32_t length)
155 {
156 	tracing_backend_output(working_backend, data, length);
157 }
158 
tracing_packet_drop_handle(void)159 void tracing_packet_drop_handle(void)
160 {
161 	atomic_inc(&tracing_packet_drop_num);
162 }
163