1 /*
2  * Copyright (c) 2021 Facebook, Inc. and its affiliates
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/debug/coredump.h>
10 
11 #ifndef CONFIG_64BIT
12 #define ARCH_HDR_VER 1
13 #else
14 #define ARCH_HDR_VER 2
15 #endif
16 
17 struct riscv_arch_block {
18 #ifdef CONFIG_64BIT
19 	struct {
20 		uint64_t ra;
21 		uint64_t tp;
22 		uint64_t t0;
23 		uint64_t t1;
24 		uint64_t t2;
25 		uint64_t a0;
26 		uint64_t a1;
27 		uint64_t a2;
28 		uint64_t a3;
29 		uint64_t a4;
30 		uint64_t a5;
31 		uint64_t a6;
32 		uint64_t a7;
33 		uint64_t t3;
34 		uint64_t t4;
35 		uint64_t t5;
36 		uint64_t t6;
37 		uint64_t pc;
38 	} r;
39 #else /* !CONFIG_64BIT */
40 	struct {
41 		uint32_t ra;
42 		uint32_t tp;
43 		uint32_t t0;
44 		uint32_t t1;
45 		uint32_t t2;
46 		uint32_t a0;
47 		uint32_t a1;
48 		uint32_t a2;
49 		uint32_t a3;
50 		uint32_t a4;
51 		uint32_t a5;
52 #if !defined(CONFIG_RISCV_ISA_RV32E)
53 		uint32_t a6;
54 		uint32_t a7;
55 		uint32_t t3;
56 		uint32_t t4;
57 		uint32_t t5;
58 		uint32_t t6;
59 #endif /* !CONFIG_RISCV_ISA_RV32E */
60 		uint32_t pc;
61 	} r;
62 #endif /* CONFIG_64BIT */
63 } __packed;
64 
65 /*
66  * This might be too large for stack space if defined
67  * inside function. So do it here.
68  */
69 static struct riscv_arch_block arch_blk;
70 
arch_coredump_info_dump(const struct arch_esf * esf)71 void arch_coredump_info_dump(const struct arch_esf *esf)
72 {
73 	struct coredump_arch_hdr_t hdr = {
74 		.id = COREDUMP_ARCH_HDR_ID,
75 		.hdr_version = ARCH_HDR_VER,
76 		.num_bytes = sizeof(arch_blk),
77 	};
78 
79 	/* Nothing to process */
80 	if (esf == NULL) {
81 		return;
82 	}
83 
84 	(void)memset(&arch_blk, 0, sizeof(arch_blk));
85 
86 	/*
87 	 * 33 registers expected by GDB. Not all are in ESF but the GDB stub will need
88 	 * to send all 33 as one packet. The stub will need to send undefined for
89 	 * registers not presented in coredump.
90 	 */
91 	arch_blk.r.ra = esf->ra;
92 	arch_blk.r.t0 = esf->t0;
93 	arch_blk.r.t1 = esf->t1;
94 	arch_blk.r.t2 = esf->t2;
95 	arch_blk.r.a0 = esf->a0;
96 	arch_blk.r.a1 = esf->a1;
97 	arch_blk.r.a2 = esf->a2;
98 	arch_blk.r.a3 = esf->a3;
99 	arch_blk.r.a4 = esf->a4;
100 	arch_blk.r.a5 = esf->a5;
101 #if !defined(CONFIG_RISCV_ISA_RV32E)
102 	arch_blk.r.t3 = esf->t3;
103 	arch_blk.r.t4 = esf->t4;
104 	arch_blk.r.t5 = esf->t5;
105 	arch_blk.r.t6 = esf->t6;
106 	arch_blk.r.a6 = esf->a6;
107 	arch_blk.r.a7 = esf->a7;
108 #endif /* !CONFIG_RISCV_ISA_RV32E */
109 	arch_blk.r.pc = esf->mepc;
110 
111 	/* Send for output */
112 	coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr));
113 	coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk));
114 }
115 
arch_coredump_tgt_code_get(void)116 uint16_t arch_coredump_tgt_code_get(void)
117 {
118 	return COREDUMP_TGT_RISC_V;
119 }
120 
121 #if defined(CONFIG_DEBUG_COREDUMP_DUMP_THREAD_PRIV_STACK)
arch_coredump_priv_stack_dump(struct k_thread * thread)122 void arch_coredump_priv_stack_dump(struct k_thread *thread)
123 {
124 	uintptr_t start_addr, end_addr;
125 
126 	/* See: zephyr/include/zephyr/arch/riscv/arch.h */
127 	if (IS_ENABLED(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)) {
128 		start_addr = thread->arch.priv_stack_start + Z_RISCV_STACK_GUARD_SIZE;
129 	} else {
130 		start_addr = thread->stack_info.start - CONFIG_PRIVILEGED_STACK_SIZE;
131 	}
132 	end_addr = Z_STACK_PTR_ALIGN(thread->arch.priv_stack_start + K_KERNEL_STACK_RESERVED +
133 				     CONFIG_PRIVILEGED_STACK_SIZE);
134 
135 	coredump_memory_dump(start_addr, end_addr);
136 }
137 #endif /* CONFIG_DEBUG_COREDUMP_DUMP_THREAD_PRIV_STACK */
138