1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2019 Western Digital Corporation or its affiliates.
5 *
6 * Authors:
7 * Anup Patel <anup.patel@wdc.com>
8 */
9
10 #include <sbi/riscv_asm.h>
11 #include <sbi/riscv_atomic.h>
12 #include <sbi/riscv_locks.h>
13 #include <sbi/sbi_console.h>
14 #include <sbi/sbi_ecall.h>
15 #include <sbi/sbi_hart.h>
16 #include <sbi/sbi_hartmask.h>
17 #include <sbi/sbi_hsm.h>
18 #include <sbi/sbi_ipi.h>
19 #include <sbi/sbi_platform.h>
20 #include <sbi/sbi_system.h>
21 #include <sbi/sbi_string.h>
22 #include <sbi/sbi_timer.h>
23 #include <sbi/sbi_tlb.h>
24 #include <sbi/sbi_version.h>
25
26 #define BANNER \
27 " ____ _____ ____ _____\n" \
28 " / __ \\ / ____| _ \\_ _|\n" \
29 " | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
30 " | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
31 " | |__| | |_) | __/ | | |____) | |_) || |_\n" \
32 " \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
33 " | |\n" \
34 " |_|\n\n"
35
sbi_boot_prints(struct sbi_scratch * scratch,u32 hartid)36 static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
37 {
38 int xlen;
39 char str[128];
40 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
41
42 #ifdef OPENSBI_VERSION_GIT
43 sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
44 #else
45 sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
46 OPENSBI_VERSION_MINOR);
47 #endif
48
49 sbi_printf(BANNER);
50
51 /* Determine MISA XLEN and MISA string */
52 xlen = misa_xlen();
53 if (xlen < 1) {
54 sbi_printf("Error %d getting MISA XLEN\n", xlen);
55 sbi_hart_hang();
56 }
57
58 /* Platform details */
59 sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
60 sbi_platform_get_features_str(plat, str, sizeof(str));
61 sbi_printf("Platform Features : %s\n", str);
62 sbi_printf("Platform HART Count : %u\n",
63 sbi_platform_hart_count(plat));
64
65 /* Boot HART details */
66 sbi_printf("Boot HART ID : %u\n", hartid);
67 misa_string(xlen, str, sizeof(str));
68 sbi_printf("Boot HART ISA : %s\n", str);
69 sbi_hart_get_features_str(scratch, str, sizeof(str));
70 sbi_printf("BOOT HART Features : %s\n", str);
71 sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
72
73 /* Firmware details */
74 sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
75 sbi_printf("Firmware Size : %d KB\n",
76 (u32)(scratch->fw_size / 1024));
77
78 /* Generic details */
79 sbi_printf("Runtime SBI Version : %d.%d\n",
80 sbi_ecall_version_major(), sbi_ecall_version_minor());
81 sbi_printf("\n");
82
83 sbi_hart_delegation_dump(scratch);
84 sbi_hart_pmp_dump(scratch);
85 }
86
87 static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
88 static unsigned long coldboot_done = 0;
89 static struct sbi_hartmask coldboot_wait_hmask = { 0 };
90
wait_for_coldboot(struct sbi_scratch * scratch,u32 hartid)91 static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
92 {
93 unsigned long saved_mie, cmip;
94 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
95
96 /* Save MIE CSR */
97 saved_mie = csr_read(CSR_MIE);
98
99 /* Set MSIE bit to receive IPI */
100 csr_set(CSR_MIE, MIP_MSIP);
101
102 /* Acquire coldboot lock */
103 spin_lock(&coldboot_lock);
104
105 /* Mark current HART as waiting */
106 sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
107
108 /* Wait for coldboot to finish using WFI */
109 while (!coldboot_done) {
110 spin_unlock(&coldboot_lock);
111 do {
112 wfi();
113 cmip = csr_read(CSR_MIP);
114 } while (!(cmip & MIP_MSIP));
115 spin_lock(&coldboot_lock);
116 };
117
118 /* Unmark current HART as waiting */
119 sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
120
121 /* Release coldboot lock */
122 spin_unlock(&coldboot_lock);
123
124 /* Restore MIE CSR */
125 csr_write(CSR_MIE, saved_mie);
126
127 /* Clear current HART IPI */
128 sbi_platform_ipi_clear(plat, hartid);
129 }
130
wake_coldboot_harts(struct sbi_scratch * scratch,u32 hartid)131 static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
132 {
133 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
134
135 /* Acquire coldboot lock */
136 spin_lock(&coldboot_lock);
137
138 /* Mark coldboot done */
139 coldboot_done = 1;
140
141 /* Send an IPI to all HARTs waiting for coldboot */
142 for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
143 if ((i != hartid) &&
144 sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
145 sbi_platform_ipi_send(plat, i);
146 }
147
148 /* Release coldboot lock */
149 spin_unlock(&coldboot_lock);
150 }
151
152 static unsigned long init_count_offset;
153
init_coldboot(struct sbi_scratch * scratch,u32 hartid)154 static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
155 {
156 int rc;
157 unsigned long *init_count;
158 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
159
160 /* Note: This has to be first thing in coldboot init sequence */
161 rc = sbi_scratch_init(scratch);
162 if (rc)
163 sbi_hart_hang();
164
165 init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
166 "INIT_COUNT");
167 if (!init_count_offset)
168 sbi_hart_hang();
169
170 rc = sbi_hsm_init(scratch, hartid, TRUE);
171 if (rc)
172 sbi_hart_hang();
173
174 rc = sbi_platform_early_init(plat, TRUE);
175 if (rc)
176 sbi_hart_hang();
177
178 rc = sbi_hart_init(scratch, hartid, TRUE);
179 if (rc)
180 sbi_hart_hang();
181
182 rc = sbi_console_init(scratch);
183 if (rc)
184 sbi_hart_hang();
185
186 rc = sbi_platform_irqchip_init(plat, TRUE);
187 if (rc)
188 sbi_hart_hang();
189
190 rc = sbi_ipi_init(scratch, TRUE);
191 if (rc)
192 sbi_hart_hang();
193
194 rc = sbi_tlb_init(scratch, TRUE);
195 if (rc)
196 sbi_hart_hang();
197
198 rc = sbi_timer_init(scratch, TRUE);
199 if (rc)
200 sbi_hart_hang();
201
202 rc = sbi_ecall_init();
203 if (rc)
204 sbi_hart_hang();
205
206 rc = sbi_platform_final_init(plat, TRUE);
207 if (rc)
208 sbi_hart_hang();
209
210 if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
211 sbi_boot_prints(scratch, hartid);
212
213 wake_coldboot_harts(scratch, hartid);
214
215 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
216 (*init_count)++;
217
218 sbi_hsm_prepare_next_jump(scratch, hartid);
219 sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
220 scratch->next_mode, FALSE);
221 }
222
init_warmboot(struct sbi_scratch * scratch,u32 hartid)223 static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
224 {
225 int rc;
226 unsigned long *init_count;
227 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
228
229 wait_for_coldboot(scratch, hartid);
230
231 if (!init_count_offset)
232 sbi_hart_hang();
233
234 rc = sbi_hsm_init(scratch, hartid, FALSE);
235 if (rc)
236 sbi_hart_hang();
237
238 rc = sbi_platform_early_init(plat, FALSE);
239 if (rc)
240 sbi_hart_hang();
241
242 rc = sbi_hart_init(scratch, hartid, FALSE);
243 if (rc)
244 sbi_hart_hang();
245
246 rc = sbi_platform_irqchip_init(plat, FALSE);
247 if (rc)
248 sbi_hart_hang();
249
250 rc = sbi_ipi_init(scratch, FALSE);
251 if (rc)
252 sbi_hart_hang();
253
254 rc = sbi_tlb_init(scratch, FALSE);
255 if (rc)
256 sbi_hart_hang();
257
258 rc = sbi_timer_init(scratch, FALSE);
259 if (rc)
260 sbi_hart_hang();
261
262 rc = sbi_platform_final_init(plat, FALSE);
263 if (rc)
264 sbi_hart_hang();
265
266 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
267 (*init_count)++;
268
269 sbi_hsm_prepare_next_jump(scratch, hartid);
270 sbi_hart_switch_mode(hartid, scratch->next_arg1,
271 scratch->next_addr,
272 scratch->next_mode, FALSE);
273 }
274
275 static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
276
277 /**
278 * Initialize OpenSBI library for current HART and jump to next
279 * booting stage.
280 *
281 * The function expects following:
282 * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
283 * 2. Stack pointer (SP) is setup for current HART
284 * 3. Interrupts are disabled in MSTATUS CSR
285 * 4. All interrupts are disabled in MIE CSR
286 *
287 * @param scratch pointer to sbi_scratch of current HART
288 */
sbi_init(struct sbi_scratch * scratch)289 void __noreturn sbi_init(struct sbi_scratch *scratch)
290 {
291 bool coldboot = FALSE;
292 u32 hartid = current_hartid();
293 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
294
295 if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
296 sbi_platform_hart_invalid(plat, hartid))
297 sbi_hart_hang();
298
299 if (atomic_xchg(&coldboot_lottery, 1) == 0)
300 coldboot = TRUE;
301
302 if (coldboot)
303 init_coldboot(scratch, hartid);
304 else
305 init_warmboot(scratch, hartid);
306 }
307
sbi_init_count(u32 hartid)308 unsigned long sbi_init_count(u32 hartid)
309 {
310 struct sbi_scratch *scratch;
311 unsigned long *init_count;
312
313 if (!init_count_offset)
314 return 0;
315
316 scratch = sbi_hartid_to_scratch(hartid);
317 if (!scratch)
318 return 0;
319
320 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
321
322 return *init_count;
323 }
324
325 /**
326 * Exit OpenSBI library for current HART and stop HART
327 *
328 * The function expects following:
329 * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
330 * 2. Stack pointer (SP) is setup for current HART
331 *
332 * @param scratch pointer to sbi_scratch of current HART
333 */
sbi_exit(struct sbi_scratch * scratch)334 void __noreturn sbi_exit(struct sbi_scratch *scratch)
335 {
336 u32 hartid = current_hartid();
337 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
338
339 if (sbi_platform_hart_invalid(plat, hartid))
340 sbi_hart_hang();
341
342 sbi_platform_early_exit(plat);
343
344 sbi_timer_exit(scratch);
345
346 sbi_ipi_exit(scratch);
347
348 sbi_platform_irqchip_exit(plat);
349
350 sbi_platform_final_exit(plat);
351
352 sbi_hsm_exit(scratch);
353 }
354