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