1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 * Description: LOG UART MODULE
15 * Author:
16 * Create:
17 */
18 #if defined USE_CMSIS_OS
19 #include <string.h>
20 #ifdef USE_OSAL_INSTEAD_CMSIS
21 #include "soc_osal.h"
22 #include "los_sched_pri.h"
23 #else
24 #include "cmsis_os2.h"
25 #endif
26 #include "core.h"
27 #if CORE == MASTER_BY_ALL
28 #include "stdio.h"
29 #if (CORE_NUMS > 1)
30 #include "watchdog.h"
31 #endif
32 #include "hal_uart.h"
33 #endif
34 #ifdef TEST_SUITE
35 #include "test_suite_uart.h"
36 #endif
37 #include "log_panic.h"
38 #include "log_buffer.h"
39 #include "log_buffer_reader.h"
40 #include "log_trigger.h"
41 #include "panic.h"
42 #include "non_os.h"
43 #ifdef SUPPORT_IPC
44 #include "ipc.h"
45 #endif
46
47 #include "uart.h"
48 #if defined(CONFIG_UART_SUPPORT_DMA)
49 #include "dma.h"
50 #endif /* CONFIG_UART_SUPPORT_DMA */
51 #include "log_uart_porting.h"
52 #include "log_uart.h"
53 #ifdef HSO_SUPPORT
54 #include "securec.h"
55 #include "diag_adapt_sdt.h"
56 #endif
57 #ifdef IPC_NEW
58 #include "ipc.h"
59 #include "ipc_porting.h"
60 #endif
61 #include "diag_log.h"
62 #include "dfx_adapt_layer.h"
63
64 /**
65 * Security core logging watermark level.
66 * When the level is under the watermark and the Security core goes to sleep the log will stop until retriggered. */
67 static uint16_t g_log_uart_security_log_watermark = LOG_UART_LOG_WATERMARK_VALUE_ON_INIT;
68
69 /** Time(ms) of the oldest message left in the logging buffer. */
70 #define OLDEST_MESSAGE_IN_BUFFER 1000
71
72 static uint8_t g_uart_log_rx_buffer_test[LOG_UART_RX_MAX_BUFFER_SIZE];
73 #ifdef SW_UART_DEBUG
74 #ifndef SW_UART_BAUDRATE
75 #define SW_UART_BAUDRATE 115200UL
76 #endif
77 #endif
78
79 /** UART Settings. Define these in the C file to avoid pulling in the UART header in the header file. */
80 #define LOG_UART_BAUD_RATE 115200
81 #define LOG_UART_DATA_BITS UART_DATA_BIT_8
82 #define LOG_UART_STOP_BITS UART_STOP_BIT_1
83 #define LOG_UART_PARITY UART_PARITY_NONE
84
85 /** Number of milliseconds to delay the trigger of a new UART write in case the UART is busy */
86 #define LOG_UART_DELAY_ON_UART_BUSY 1
87 #if CORE == MASTER_BY_ALL
88
89 /** Mutex protecting accesses to the circular buffer. */
90 #ifdef USE_OSAL_INSTEAD_CMSIS
91 static osal_semaphore g_semaphore_uart = { NULL };
92 static osal_semaphore g_semaphore_logs = { NULL };
93 #else
94 static osSemaphoreId_t g_semaphore_uart = NULL;
95 static osSemaphoreId_t g_semaphore_logs = NULL;
96 #endif
97
98 /** UART Handle */
99 static uart_bus_t g_log_uart = LOG_UART_BUS;
100
101 #if defined(CONFIG_UART_SUPPORT_DMA)
102 #define DMA_UART_TRANSFER_WIDTH_WORD 4
103 #define DMA_UART_TRANSFER_WIDTH_HALF_WORD 2
104 #define DMA_UART_TRANSFER_WIDTH_8 0
105 #define DMA_UART_TRANSFER_WIDTH_16 1
106 #define DMA_UART_TRANSFER_WIDTH_32 2
107 #define DMA_UART_BURST_TRANSACTION_LENGTH_8 2
108 #endif /* CONFIG_UART_SUPPORT_DMA */
109
110 /* Local function prototypes. */
111 static void log_uart_tx_isr_callback(const void *buffer, uint32_t length, const void *params);
112
113 /**
114 * This handler gets called when one of the cores wants to trigger the log reader
115 * @param message The IPC message
116 * @param payload_p The payload, contains the reset reason
117 * @param src The core who has just started
118 * @param id The message ID (should always be 0 - the first message after starting)
119 * @return
120 */
121 #if (CORE_NUMS > 1) && defined(IPC_NEW)
log_reader_info_action_handler(uint8_t * payload_addr,uint32_t payload_len)122 static void log_reader_info_action_handler(uint8_t *payload_addr, uint32_t payload_len)
123 {
124 unused(payload_addr);
125 unused(payload_len);
126 log_uart_trigger();
127 }
128 #elif (CORE_NUMS > 1) && (defined CONFIG_DFX_SUPPORT_CUSTOM_LOG) && (CONFIG_DFX_SUPPORT_CUSTOM_LOG == DFX_YES)
log_reader_info_action_handler(void)129 void log_reader_info_action_handler(void)
130 {
131 dfx_log_reader_irq_clr(); /* Clear Software interrupt. */
132 log_uart_trigger();
133 }
134
135 #elif (CORE_NUMS > 1)
log_reader_info_action_handler(ipc_action_t message,const volatile ipc_payload * payload_p,cores_t src,uint32_t id)136 static bool log_reader_info_action_handler(ipc_action_t message,
137 const volatile ipc_payload *payload_p, cores_t src, uint32_t id)
138 {
139 unused(message);
140 unused(id);
141 unused(payload_p);
142 unused(src);
143 log_uart_trigger();
144 return true;
145 }
146 #endif
147
148 /* Initialise the UART and open it at the specified speed! */
log_uart_init(void)149 void log_uart_init(void)
150 {
151 #if (CORE_NUMS > 1)
152 unused(log_reader_info_action_handler);
153 #endif
154
155 /* Configure and open the UART port for use. */
156 uart_pin_config_t log_uart_pins = {
157 .tx_pin = CODELOADER_UART_TX_PIN, /* TEST_SUITE_UART_TX_PIN */
158 .rx_pin = CODELOADER_UART_RX_PIN, /* TEST_SUITE_UART_RX_PIN */
159 .cts_pin = PIN_NONE,
160 .rts_pin = PIN_NONE
161 };
162
163 uart_attr_t uart_line_config = {
164 .baud_rate = LOG_UART_BAUD_RATE,
165 .data_bits = LOG_UART_DATA_BITS,
166 .stop_bits = LOG_UART_STOP_BITS,
167 .parity = LOG_UART_PARITY
168 };
169 uart_buffer_config_t uart_buffer_config;
170
171 uart_buffer_config.rx_buffer_size = LOG_UART_RX_MAX_BUFFER_SIZE;
172 uart_buffer_config.rx_buffer = g_uart_log_rx_buffer_test;
173
174 /* Open and configure the UART */
175 g_log_uart = LOG_UART_BUS;
176 #if defined(CONFIG_UART_SUPPORT_DMA)
177 uart_extra_attr_t extra_attr = {
178 .tx_dma_enable = 1,
179 .tx_int_threshold = 0,
180 .rx_dma_enable = 1,
181 .rx_int_threshold = 0
182 };
183
184 uapi_dma_init();
185 uapi_dma_open();
186 (void)uapi_uart_init(LOG_UART_BUS, &log_uart_pins, &uart_line_config, &extra_attr, &uart_buffer_config);
187 #else
188 (void)uapi_uart_init(LOG_UART_BUS, &log_uart_pins, &uart_line_config, NULL, &uart_buffer_config);
189 #endif /* CONFIG_UART_SUPPORT_DMA */
190
191 #if SYS_DEBUG_MODE_ENABLE == YES
192 uapi_uart_register_rx_callback(LOG_UART_BUS, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
193 LOG_UART_RX_MAX_BUFFER_SIZE, log_uart_rx_callback);
194 #endif
195 }
196
log_uart_send_buffer(const uint8_t * buffer,uint16_t length)197 void log_uart_send_buffer(const uint8_t *buffer, uint16_t length)
198 {
199 uapi_uart_write(g_log_uart, (const void *)buffer, length, 0);
200 }
201
log_uart_update_watermark_level(log_memory_region_section_t log_mem_region,uint16_t new_watermark_val)202 void log_uart_update_watermark_level(log_memory_region_section_t log_mem_region, uint16_t new_watermark_val)
203 {
204 #if CORE_NUMS > 1
205 if (log_mem_region == LOG_MEMORY_REGION_SECTION_1) {
206 g_log_uart_security_log_watermark = new_watermark_val;
207 }
208 #else
209 if (log_mem_region == LOG_MEMORY_REGION_SECTION_0) {
210 g_log_uart_security_log_watermark = new_watermark_val;
211 }
212 #endif
213 }
214
215 /* Initialises the UART when RTOS functions are available. This should be called before the RTOS scheduler starts,
216 * but when we can create the mutex.
217 */
218 // Run after OS, but before threads are started, so in a single thread.
log_uart_init_after_rtos(void)219 void log_uart_init_after_rtos(void)
220 {
221 /* Create the mutex used to control logs written to . */
222 #ifdef USE_OSAL_INSTEAD_CMSIS
223 osal_sem_binary_sem_init(&g_semaphore_logs, 1);
224 if (g_semaphore_logs.sem == NULL) {
225 #else
226 g_semaphore_logs = osSemaphoreNew(1, 0, NULL);
227 if (!g_semaphore_logs) {
228 #endif
229 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
230 return;
231 }
232 register_log_trigger(log_uart_trigger);
233
234 #ifdef USE_OSAL_INSTEAD_CMSIS
235 osal_sem_binary_sem_init(&g_semaphore_uart, 1);
236 if (g_semaphore_uart.sem == NULL) {
237 #else
238 g_semaphore_uart = osSemaphoreNew(1, 0, NULL);
239 if (!g_semaphore_uart) {
240 #endif
241
242 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
243 return;
244 }
245
246 log_reader_ret_t lret = log_buffer_reader_init();
247 if (lret != LOG_READER_RET_OK) {
248 panic(PANIC_LOG, __LINE__);
249 return;
250 }
251
252 // Register IPC handler to handle log trigger notifications from other cores
253 #if (CORE_NUMS > 1) && defined(IPC_NEW)
254 if (non_os_is_driver_initialised(DRIVER_INIT_IPC) == false) {
255 uapi_ipc_init();
256 }
257 ipc_rx_handler_info_t handler_info;
258 handler_info.msg_id = IPC_MSG_LOG_INFO;
259 handler_info.cb = log_reader_info_action_handler;
260 (void)uapi_ipc_register_rx_handler(&handler_info);
261 #elif (CORE_NUMS > 1) && (defined CONFIG_DFX_SUPPORT_CUSTOM_LOG) && (CONFIG_DFX_SUPPORT_CUSTOM_LOG == DFX_YES)
262 dfx_log_read_info_init();
263 #elif (CORE_NUMS > 1)
264 if (non_os_is_driver_initialised(DRIVER_INIT_IPC) == false) {
265 ipc_init();
266 }
267
268 ipc_register_handler(IPC_ACTION_LOG_INFO, log_reader_info_action_handler);
269 #endif
270 }
271
272 /*
273 * UART has trasnmitted some data. Call in interrupt context,
274 * simply schedule the read index update and additional data check.
275 */
276 static void log_uart_tx_isr_callback(const void *buffer, uint32_t length, const void *params)
277 {
278 unused(buffer);
279 unused(params);
280 unused(length);
281
282 /* Pass the amount of data actually transmitted, so we can update the read pointer. */
283 #ifdef USE_OSAL_INSTEAD_CMSIS
284 osal_sem_up(&g_semaphore_uart);
285 #else
286 (void)osSemaphoreRelease(g_semaphore_uart);
287 #endif
288 }
289
290 void log_uart_trigger(void)
291 {
292 /* Give the semaphore to ensure the main logging task will be active */
293 #ifdef USE_OSAL_INSTEAD_CMSIS
294 osal_sem_up(&g_semaphore_logs);
295 #else
296 (void)osSemaphoreRelease(g_semaphore_logs);
297 #endif
298 }
299
300 #if defined(CONFIG_UART_SUPPORT_DMA)
301 static inline bool uart_dma_align_check_word(uint32_t data_buf, uint32_t data_len, uint32_t align_data)
302 {
303 bool ret1 = (data_buf % align_data) == 0 ? true : false;
304 bool ret2 = (data_len % align_data) == 0 ? true : false;
305 return ret1 && ret2;
306 }
307
308 static uint8_t uart_dma_get_mem_width(uint32_t buff, uint32_t bytes)
309 {
310 if (uart_dma_align_check_word(buff, bytes, (uint32_t)DMA_UART_TRANSFER_WIDTH_WORD)) {
311 return DMA_UART_TRANSFER_WIDTH_32;
312 }
313 if (uart_dma_align_check_word(buff, bytes, (uint32_t)DMA_UART_TRANSFER_WIDTH_HALF_WORD)) {
314 return DMA_UART_TRANSFER_WIDTH_16;
315 }
316 return DMA_UART_TRANSFER_WIDTH_8;
317 }
318
319 static uart_write_dma_config_t dma_cfg = { 0 };
320 static void log_uart_write_blocking_dma(const void *buf, uint32_t len)
321 {
322 dma_cfg.src_width = uart_dma_get_mem_width((uint32_t)(uintptr_t)buf, len);
323 dma_cfg.dest_width = DMA_UART_TRANSFER_WIDTH_8;
324 dma_cfg.burst_length = DMA_UART_BURST_TRANSACTION_LENGTH_8;
325 if (uapi_uart_write_by_dma(g_log_uart, buf, (uint16_t)len, &dma_cfg) != (int32_t)len) {
326 return;
327 }
328 while (uapi_uart_has_pending_transmissions(g_log_uart)) {};
329 }
330 #endif /* CONFIG_UART_SUPPORT_DMA */
331
332 static void log_uart_write_blocking_int(const void *buf, uint32_t len)
333 {
334 // Write The buffer to the uart
335 while (uapi_uart_write_int(g_log_uart, buf, (uint16_t)len, NULL, log_uart_tx_isr_callback) != ERRCODE_SUCC) {
336 // If it was unsuccessful try again after some ticks
337 #ifdef USE_OSAL_INSTEAD_CMSIS
338 if (OS_SCHEDULER_ALL_ACTIVE) {
339 (void)osal_msleep(LOG_UART_DELAY_ON_UART_BUSY);
340 }
341 #else
342 if (osKernelGetState() == osKernelRunning) {
343 (void)osDelay(LOG_UART_DELAY_ON_UART_BUSY);
344 }
345 #endif
346 }
347
348 // Wait until the uart write has been completed
349 #ifdef USE_OSAL_INSTEAD_CMSIS
350 if (OS_SCHEDULER_ALL_ACTIVE && osal_sem_down(&g_semaphore_uart) != osOK) {
351 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
352 return;
353 }
354 #else
355 if (osKernelGetState() == osKernelRunning && osSemaphoreAcquire(g_semaphore_uart, osWaitForever) != osOK) {
356 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
357 return;
358 }
359 #endif
360 else {
361 while (uapi_uart_has_pending_transmissions(g_log_uart)) {};
362 }
363 }
364
365 void log_uart_write_blocking(const void *buf, uint32_t len)
366 {
367 #if defined(CONFIG_UART_SUPPORT_DMA)
368 if (len <= CONFIG_UART_FIFO_DEPTH) {
369 log_uart_write_blocking_int(buf, len);
370 } else {
371 log_uart_write_blocking_dma(buf, len);
372 }
373 #else
374 log_uart_write_blocking_int(buf, len);
375 #endif /* CONFIG_UART_SUPPORT_DMA */
376 }
377
378 #define IBRD_NEED_BAUD_OFFSET_NUM 3
379 #define REMAINDER_NEED_BAUD_OFFSET_NUM 3
380 #define FBRD_NEED_REMAINDER_OFFSET_NUM 4
381
382 static void log_uart_set_baud_rate(uart_bus_t bus, uint32_t baud)
383 {
384 uart_attr_t uart_line_config = {
385 .baud_rate = baud,
386 .data_bits = LOG_UART_DATA_BITS,
387 .stop_bits = LOG_UART_STOP_BITS,
388 .parity = LOG_UART_PARITY
389 };
390 uapi_uart_set_attr(bus, &uart_line_config);
391 }
392
393 void log_uart_reset_baud_rate(void)
394 {
395 log_uart_set_baud_rate(LOG_UART_BUS, LOG_UART_BAUD_RATE);
396
397 #ifdef SW_UART_DEBUG
398 log_uart_set_baud_rate(SW_DEBUG_UART_BUS, SW_UART_BAUDRATE);
399 #endif
400 #ifdef TEST_SUITE
401 log_uart_set_baud_rate(TEST_SUITE_UART_BUS, TEST_SUITE_UART_BAUD_RATE);
402 #endif
403 }
404
405 void log_main(const void *unused_p)
406 {
407 unused(unused_p);
408
409 log_reader_ret_t lr_ret;
410 log_memory_region_section_t lregion;
411 log_buffer_header_t lb_header = { 0 };
412 uint8_t *b1 = NULL;
413 uint32_t l1 = 0;
414 uint8_t *b2 = NULL;
415 uint32_t l2 = 0;
416
417 for (;;) {
418 // Check if there are messages
419 while (log_buffer_reader_lock_next(&lregion, &lb_header) == LOG_READER_RET_OK) {
420 // Claim the message available
421 lr_ret = log_buffer_reader_claim_next(lregion, &b1, &l1, &b2, &l2);
422 // we are sure there is a new message
423 if ((lr_ret != LOG_READER_RET_OK) || ((lb_header.length - sizeof(lb_header)) != (l1 + l2))) {
424 uapi_diag_error_log(0, "[log_uart]data error, r1=0x%x, len1=0x%x, r2=0x%x, len2=0x%x",
425 (uintptr_t)b1, l1, (uintptr_t)b2, l2);
426 log_buffer_reader_error_recovery(lregion);
427 break;
428 }
429 #ifdef HSO_SUPPORT
430 zdiag_adapt_sdt_msg_proc(b1, l1, b2, l2);
431 #else
432 /* Copy SYNC, TIME, SEQUENCE and MSG to circular buffer. */
433 if ((g_log_uart != UART_BUS_NONE) && (l1 > 0)) {
434 log_uart_write_blocking((const void *)b1, l1);
435 }
436 if ((g_log_uart != UART_BUS_NONE) && (l2 > 0)) {
437 log_uart_write_blocking((const void *)b2, l2);
438 }
439 #endif
440 log_buffer_reader_discard(lregion);
441 dfx_watchdog_kick();
442 }
443 // If there has been log indicator get run again
444 #ifdef USE_OSAL_INSTEAD_CMSIS
445 if (OS_SCHEDULER_ALL_ACTIVE && osal_sem_down(&g_semaphore_logs) != OSAL_SUCCESS) {
446 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
447 }
448 #else
449 if (osKernelGetState() == osKernelRunning && osSemaphoreAcquire(g_semaphore_logs, osWaitForever) != osOK) {
450 panic(PANIC_LOG, LOG_PANIC_MUTEX_NOT_READY);
451 }
452 #endif
453 }
454 }
455 #endif
456
457 #endif // defined USE_CMSIS_OS
458