xref: /aosp_15_r20/external/coreboot/src/arch/riscv/sbi.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <mcall.h>
5 #include <stdint.h>
6 #include <arch/exception.h>
7 #include <sbi.h>
8 #include <vm.h>
9 #include <console/uart.h>
10 #include <commonlib/helpers.h>
11 
send_ipi(uintptr_t * pmask,intptr_t type)12 static uintptr_t send_ipi(uintptr_t *pmask, intptr_t type)
13 {
14 	uintptr_t mask = mprv_read_uintptr_t(pmask);
15 	for (int i = 0; mask; i++) {
16 		if (mask & 1) {
17 			OTHER_HLS(i)->ipi_pending |= type;
18 			/* send soft interrupt to target hart */
19 			set_msip(i, 1);
20 		}
21 		mask = mask >> 1;
22 	}
23 	return 0;
24 }
25 
sbi_set_timer(uint64_t when)26 static uintptr_t sbi_set_timer(uint64_t when)
27 {
28 	clear_csr(mip, MIP_STIP);
29 	set_csr(mie, MIP_MTIP);
30 	*(HLS()->timecmp) = when;
31 	return 0;
32 }
33 
34 #if CONFIG(CONSOLE_SERIAL)
sbi_console_putchar(uint8_t ch)35 static uintptr_t sbi_console_putchar(uint8_t ch)
36 {
37 	uart_tx_byte(CONFIG_UART_FOR_CONSOLE, ch);
38 	return 0;
39 }
40 
sbi_console_getchar(void)41 static uintptr_t sbi_console_getchar(void)
42 {
43 	return uart_rx_byte(CONFIG_UART_FOR_CONSOLE);
44 }
45 #endif
46 
sbi_clear_ipi(void)47 static uintptr_t sbi_clear_ipi(void)
48 {
49 	clear_csr(mip, MIP_SSIP);
50 	return 0;
51 }
52 
print_sbi_trap(uintptr_t trap)53 static void print_sbi_trap(uintptr_t trap)
54 {
55 	switch (trap) {
56 	case SBI_SHUTDOWN:
57 		printk(BIOS_EMERG, "SBI_SHUTDOWN\n");
58 		break;
59 	case SBI_REMOTE_SFENCE_VMA_ASID:
60 		printk(BIOS_EMERG, "SBI_REMOTE_SFENCE_VMA_ASID\n");
61 		break;
62 	case SBI_REMOTE_SFENCE_VMA:
63 		printk(BIOS_EMERG, "SBI_REMOTE_SFENCE_VMA\n");
64 		break;
65 	case SBI_REMOTE_FENCE_I:
66 		printk(BIOS_EMERG, "SBI_REMOTE_FENCE_I\n");
67 		break;
68 	case SBI_SEND_IPI:
69 		printk(BIOS_EMERG, "SBI_SEND_IPI\n");
70 		break;
71 	case SBI_CLEAR_IPI:
72 		printk(BIOS_EMERG, "SBI_CLEAR_IPI\n");
73 		break;
74 	case SBI_CONSOLE_GETCHAR:
75 		printk(BIOS_EMERG, "SBI_CONSOLE_GETCHAR\n");
76 		break;
77 	case SBI_CONSOLE_PUTCHAR:
78 		printk(BIOS_EMERG, "SBI_CONSOLE_PUTCHAR\n");
79 		break;
80 	case SBI_SET_TIMER:
81 		printk(BIOS_EMERG, "SBI_SET_TIMER\n");
82 		break;
83 	case SBI_BASE_EXTENSION:
84 		printk(BIOS_EMERG, "SBI_BASE_EXTENSION\n");
85 		break;
86 	default:
87 		printk(BIOS_EMERG, "%lx is an unknown SBI trap\n", trap);
88 		break;
89 	}
90 }
91 
92 /*
93  * These are the default SBI extension values.
94  * They can be overridden, by specialized code,
95  * but since this is a GPL SBI, it may be better
96  * that they evolve as we extend this SBI.
97  * over time, the will be updated.
98  */
99 int sbi_features[] = {1, 0, 0, 0, 0, 0, 0};
100 
101 /*
102  * sbi is triggered by the s-mode ecall
103  * parameter : register a0 a1 a2
104  * function  : register a7
105  * return    : register a0
106  */
handle_sbi(struct trapframe * tf)107 void handle_sbi(struct trapframe *tf)
108 {
109 	uintptr_t ret = 0;
110 	uintptr_t sbiret = 0;
111 	uintptr_t arg0 = tf->gpr[10];
112 	__maybe_unused uintptr_t arg1 = tf->gpr[11];
113 	uintptr_t fid = tf->gpr[16];
114 	uintptr_t eid = tf->gpr[17];
115 	uintptr_t retpc = read_csr(mepc) + 4;
116 
117 	switch (eid) {
118 	case SBI_SET_TIMER:
119 #if __riscv_xlen == 32
120 		ret = sbi_set_timer(arg0 + ((uint64_t)arg1 << 32));
121 #else
122 		ret = sbi_set_timer(arg0);
123 #endif
124 		break;
125 #if CONFIG(CONSOLE_SERIAL)
126 	case SBI_CONSOLE_PUTCHAR:
127 		ret = sbi_console_putchar(arg0);
128 		break;
129 	case SBI_CONSOLE_GETCHAR:
130 		ret = sbi_console_getchar();
131 		break;
132 #endif
133 	case SBI_CLEAR_IPI:
134 		ret = sbi_clear_ipi();
135 		break;
136 	case SBI_SEND_IPI:
137 		ret = send_ipi((uintptr_t *)arg0, IPI_SOFT);
138 		break;
139 	case SBI_REMOTE_FENCE_I:
140 		ret = send_ipi((uintptr_t *)arg0, IPI_FENCE_I);
141 		break;
142 	case SBI_REMOTE_SFENCE_VMA:
143 		ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA);
144 		break;
145 	case SBI_REMOTE_SFENCE_VMA_ASID:
146 		ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA_ASID);
147 		break;
148 	case SBI_SHUTDOWN:
149 		ret = send_ipi((uintptr_t *)arg0, IPI_SHUTDOWN);
150 		break;
151 	case SBI_BASE_EXTENSION:
152 		/* zero is an allowed return value for most features,
153 		 * and the only required one is feature 0.
154 		 * So this test will return legal values
155 		 * for all possible values of fid.
156 		 */
157 		if (fid < ARRAY_SIZE(sbi_features))
158 			ret = sbi_features[fid];
159 		break;
160 	default:
161 		print_sbi_trap(eid);
162 		printk(BIOS_EMERG, "SBI: %lx: ENOSYS\n", fid);
163 		sbiret = -SBI_ENOSYS;
164 		break;
165 	}
166 	tf->gpr[10] = sbiret;
167 	tf->gpr[11] = ret;
168 
169 	write_csr(mepc, retpc);
170 }
171