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_barrier.h>
13 #include <sbi/riscv_locks.h>
14 #include <sbi/sbi_console.h>
15 #include <sbi/sbi_domain.h>
16 #include <sbi/sbi_ecall.h>
17 #include <sbi/sbi_hart.h>
18 #include <sbi/sbi_hartmask.h>
19 #include <sbi/sbi_hsm.h>
20 #include <sbi/sbi_ipi.h>
21 #include <sbi/sbi_platform.h>
22 #include <sbi/sbi_system.h>
23 #include <sbi/sbi_string.h>
24 #include <sbi/sbi_timer.h>
25 #include <sbi/sbi_tlb.h>
26 #include <sbi/sbi_version.h>
27
28 #define BANNER \
29 " ____ _____ ____ _____\n" \
30 " / __ \\ / ____| _ \\_ _|\n" \
31 " | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
32 " | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
33 " | |__| | |_) | __/ | | |____) | |_) || |_\n" \
34 " \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
35 " | |\n" \
36 " |_|\n\n"
37
sbi_boot_print_banner(struct sbi_scratch * scratch)38 static void sbi_boot_print_banner(struct sbi_scratch *scratch)
39 {
40 if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
41 return;
42
43 #ifdef OPENSBI_VERSION_GIT
44 sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
45 #else
46 sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
47 OPENSBI_VERSION_MINOR);
48 #endif
49
50 sbi_printf(BANNER);
51 }
52
sbi_boot_print_general(struct sbi_scratch * scratch)53 static void sbi_boot_print_general(struct sbi_scratch *scratch)
54 {
55 char str[128];
56 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
57
58 if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
59 return;
60
61 /* Platform details */
62 sbi_printf("Platform Name : %s\n",
63 sbi_platform_name(plat));
64 sbi_platform_get_features_str(plat, str, sizeof(str));
65 sbi_printf("Platform Features : %s\n", str);
66 sbi_printf("Platform HART Count : %u\n",
67 sbi_platform_hart_count(plat));
68
69 /* Firmware details */
70 sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
71 sbi_printf("Firmware Size : %d KB\n",
72 (u32)(scratch->fw_size / 1024));
73
74 /* SBI details */
75 sbi_printf("Runtime SBI Version : %d.%d\n",
76 sbi_ecall_version_major(), sbi_ecall_version_minor());
77 sbi_printf("\n");
78 }
79
sbi_boot_print_domains(struct sbi_scratch * scratch)80 static void sbi_boot_print_domains(struct sbi_scratch *scratch)
81 {
82 if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
83 return;
84
85 /* Domain details */
86 sbi_domain_dump_all(" ");
87 }
88
sbi_boot_print_hart(struct sbi_scratch * scratch,u32 hartid)89 static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
90 {
91 int xlen;
92 char str[128];
93 const struct sbi_domain *dom = sbi_domain_thishart_ptr();
94
95 if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
96 return;
97
98 /* Determine MISA XLEN and MISA string */
99 xlen = misa_xlen();
100 if (xlen < 1) {
101 sbi_printf("Error %d getting MISA XLEN\n", xlen);
102 sbi_hart_hang();
103 }
104
105 /* Boot HART details */
106 sbi_printf("Boot HART ID : %u\n", hartid);
107 sbi_printf("Boot HART Domain : %s\n", dom->name);
108 misa_string(xlen, str, sizeof(str));
109 sbi_printf("Boot HART ISA : %s\n", str);
110 sbi_hart_get_features_str(scratch, str, sizeof(str));
111 sbi_printf("Boot HART Features : %s\n", str);
112 sbi_printf("Boot HART PMP Count : %d\n",
113 sbi_hart_pmp_count(scratch));
114 sbi_printf("Boot HART PMP Granularity : %lu\n",
115 sbi_hart_pmp_granularity(scratch));
116 sbi_printf("Boot HART PMP Address Bits: %d\n",
117 sbi_hart_pmp_addrbits(scratch));
118 sbi_printf("Boot HART MHPM Count : %d\n",
119 sbi_hart_mhpm_count(scratch));
120 sbi_printf("Boot HART MHPM Count : %d\n",
121 sbi_hart_mhpm_count(scratch));
122 sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
123 }
124
125 static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
126 static struct sbi_hartmask coldboot_wait_hmask = { 0 };
127
128 static unsigned long coldboot_done;
129
wait_for_coldboot(struct sbi_scratch * scratch,u32 hartid)130 static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
131 {
132 unsigned long saved_mie, cmip;
133 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
134
135 /* Save MIE CSR */
136 saved_mie = csr_read(CSR_MIE);
137
138 /* Set MSIE bit to receive IPI */
139 csr_set(CSR_MIE, MIP_MSIP);
140
141 /* Acquire coldboot lock */
142 spin_lock(&coldboot_lock);
143
144 /* Mark current HART as waiting */
145 sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
146
147 /* Release coldboot lock */
148 spin_unlock(&coldboot_lock);
149
150 /* Wait for coldboot to finish using WFI */
151 while (!__smp_load_acquire(&coldboot_done)) {
152 do {
153 wfi();
154 cmip = csr_read(CSR_MIP);
155 } while (!(cmip & MIP_MSIP));
156 };
157
158 /* Acquire coldboot lock */
159 spin_lock(&coldboot_lock);
160
161 /* Unmark current HART as waiting */
162 sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
163
164 /* Release coldboot lock */
165 spin_unlock(&coldboot_lock);
166
167 /* Restore MIE CSR */
168 csr_write(CSR_MIE, saved_mie);
169
170 /* Clear current HART IPI */
171 sbi_platform_ipi_clear(plat, hartid);
172 }
173
wake_coldboot_harts(struct sbi_scratch * scratch,u32 hartid)174 static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
175 {
176 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
177
178 /* Mark coldboot done */
179 __smp_store_release(&coldboot_done, 1);
180
181 /* Acquire coldboot lock */
182 spin_lock(&coldboot_lock);
183
184 /* Send an IPI to all HARTs waiting for coldboot */
185 for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
186 if ((i != hartid) &&
187 sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
188 sbi_platform_ipi_send(plat, i);
189 }
190
191 /* Release coldboot lock */
192 spin_unlock(&coldboot_lock);
193 }
194
195 static unsigned long init_count_offset;
196
init_coldboot(struct sbi_scratch * scratch,u32 hartid)197 static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
198 {
199 int rc;
200 unsigned long *init_count;
201 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
202
203 /* Note: This has to be first thing in coldboot init sequence */
204 rc = sbi_scratch_init(scratch);
205 if (rc)
206 sbi_hart_hang();
207
208 /* Note: This has to be second thing in coldboot init sequence */
209 rc = sbi_domain_init(scratch, hartid);
210 if (rc)
211 sbi_hart_hang();
212
213 init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
214 "INIT_COUNT");
215 if (!init_count_offset)
216 sbi_hart_hang();
217
218 rc = sbi_hsm_init(scratch, hartid, TRUE);
219 if (rc)
220 sbi_hart_hang();
221
222 rc = sbi_platform_early_init(plat, TRUE);
223 if (rc)
224 sbi_hart_hang();
225
226 rc = sbi_hart_init(scratch, TRUE);
227 if (rc)
228 sbi_hart_hang();
229
230 rc = sbi_console_init(scratch);
231 if (rc)
232 sbi_hart_hang();
233
234 sbi_boot_print_banner(scratch);
235
236 rc = sbi_platform_irqchip_init(plat, TRUE);
237 if (rc) {
238 sbi_printf("%s: platform irqchip init failed (error %d)\n",
239 __func__, rc);
240 sbi_hart_hang();
241 }
242
243 rc = sbi_ipi_init(scratch, TRUE);
244 if (rc) {
245 sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
246 sbi_hart_hang();
247 }
248
249 rc = sbi_tlb_init(scratch, TRUE);
250 if (rc) {
251 sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
252 sbi_hart_hang();
253 }
254
255 rc = sbi_timer_init(scratch, TRUE);
256 if (rc) {
257 sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
258 sbi_hart_hang();
259 }
260
261 rc = sbi_ecall_init();
262 if (rc) {
263 sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
264 sbi_hart_hang();
265 }
266
267 sbi_boot_print_general(scratch);
268
269 /*
270 * Note: Finalize domains after HSM initialization so that we
271 * can startup non-root domains.
272 * Note: Finalize domains before HART PMP configuration so
273 * that we use correct domain for configuring PMP.
274 */
275 rc = sbi_domain_finalize(scratch, hartid);
276 if (rc) {
277 sbi_printf("%s: domain finalize failed (error %d)\n",
278 __func__, rc);
279 sbi_hart_hang();
280 }
281
282 sbi_boot_print_domains(scratch);
283
284 rc = sbi_hart_pmp_configure(scratch);
285 if (rc) {
286 sbi_printf("%s: PMP configure failed (error %d)\n",
287 __func__, rc);
288 sbi_hart_hang();
289 }
290
291 /*
292 * Note: Platform final initialization should be last so that
293 * it sees correct domain assignment and PMP configuration.
294 */
295 rc = sbi_platform_final_init(plat, TRUE);
296 if (rc) {
297 sbi_printf("%s: platform final init failed (error %d)\n",
298 __func__, rc);
299 sbi_hart_hang();
300 }
301
302 sbi_boot_print_hart(scratch, hartid);
303
304 wake_coldboot_harts(scratch, hartid);
305
306 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
307 (*init_count)++;
308
309 sbi_hsm_prepare_next_jump(scratch, hartid);
310 sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
311 scratch->next_mode, FALSE);
312 }
313
init_warmboot(struct sbi_scratch * scratch,u32 hartid)314 static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
315 {
316 int rc;
317 unsigned long *init_count;
318 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
319
320 wait_for_coldboot(scratch, hartid);
321
322 if (!init_count_offset)
323 sbi_hart_hang();
324
325 rc = sbi_hsm_init(scratch, hartid, FALSE);
326 if (rc)
327 sbi_hart_hang();
328
329 rc = sbi_platform_early_init(plat, FALSE);
330 if (rc)
331 sbi_hart_hang();
332
333 rc = sbi_hart_init(scratch, FALSE);
334 if (rc)
335 sbi_hart_hang();
336
337 rc = sbi_platform_irqchip_init(plat, FALSE);
338 if (rc)
339 sbi_hart_hang();
340
341 rc = sbi_ipi_init(scratch, FALSE);
342 if (rc)
343 sbi_hart_hang();
344
345 rc = sbi_tlb_init(scratch, FALSE);
346 if (rc)
347 sbi_hart_hang();
348
349 rc = sbi_timer_init(scratch, FALSE);
350 if (rc)
351 sbi_hart_hang();
352
353 rc = sbi_hart_pmp_configure(scratch);
354 if (rc)
355 sbi_hart_hang();
356
357 rc = sbi_platform_final_init(plat, FALSE);
358 if (rc)
359 sbi_hart_hang();
360
361 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
362 (*init_count)++;
363
364 sbi_hsm_prepare_next_jump(scratch, hartid);
365 sbi_hart_switch_mode(hartid, scratch->next_arg1,
366 scratch->next_addr,
367 scratch->next_mode, FALSE);
368 }
369
370 static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
371
372 /**
373 * Initialize OpenSBI library for current HART and jump to next
374 * booting stage.
375 *
376 * The function expects following:
377 * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
378 * 2. Stack pointer (SP) is setup for current HART
379 * 3. Interrupts are disabled in MSTATUS CSR
380 * 4. All interrupts are disabled in MIE CSR
381 *
382 * @param scratch pointer to sbi_scratch of current HART
383 */
sbi_init(struct sbi_scratch * scratch)384 void __noreturn sbi_init(struct sbi_scratch *scratch)
385 {
386 bool next_mode_supported = FALSE;
387 bool coldboot = FALSE;
388 u32 hartid = current_hartid();
389 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
390
391 if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
392 sbi_platform_hart_invalid(plat, hartid))
393 sbi_hart_hang();
394
395 switch (scratch->next_mode) {
396 case PRV_M:
397 next_mode_supported = TRUE;
398 break;
399 case PRV_S:
400 if (misa_extension('S'))
401 next_mode_supported = TRUE;
402 break;
403 case PRV_U:
404 if (misa_extension('U'))
405 next_mode_supported = TRUE;
406 break;
407 default:
408 sbi_hart_hang();
409 }
410
411 /*
412 * Only the HART supporting privilege mode specified in the
413 * scratch->next_mode should be allowed to become the coldboot
414 * HART because the coldboot HART will be directly jumping to
415 * the next booting stage.
416 *
417 * We use a lottery mechanism to select coldboot HART among
418 * HARTs which satisfy above condition.
419 */
420
421 if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
422 coldboot = TRUE;
423
424 if (coldboot)
425 init_coldboot(scratch, hartid);
426 else
427 init_warmboot(scratch, hartid);
428 }
429
sbi_init_count(u32 hartid)430 unsigned long sbi_init_count(u32 hartid)
431 {
432 struct sbi_scratch *scratch;
433 unsigned long *init_count;
434
435 if (!init_count_offset)
436 return 0;
437
438 scratch = sbi_hartid_to_scratch(hartid);
439 if (!scratch)
440 return 0;
441
442 init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
443
444 return *init_count;
445 }
446
447 /**
448 * Exit OpenSBI library for current HART and stop HART
449 *
450 * The function expects following:
451 * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
452 * 2. Stack pointer (SP) is setup for current HART
453 *
454 * @param scratch pointer to sbi_scratch of current HART
455 */
sbi_exit(struct sbi_scratch * scratch)456 void __noreturn sbi_exit(struct sbi_scratch *scratch)
457 {
458 u32 hartid = current_hartid();
459 const struct sbi_platform *plat = sbi_platform_ptr(scratch);
460
461 if (sbi_platform_hart_invalid(plat, hartid))
462 sbi_hart_hang();
463
464 sbi_platform_early_exit(plat);
465
466 sbi_timer_exit(scratch);
467
468 sbi_ipi_exit(scratch);
469
470 sbi_platform_irqchip_exit(plat);
471
472 sbi_platform_final_exit(plat);
473
474 sbi_hsm_exit(scratch);
475 }
476