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 "../../crt0.h"
37
38 static void __attribute__((used)) __section(".init")
_cstart(void)39 _cstart(void)
40 {
41 __start();
42 }
43
44 #ifdef CRT0_SEMIHOST
45 #include <semihost.h>
46 #include <unistd.h>
47 #include <stdio.h>
48
49 #ifdef __riscv_32e
50 #define NUM_REG 16
51 #else
52 #define NUM_REG 32
53 #endif
54
55 #if __riscv_xlen == 32
56 #define FMT "%08lx"
57 #define SD "sw"
58 #else
59 #define FMT "%016lx"
60 #define SD "sd"
61 #endif
62
63 struct fault {
64 unsigned long r[NUM_REG];
65 unsigned long mepc;
66 unsigned long mcause;
67 unsigned long mtval;
68 };
69
70 static const char *const names[NUM_REG] = {
71 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
72 "s0/fp","s1", "a0", "a1", "a2", "a3", "a4", "a5",
73 #if NUM_REG > 16
74 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
75 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
76 #endif
77 };
78
79
80 static void __attribute__((used)) __section(".init")
_ctrap(struct fault * fault)81 _ctrap(struct fault *fault)
82 {
83 int r;
84 printf("RISCV fault\n");
85 for (r = 0; r < NUM_REG; r++)
86 printf("\tx%d %-5.5s%s 0x" FMT "\n", r, names[r], r < 10 ? " " : "", fault->r[r]);
87 printf("\tmepc: 0x" FMT "\n", fault->mepc);
88 printf("\tmcause: 0x" FMT "\n", fault->mcause);
89 printf("\tmtval: 0x" FMT "\n", fault->mtval);
90 _exit(1);
91 }
92
93 #define _PASTE(r) #r
94 #define PASTE(r) _PASTE(r)
95
96 void __attribute__((naked)) __section(".init") __attribute__((used)) __attribute((aligned(4)))
_trap(void)97 _trap(void)
98 {
99 #ifndef __clang__
100 __asm__(".option nopic");
101 #endif
102
103 /* Build a known-working C environment */
104 __asm__(".option push\n"
105 ".option norelax\n"
106 "la sp, __stack\n"
107 "la gp, __global_pointer$\n"
108 ".option pop");
109
110 /* Make space for saved registers */
111 __asm__("addi sp,sp,%0" :: "i" (-sizeof(struct fault)));
112
113 /* Save registers on stack */
114 #define SAVE_REG(num) \
115 __asm__(SD" x%0, %1(sp)" :: "i" (num), \
116 "i" ((num) * sizeof(unsigned long) + offsetof(struct fault, r)))
117
118 #define SAVE_REGS_8(base) \
119 SAVE_REG(base+0); SAVE_REG(base+1); SAVE_REG(base+2); SAVE_REG(base+3); \
120 SAVE_REG(base+4); SAVE_REG(base+5); SAVE_REG(base+6); SAVE_REG(base+7)
121
122 SAVE_REGS_8(0);
123 SAVE_REGS_8(8);
124 #ifndef __riscv_32e
125 SAVE_REGS_8(16);
126 SAVE_REGS_8(24);
127 #endif
128
129 #define SAVE_CSR(name) \
130 __asm__("csrr t0, "PASTE(name));\
131 __asm__(SD" t0, %0(sp)" :: "i" (offsetof(struct fault, name)))
132
133 SAVE_CSR(mepc);
134 SAVE_CSR(mcause);
135 SAVE_CSR(mtval);
136
137 /*
138 * Pass pointer to saved registers in first parameter register
139 */
140 __asm__("mv a0, sp");
141
142 /* Enable FPU (just in case) */
143 #ifdef __riscv_flen
144 __asm__("csrr t0, mstatus\n"
145 "li t1, 8192\n" // 1 << 13 = 8192
146 "or t0, t1, t0\n"
147 "csrw mstatus, t0\n"
148 "csrwi fcsr, 0");
149 #endif
150 __asm__("j _ctrap");
151 }
152 #endif
153
154 void __attribute__((naked)) __section(".text.init.enter") __attribute__((used))
_start(void)155 _start(void)
156 {
157
158 /**
159 * seems clang has no option "nopic". Now this could be problematic,
160 * since according to the clang devs at [0], that option has an effect
161 * on `la`. However, the resulting crt0.o looks the same as the one from
162 * gcc (same opcodes + pc relative relocations where I used `la`), so
163 * this could be okay.
164 * [0] https://reviews.llvm.org/D55325
165 */
166 #ifndef __clang__
167 __asm__(".option nopic");
168 #endif
169
170 __asm__(".option push\n"
171 ".option norelax\n"
172 "la sp, __stack\n"
173 "la gp, __global_pointer$\n"
174 ".option pop");
175
176 #ifdef __riscv_flen
177 __asm__("csrr t0, mstatus\n"
178 "li t1, 8192\n" // 1 << 13 = 8192
179 "or t0, t1, t0\n"
180 "csrw mstatus, t0\n"
181 "csrwi fcsr, 0");
182 #endif
183 #ifdef CRT0_SEMIHOST
184 __asm__("la t0, _trap");
185 __asm__("csrw mtvec, t0");
186 __asm__("csrr t1, mtvec");
187 #endif
188 __asm__("j _cstart");
189 }
190