1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2020 Sebastian Meyer
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <stddef.h>
37 #include "../../crt0.h"
38
39 static void __attribute__((used)) __section(".init")
_cstart(void)40 _cstart(void)
41 {
42 __start();
43 }
44
45 #ifdef CRT0_SEMIHOST
46 #include <semihost.h>
47 #include <unistd.h>
48 #include <stdio.h>
49
50 #ifdef __riscv_32e
51 #define NUM_REG 16
52 #else
53 #define NUM_REG 32
54 #endif
55
56 #if __riscv_xlen == 32
57 #define FMT "%08lx"
58 #define SD "sw"
59 #else
60 #define FMT "%016lx"
61 #define SD "sd"
62 #endif
63
64 struct fault {
65 unsigned long r[NUM_REG];
66 unsigned long mepc;
67 unsigned long mcause;
68 unsigned long mtval;
69 };
70
71 static const char *const names[NUM_REG] = {
72 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
73 "s0/fp","s1", "a0", "a1", "a2", "a3", "a4", "a5",
74 #if NUM_REG > 16
75 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
76 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
77 #endif
78 };
79
80
81 static void __attribute__((used)) __section(".init")
_ctrap(struct fault * fault)82 _ctrap(struct fault *fault)
83 {
84 int r;
85 printf("RISCV fault\n");
86 for (r = 0; r < NUM_REG; r++)
87 printf("\tx%d %-5.5s%s 0x" FMT "\n", r, names[r], r < 10 ? " " : "", fault->r[r]);
88 printf("\tmepc: 0x" FMT "\n", fault->mepc);
89 printf("\tmcause: 0x" FMT "\n", fault->mcause);
90 printf("\tmtval: 0x" FMT "\n", fault->mtval);
91 _exit(1);
92 }
93
94 #define _PASTE(r) #r
95 #define PASTE(r) _PASTE(r)
96
97 void __attribute__((naked)) __section(".init") __attribute__((used)) __attribute((aligned(4)))
_trap(void)98 _trap(void)
99 {
100 #ifndef __clang__
101 __asm__(".option nopic");
102 #endif
103
104 /* Build a known-working C environment */
105 __asm__(".option push\n"
106 ".option norelax\n"
107 "csrrw sp, mscratch, sp\n"
108 "la sp, __heap_end\n"
109 ".option pop");
110
111 /* Make space for saved registers */
112 __asm__("addi sp, sp, %0\n"
113 ".cfi_def_cfa sp, 0\n"
114 :: "i"(-sizeof(struct fault)));
115
116 /* Save registers on stack */
117 #define SAVE_REG(num) \
118 __asm__(SD" x%0, %1(sp)" :: "i" (num), \
119 "i" ((num) * sizeof(unsigned long) + offsetof(struct fault, r)))
120
121 #define SAVE_REGS_8(base) \
122 SAVE_REG(base+0); SAVE_REG(base+1); SAVE_REG(base+2); SAVE_REG(base+3); \
123 SAVE_REG(base+4); SAVE_REG(base+5); SAVE_REG(base+6); SAVE_REG(base+7)
124
125 SAVE_REGS_8(0);
126 SAVE_REGS_8(8);
127 #ifndef __riscv_32e
128 SAVE_REGS_8(16);
129 SAVE_REGS_8(24);
130 #endif
131
132 #define SAVE_CSR(name) \
133 __asm__("csrr t0, "PASTE(name));\
134 __asm__(SD" t0, %0(sp)" :: "i" (offsetof(struct fault, name)))
135
136 /*
137 * Save the trapping frame's stack pointer that was stashed in mscratch
138 * and tell the unwinder where we can find the return address (mepc).
139 */
140 __asm__("csrr ra, mepc\n"
141 SD " ra, %0(sp)\n"
142 ".cfi_offset ra, %0\n"
143 "csrrw t0, mscratch, zero\n"
144 SD " t0, %1(sp)\n"
145 ".cfi_offset sp, %1\n"
146 :: "i"(offsetof(struct fault, mepc)),
147 "i"(offsetof(struct fault, r[2])));
148 SAVE_CSR(mcause);
149 SAVE_CSR(mtval);
150
151 /*
152 * Pass pointer to saved registers in first parameter register
153 */
154 __asm__("la gp, __global_pointer$");
155 __asm__("mv a0, sp");
156
157 /* Enable FPU (just in case) */
158 #ifdef __riscv_flen
159 __asm__("csrr t0, mstatus\n"
160 "li t1, 8192\n" // 1 << 13 = 8192
161 "or t0, t1, t0\n"
162 "csrw mstatus, t0\n"
163 "csrwi fcsr, 0");
164 #endif
165 __asm__("jal _ctrap");
166 }
167 #endif
168
169 void __attribute__((naked)) __section(".text.init.enter") __attribute__((used))
_start(void)170 _start(void)
171 {
172
173 /**
174 * seems clang has no option "nopic". Now this could be problematic,
175 * since according to the clang devs at [0], that option has an effect
176 * on `la`. However, the resulting crt0.o looks the same as the one from
177 * gcc (same opcodes + pc relative relocations where I used `la`), so
178 * this could be okay.
179 * [0] https://reviews.llvm.org/D55325
180 */
181 #ifndef __clang__
182 __asm__(".option nopic");
183 #endif
184
185 __asm__(".option push\n"
186 ".option norelax\n"
187 "la sp, __stack\n"
188 "la gp, __global_pointer$\n"
189 ".option pop");
190
191 #ifdef __riscv_flen
192 __asm__("csrr t0, mstatus\n"
193 "li t1, 8192\n" // 1 << 13 = 8192
194 "or t0, t1, t0\n"
195 "csrw mstatus, t0\n"
196 "csrwi fcsr, 0");
197 #endif
198 #ifdef CRT0_SEMIHOST
199 __asm__("la t0, _trap");
200 __asm__("csrw mtvec, t0");
201 __asm__("csrr t1, mtvec");
202 #endif
203 __asm__("j _cstart");
204 }
205