1 /*
2  * Copyright (c) 2023 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/sys/util.h>
9 
10 #include <zephyr/debug/coredump.h>
11 #include "coredump_internal.h"
12 
13 #include <zephyr/logging/log.h>
14 #include <zephyr/logging/log_ctrl.h>
15 #include <adsp_memory.h>
16 #include <adsp_debug_window.h>
17 LOG_MODULE_REGISTER(coredump_error, CONFIG_KERNEL_LOG_LEVEL);
18 
19 static int error;
20 static uint32_t mem_wptr;
21 
coredump_mem_window_backend_start(void)22 static void coredump_mem_window_backend_start(void)
23 {
24 	/* Reset error & mem write ptr */
25 	error = 0;
26 	mem_wptr = 0;
27 	ADSP_DW->descs[1].type = ADSP_DW_SLOT_TELEMETRY;
28 
29 	while (LOG_PROCESS()) {
30 		;
31 	}
32 
33 	LOG_PANIC();
34 	LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_BEGIN_STR);
35 }
36 
coredump_mem_window_backend_end(void)37 static void coredump_mem_window_backend_end(void)
38 {
39 	if (error != 0) {
40 		LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_ERROR_STR);
41 	}
42 
43 	LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_END_STR);
44 }
45 
coredump_mem_window_backend_buffer_output(uint8_t * buf,size_t buflen)46 static void coredump_mem_window_backend_buffer_output(uint8_t *buf, size_t buflen)
47 {
48 	uint32_t *mem_window_separator = (uint32_t *)(ADSP_DW->slots[1]);
49 	uint8_t *mem_window_sink = (uint8_t *)(ADSP_DW->slots[1]) + 4 + mem_wptr;
50 	uint8_t *coredump_data = buf;
51 	size_t data_left;
52 	/* Default place for telemetry dump is in memory window. Each data is easily find using
53 	 * separator. For telemetry that separator is 0x0DEC0DEB.
54 	 */
55 	*mem_window_separator = 0x0DEC0DEB;
56 
57 	/* skip the overflow data. Don't wrap around to keep the most important data
58 	 * such as registers and call stack in the beginning of mem window.
59 	 */
60 	if (mem_wptr >= ADSP_DW_SLOT_SIZE - 4) {
61 		return;
62 	}
63 
64 	if (buf) {
65 		for (data_left = buflen; data_left > 0; data_left--) {
66 			*mem_window_sink = *coredump_data;
67 			mem_window_sink++;
68 			coredump_data++;
69 		}
70 
71 		mem_wptr += buflen;
72 	} else {
73 		error = -EINVAL;
74 	}
75 }
76 
coredump_mem_window_backend_query(enum coredump_query_id query_id,void * arg)77 static int coredump_mem_window_backend_query(enum coredump_query_id query_id,
78 					     void *arg)
79 {
80 	int ret;
81 
82 	switch (query_id) {
83 	case COREDUMP_QUERY_GET_ERROR:
84 		ret = error;
85 		break;
86 	default:
87 		ret = -ENOTSUP;
88 		break;
89 	}
90 
91 	return ret;
92 }
93 
coredump_mem_window_backend_cmd(enum coredump_cmd_id cmd_id,void * arg)94 static int coredump_mem_window_backend_cmd(enum coredump_cmd_id cmd_id,
95 					   void *arg)
96 {
97 	int ret;
98 
99 	switch (cmd_id) {
100 	case COREDUMP_CMD_CLEAR_ERROR:
101 		ret = 0;
102 		error = 0;
103 		break;
104 	default:
105 		ret = -ENOTSUP;
106 		break;
107 	}
108 
109 	return ret;
110 }
111 
112 struct coredump_backend_api coredump_backend_intel_adsp_mem_window = {
113 	.start = coredump_mem_window_backend_start,
114 	.end = coredump_mem_window_backend_end,
115 	.buffer_output = coredump_mem_window_backend_buffer_output,
116 	.query = coredump_mem_window_backend_query,
117 	.cmd = coredump_mem_window_backend_cmd,
118 };
119