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