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