xref: /kvm-unit-tests/lib/riscv/sbi.c (revision 0182459af36445327a0a4f6e724e550e27863168)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <libcflat.h>
3 #include <cpumask.h>
4 #include <limits.h>
5 #include <asm/io.h>
6 #include <asm/sbi.h>
7 #include <asm/setup.h>
8 
sbi_ecall(int ext,int fid,unsigned long arg0,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)9 struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
10 			unsigned long arg1, unsigned long arg2,
11 			unsigned long arg3, unsigned long arg4,
12 			unsigned long arg5)
13 {
14 	register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
15 	register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
16 	register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
17 	register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
18 	register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
19 	register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
20 	register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
21 	register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
22 	struct sbiret ret;
23 
24 	asm volatile (
25 		"ecall"
26 		: "+r" (a0), "+r" (a1)
27 		: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
28 		: "memory");
29 	ret.error = a0;
30 	ret.value = a1;
31 
32 	return ret;
33 }
34 
sbi_sse_read_attrs_raw(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long phys_lo,unsigned long phys_hi)35 struct sbiret sbi_sse_read_attrs_raw(unsigned long event_id, unsigned long base_attr_id,
36 				     unsigned long attr_count, unsigned long phys_lo,
37 				     unsigned long phys_hi)
38 {
39 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_READ_ATTRS, event_id, base_attr_id, attr_count,
40 			 phys_lo, phys_hi, 0);
41 }
42 
sbi_sse_read_attrs(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long * values)43 struct sbiret sbi_sse_read_attrs(unsigned long event_id, unsigned long base_attr_id,
44 				 unsigned long attr_count, unsigned long *values)
45 {
46 	phys_addr_t p = virt_to_phys(values);
47 
48 	return sbi_sse_read_attrs_raw(event_id, base_attr_id, attr_count, lower_32_bits(p),
49 				      upper_32_bits(p));
50 }
51 
sbi_sse_write_attrs_raw(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long phys_lo,unsigned long phys_hi)52 struct sbiret sbi_sse_write_attrs_raw(unsigned long event_id, unsigned long base_attr_id,
53 				      unsigned long attr_count, unsigned long phys_lo,
54 				      unsigned long phys_hi)
55 {
56 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_WRITE_ATTRS, event_id, base_attr_id, attr_count,
57 			 phys_lo, phys_hi, 0);
58 }
59 
sbi_sse_write_attrs(unsigned long event_id,unsigned long base_attr_id,unsigned long attr_count,unsigned long * values)60 struct sbiret sbi_sse_write_attrs(unsigned long event_id, unsigned long base_attr_id,
61 				  unsigned long attr_count, unsigned long *values)
62 {
63 	phys_addr_t p = virt_to_phys(values);
64 
65 	return sbi_sse_write_attrs_raw(event_id, base_attr_id, attr_count, lower_32_bits(p),
66 				       upper_32_bits(p));
67 }
68 
sbi_sse_register_raw(unsigned long event_id,unsigned long entry_pc,unsigned long entry_arg)69 struct sbiret sbi_sse_register_raw(unsigned long event_id, unsigned long entry_pc,
70 				   unsigned long entry_arg)
71 {
72 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_REGISTER, event_id, entry_pc, entry_arg, 0, 0, 0);
73 }
74 
sbi_sse_register(unsigned long event_id,struct sbi_sse_handler_arg * arg)75 struct sbiret sbi_sse_register(unsigned long event_id, struct sbi_sse_handler_arg *arg)
76 {
77 	return sbi_sse_register_raw(event_id, (unsigned long)sbi_sse_entry, (unsigned long)arg);
78 }
79 
sbi_sse_unregister(unsigned long event_id)80 struct sbiret sbi_sse_unregister(unsigned long event_id)
81 {
82 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_UNREGISTER, event_id, 0, 0, 0, 0, 0);
83 }
84 
sbi_sse_enable(unsigned long event_id)85 struct sbiret sbi_sse_enable(unsigned long event_id)
86 {
87 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_ENABLE, event_id, 0, 0, 0, 0, 0);
88 }
89 
sbi_sse_disable(unsigned long event_id)90 struct sbiret sbi_sse_disable(unsigned long event_id)
91 {
92 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_DISABLE, event_id, 0, 0, 0, 0, 0);
93 }
94 
sbi_sse_hart_mask(void)95 struct sbiret sbi_sse_hart_mask(void)
96 {
97 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_HART_MASK, 0, 0, 0, 0, 0, 0);
98 }
99 
sbi_sse_hart_unmask(void)100 struct sbiret sbi_sse_hart_unmask(void)
101 {
102 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_HART_UNMASK, 0, 0, 0, 0, 0, 0);
103 }
104 
sbi_sse_inject(unsigned long event_id,unsigned long hart_id)105 struct sbiret sbi_sse_inject(unsigned long event_id, unsigned long hart_id)
106 {
107 	return sbi_ecall(SBI_EXT_SSE, SBI_EXT_SSE_INJECT, event_id, hart_id, 0, 0, 0, 0);
108 }
109 
sbi_fwft_set_raw(unsigned long feature,unsigned long value,unsigned long flags)110 struct sbiret sbi_fwft_set_raw(unsigned long feature, unsigned long value, unsigned long flags)
111 {
112 	return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, feature, value, flags, 0, 0, 0);
113 }
114 
sbi_fwft_set(uint32_t feature,unsigned long value,unsigned long flags)115 struct sbiret sbi_fwft_set(uint32_t feature, unsigned long value, unsigned long flags)
116 {
117 	return sbi_fwft_set_raw(feature, value, flags);
118 }
119 
sbi_fwft_get_raw(unsigned long feature)120 struct sbiret sbi_fwft_get_raw(unsigned long feature)
121 {
122 	return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_GET, feature, 0, 0, 0, 0, 0);
123 }
124 
sbi_fwft_get(uint32_t feature)125 struct sbiret sbi_fwft_get(uint32_t feature)
126 {
127 	return sbi_fwft_get_raw(feature);
128 }
129 
sbi_shutdown(bool passed)130 void sbi_shutdown(bool passed)
131 {
132 	sbi_ecall(SBI_EXT_SRST, 0, 0, !passed, 0, 0, 0, 0);
133 	puts("SBI shutdown failed!\n");
134 }
135 
sbi_hart_start(unsigned long hartid,unsigned long entry,unsigned long sp)136 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp)
137 {
138 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0);
139 }
140 
sbi_hart_stop(void)141 struct sbiret sbi_hart_stop(void)
142 {
143 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
144 }
145 
sbi_hart_get_status(unsigned long hartid)146 struct sbiret sbi_hart_get_status(unsigned long hartid)
147 {
148 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0);
149 }
150 
sbi_send_ipi(unsigned long hart_mask,unsigned long hart_mask_base)151 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base)
152 {
153 	return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0);
154 }
155 
sbi_send_ipi_cpu(int cpu)156 struct sbiret sbi_send_ipi_cpu(int cpu)
157 {
158 	return sbi_send_ipi(1UL, cpus[cpu].hartid);
159 }
160 
sbi_send_ipi_broadcast(void)161 struct sbiret sbi_send_ipi_broadcast(void)
162 {
163 	return sbi_send_ipi(0, -1UL);
164 }
165 
sbi_send_ipi_cpumask(const cpumask_t * mask)166 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask)
167 {
168 	struct sbiret ret;
169 	cpumask_t tmp;
170 
171 	if (cpumask_full(mask))
172 		return sbi_send_ipi_broadcast();
173 
174 	cpumask_copy(&tmp, mask);
175 
176 	while (!cpumask_empty(&tmp)) {
177 		unsigned long base = ULONG_MAX;
178 		unsigned long mask = 0;
179 		int cpu;
180 
181 		for_each_cpu(cpu, &tmp) {
182 			if (base > cpus[cpu].hartid)
183 				base = cpus[cpu].hartid;
184 		}
185 
186 		for_each_cpu(cpu, &tmp) {
187 			if (cpus[cpu].hartid < base + BITS_PER_LONG) {
188 				mask |= 1UL << (cpus[cpu].hartid - base);
189 				cpumask_clear_cpu(cpu, &tmp);
190 			}
191 		}
192 
193 		ret = sbi_send_ipi(mask, base);
194 		if (ret.error)
195 			break;
196 	}
197 
198 	return ret;
199 }
200 
sbi_set_timer(unsigned long stime_value)201 struct sbiret sbi_set_timer(unsigned long stime_value)
202 {
203 	return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0);
204 }
205 
sbi_get_imp_version(void)206 struct sbiret sbi_get_imp_version(void)
207 {
208 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0);
209 }
210 
sbi_get_imp_id(void)211 struct sbiret sbi_get_imp_id(void)
212 {
213 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0);
214 }
215 
__sbi_get_imp_version(void)216 unsigned long __sbi_get_imp_version(void)
217 {
218 	struct sbiret ret;
219 
220 	ret = sbi_get_imp_version();
221 	assert(!ret.error);
222 
223 	return ret.value;
224 }
225 
__sbi_get_imp_id(void)226 unsigned long __sbi_get_imp_id(void)
227 {
228 	struct sbiret ret;
229 
230 	ret = sbi_get_imp_id();
231 	assert(!ret.error);
232 
233 	return ret.value;
234 }
235 
sbi_get_spec_version(void)236 struct sbiret sbi_get_spec_version(void)
237 {
238 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0);
239 }
240 
sbi_probe(int ext)241 long sbi_probe(int ext)
242 {
243 	struct sbiret ret;
244 
245 	ret = sbi_get_spec_version();
246 	assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2));
247 
248 	ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0);
249 	assert(!ret.error);
250 
251 	return ret.value;
252 }
253