xref: /kvm-unit-tests/lib/riscv/sbi.c (revision 695740795adee59b48599e2f1a6bf19866a77779)
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_shutdown(void)110 void sbi_shutdown(void)
111 {
112 	sbi_ecall(SBI_EXT_SRST, 0, 0, 0, 0, 0, 0, 0);
113 	puts("SBI shutdown failed!\n");
114 }
115 
sbi_hart_start(unsigned long hartid,unsigned long entry,unsigned long sp)116 struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp)
117 {
118 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0);
119 }
120 
sbi_hart_stop(void)121 struct sbiret sbi_hart_stop(void)
122 {
123 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
124 }
125 
sbi_hart_get_status(unsigned long hartid)126 struct sbiret sbi_hart_get_status(unsigned long hartid)
127 {
128 	return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS, hartid, 0, 0, 0, 0, 0);
129 }
130 
sbi_send_ipi(unsigned long hart_mask,unsigned long hart_mask_base)131 struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base)
132 {
133 	return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0);
134 }
135 
sbi_send_ipi_cpu(int cpu)136 struct sbiret sbi_send_ipi_cpu(int cpu)
137 {
138 	return sbi_send_ipi(1UL, cpus[cpu].hartid);
139 }
140 
sbi_send_ipi_broadcast(void)141 struct sbiret sbi_send_ipi_broadcast(void)
142 {
143 	return sbi_send_ipi(0, -1UL);
144 }
145 
sbi_send_ipi_cpumask(const cpumask_t * mask)146 struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask)
147 {
148 	struct sbiret ret;
149 	cpumask_t tmp;
150 
151 	if (cpumask_full(mask))
152 		return sbi_send_ipi_broadcast();
153 
154 	cpumask_copy(&tmp, mask);
155 
156 	while (!cpumask_empty(&tmp)) {
157 		unsigned long base = ULONG_MAX;
158 		unsigned long mask = 0;
159 		int cpu;
160 
161 		for_each_cpu(cpu, &tmp) {
162 			if (base > cpus[cpu].hartid)
163 				base = cpus[cpu].hartid;
164 		}
165 
166 		for_each_cpu(cpu, &tmp) {
167 			if (cpus[cpu].hartid < base + BITS_PER_LONG) {
168 				mask |= 1UL << (cpus[cpu].hartid - base);
169 				cpumask_clear_cpu(cpu, &tmp);
170 			}
171 		}
172 
173 		ret = sbi_send_ipi(mask, base);
174 		if (ret.error)
175 			break;
176 	}
177 
178 	return ret;
179 }
180 
sbi_set_timer(unsigned long stime_value)181 struct sbiret sbi_set_timer(unsigned long stime_value)
182 {
183 	return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0);
184 }
185 
sbi_get_imp_version(void)186 struct sbiret sbi_get_imp_version(void)
187 {
188 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_VERSION, 0, 0, 0, 0, 0, 0);
189 }
190 
sbi_get_imp_id(void)191 struct sbiret sbi_get_imp_id(void)
192 {
193 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_IMP_ID, 0, 0, 0, 0, 0, 0);
194 }
195 
__sbi_get_imp_version(void)196 unsigned long __sbi_get_imp_version(void)
197 {
198 	struct sbiret ret;
199 
200 	ret = sbi_get_imp_version();
201 	assert(!ret.error);
202 
203 	return ret.value;
204 }
205 
__sbi_get_imp_id(void)206 unsigned long __sbi_get_imp_id(void)
207 {
208 	struct sbiret ret;
209 
210 	ret = sbi_get_imp_id();
211 	assert(!ret.error);
212 
213 	return ret.value;
214 }
215 
sbi_get_spec_version(void)216 struct sbiret sbi_get_spec_version(void)
217 {
218 	return sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_SPEC_VERSION, 0, 0, 0, 0, 0, 0);
219 }
220 
sbi_probe(int ext)221 long sbi_probe(int ext)
222 {
223 	struct sbiret ret;
224 
225 	ret = sbi_get_spec_version();
226 	assert(!ret.error && (ret.value & SBI_SPEC_VERSION_MASK) >= sbi_mk_version(0, 2));
227 
228 	ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, ext, 0, 0, 0, 0, 0);
229 	assert(!ret.error);
230 
231 	return ret.value;
232 }
233