1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_DEBUG_COREDUMP_H_
8 #define ZEPHYR_INCLUDE_DEBUG_COREDUMP_H_
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sys/types.h>
13 
14 
15 /**
16  * @file
17  *
18  * @defgroup coredump_apis Coredump APIs
19  * @ingroup os_services
20  * @brief Coredump APIs
21  * @{
22  */
23 
24 
25 /** Query ID */
26 enum coredump_query_id {
27 	/**
28 	 * Returns error code from backend.
29 	 */
30 	COREDUMP_QUERY_GET_ERROR,
31 
32 	/**
33 	 * Check if there is a stored coredump from backend.
34 	 *
35 	 * Returns:
36 	 * - 1 if there is a stored coredump, 0 if none.
37 	 * - -ENOTSUP if this query is not supported.
38 	 * - Otherwise, error code from backend.
39 	 */
40 	COREDUMP_QUERY_HAS_STORED_DUMP,
41 
42 	/**
43 	 * Returns:
44 	 * - coredump raw size from backend, 0 if none.
45 	 * - -ENOTSUP if this query is not supported.
46 	 * - Otherwise, error code from backend.
47 	 */
48 	COREDUMP_QUERY_GET_STORED_DUMP_SIZE,
49 
50 	/**
51 	 * Max value for query ID.
52 	 */
53 	COREDUMP_QUERY_MAX
54 };
55 
56 /** Command ID */
57 enum coredump_cmd_id {
58 	/**
59 	 * Clear error code from backend.
60 	 *
61 	 * Returns 0 if successful, failed otherwise.
62 	 */
63 	COREDUMP_CMD_CLEAR_ERROR,
64 
65 	/**
66 	 * Verify that the stored coredump is valid.
67 	 *
68 	 * Returns:
69 	 * - 1 if valid.
70 	 * - 0 if not valid or no stored coredump.
71 	 * - -ENOTSUP if this command is not supported.
72 	 * - Otherwise, error code from backend.
73 	 */
74 	COREDUMP_CMD_VERIFY_STORED_DUMP,
75 
76 	/**
77 	 * Erase the stored coredump.
78 	 *
79 	 * Returns:
80 	 * - 0 if successful.
81 	 * - -ENOTSUP if this command is not supported.
82 	 * - Otherwise, error code from backend.
83 	 */
84 	COREDUMP_CMD_ERASE_STORED_DUMP,
85 
86 	/**
87 	 * Copy the raw stored coredump.
88 	 *
89 	 * Returns:
90 	 * - copied size if successful
91 	 * - 0 if stored coredump is not found
92 	 * - -ENOTSUP if this command is not supported.
93 	 * - Otherwise, error code from backend.
94 	 */
95 	COREDUMP_CMD_COPY_STORED_DUMP,
96 
97 	/**
98 	 * Invalidate the stored coredump. This is faster than
99 	 * erasing the whole partition.
100 	 *
101 	 * Returns:
102 	 * - 0 if successful.
103 	 * - -ENOTSUP if this command is not supported.
104 	 * - Otherwise, error code from backend.
105 	 */
106 	COREDUMP_CMD_INVALIDATE_STORED_DUMP,
107 
108 	/**
109 	 * Max value for command ID.
110 	 */
111 	COREDUMP_CMD_MAX
112 };
113 
114 /** Coredump copy command (@ref COREDUMP_CMD_COPY_STORED_DUMP) argument definition */
115 struct coredump_cmd_copy_arg {
116 	/** Copy offset */
117 	off_t offset;
118 
119 	/** Copy destination buffer */
120 	uint8_t *buffer;
121 
122 	/** Copy length */
123 	size_t length;
124 };
125 
126 #ifdef CONFIG_DEBUG_COREDUMP
127 
128 #include <zephyr/toolchain.h>
129 #include <zephyr/arch/cpu.h>
130 #include <zephyr/sys/byteorder.h>
131 
132 #define COREDUMP_HDR_VER		1
133 
134 #define	COREDUMP_ARCH_HDR_ID		'A'
135 
136 #define	COREDUMP_MEM_HDR_ID		'M'
137 #define COREDUMP_MEM_HDR_VER		1
138 
139 /* Target code */
140 enum coredump_tgt_code {
141 	COREDUMP_TGT_UNKNOWN = 0,
142 	COREDUMP_TGT_X86,
143 	COREDUMP_TGT_X86_64,
144 	COREDUMP_TGT_ARM_CORTEX_M,
145 	COREDUMP_TGT_RISC_V,
146 	COREDUMP_TGT_XTENSA,
147 	COREDUMP_TGT_ARM64,
148 };
149 
150 /* Coredump header */
151 struct coredump_hdr_t {
152 	/* 'Z', 'E' */
153 	char		id[2];
154 
155 	/* Header version */
156 	uint16_t	hdr_version;
157 
158 	/* Target code */
159 	uint16_t	tgt_code;
160 
161 	/* Pointer size in Log2 */
162 	uint8_t		ptr_size_bits;
163 
164 	uint8_t		flag;
165 
166 	/* Coredump Reason given */
167 	unsigned int	reason;
168 } __packed;
169 
170 /* Architecture-specific block header */
171 struct coredump_arch_hdr_t {
172 	/* COREDUMP_ARCH_HDR_ID */
173 	char		id;
174 
175 	/* Header version */
176 	uint16_t	hdr_version;
177 
178 	/* Number of bytes in this block (excluding header) */
179 	uint16_t	num_bytes;
180 } __packed;
181 
182 /* Memory block header */
183 struct coredump_mem_hdr_t {
184 	/* COREDUMP_MEM_HDR_ID */
185 	char		id;
186 
187 	/* Header version */
188 	uint16_t	hdr_version;
189 
190 	/* Address of start of memory region */
191 	uintptr_t	start;
192 
193 	/* Address of end of memory region */
194 	uintptr_t	end;
195 } __packed;
196 
197 typedef void (*coredump_backend_start_t)(void);
198 typedef void (*coredump_backend_end_t)(void);
199 typedef void (*coredump_backend_buffer_output_t)(uint8_t *buf, size_t buflen);
200 typedef int (*coredump_backend_query_t)(enum coredump_query_id query_id,
201 					void *arg);
202 typedef int (*coredump_backend_cmd_t)(enum coredump_cmd_id cmd_id,
203 				      void *arg);
204 
205 struct coredump_backend_api {
206 	/* Signal to backend of the start of coredump. */
207 	coredump_backend_start_t		start;
208 
209 	/* Signal to backend of the end of coredump. */
210 	coredump_backend_end_t		end;
211 
212 	/* Raw buffer output */
213 	coredump_backend_buffer_output_t	buffer_output;
214 
215 	/* Perform query on backend */
216 	coredump_backend_query_t		query;
217 
218 	/* Perform command on backend */
219 	coredump_backend_cmd_t			cmd;
220 };
221 
222 void coredump(unsigned int reason, const z_arch_esf_t *esf,
223 	      struct k_thread *thread);
224 void coredump_memory_dump(uintptr_t start_addr, uintptr_t end_addr);
225 void coredump_buffer_output(uint8_t *buf, size_t buflen);
226 
227 int coredump_query(enum coredump_query_id query_id, void *arg);
228 int coredump_cmd(enum coredump_cmd_id cmd_id, void *arg);
229 
230 #else
231 
coredump(unsigned int reason,const z_arch_esf_t * esf,struct k_thread * thread)232 void coredump(unsigned int reason, const z_arch_esf_t *esf,
233 	      struct k_thread *thread)
234 {
235 	ARG_UNUSED(reason);
236 	ARG_UNUSED(esf);
237 	ARG_UNUSED(thread);
238 }
239 
coredump_memory_dump(uintptr_t start_addr,uintptr_t end_addr)240 void coredump_memory_dump(uintptr_t start_addr, uintptr_t end_addr)
241 {
242 	ARG_UNUSED(start_addr);
243 	ARG_UNUSED(end_addr);
244 }
245 
coredump_buffer_output(uint8_t * buf,size_t buflen)246 void coredump_buffer_output(uint8_t *buf, size_t buflen)
247 {
248 	ARG_UNUSED(buf);
249 	ARG_UNUSED(buflen);
250 }
251 
coredump_query(enum coredump_query_id query_id,void * arg)252 int coredump_query(enum coredump_query_id query_id, void *arg)
253 {
254 	ARG_UNUSED(query_id);
255 	ARG_UNUSED(arg);
256 	return -ENOTSUP;
257 }
258 
coredump_cmd(enum coredump_cmd_id query_id,void * arg)259 int coredump_cmd(enum coredump_cmd_id query_id, void *arg)
260 {
261 	ARG_UNUSED(query_id);
262 	ARG_UNUSED(arg);
263 	return -ENOTSUP;
264 }
265 
266 #endif /* CONFIG_DEBUG_COREDUMP */
267 
268 /**
269  * @fn void coredump(unsigned int reason, const z_arch_esf_t *esf, struct k_thread *thread);
270  * @brief Perform coredump.
271  *
272  * Normally, this is called inside z_fatal_error() to generate coredump
273  * when a fatal error is encountered. This can also be called on demand
274  * whenever a coredump is desired.
275  *
276  * @param reason Reason for the fatal error
277  * @param esf Exception context
278  * @param thread Thread information to dump
279  */
280 
281 /**
282  * @fn void coredump_memory_dump(uintptr_t start_addr, uintptr_t end_addr);
283  * @brief Dump memory region
284  *
285  * @param start_addr Start address of memory region to be dumped
286  * @param end_addr End address of memory region to be dumped
287  */
288 
289 /**
290  * @fn int coredump_buffer_output(uint8_t *buf, size_t buflen);
291  * @brief Output the buffer via coredump
292  *
293  * This outputs the buffer of byte array to the coredump backend.
294  * For example, this can be called to output the coredump section
295  * containing registers, or a section for memory dump.
296  *
297  * @param buf Buffer to be send to coredump output
298  * @param buflen Buffer length
299  */
300 
301 /**
302  * @fn int coredump_query(enum coredump_query_id query_id, void *arg);
303  * @brief Perform query on coredump subsystem.
304  *
305  * Query the coredump subsystem for information, for example, if there is
306  * an error.
307  *
308  * @param[in] query_id Query ID
309  * @param[in,out] arg Pointer to argument for exchanging information
310  * @return Depends on the query
311  */
312 
313 /**
314  * @fn int coredump_cmd(enum coredump_cmd_id cmd_id, void *arg);
315  * @brief Perform command on coredump subsystem.
316  *
317  * Perform command on coredump subsystem, for example, output the stored
318  * coredump via logging.
319  *
320  * @param[in] cmd_id Command ID
321  * @param[in,out] arg Pointer to argument for exchanging information
322  * @return Depends on the command
323  */
324 
325 /**
326  * @}
327  */
328 
329 #endif /* ZEPHYR_INCLUDE_DEBUG_COREDUMP_H_ */
330