xref: /linux/arch/riscv/kvm/vcpu_sbi.c (revision 51d90a15fedf8366cb96ef68d0ea2d0bf15417d2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019 Western Digital Corporation or its affiliates.
4  *
5  * Authors:
6  *     Atish Patra <atish.patra@wdc.com>
7  */
8 
9 #include <linux/errno.h>
10 #include <linux/err.h>
11 #include <linux/kvm_host.h>
12 #include <asm/sbi.h>
13 #include <asm/kvm_vcpu_sbi.h>
14 
15 #ifndef CONFIG_RISCV_SBI_V01
16 static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = {
17 	.extid_start = -1UL,
18 	.extid_end = -1UL,
19 	.handler = NULL,
20 };
21 #endif
22 
23 #ifndef CONFIG_RISCV_PMU_SBI
24 static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = {
25 	.extid_start = -1UL,
26 	.extid_end = -1UL,
27 	.handler = NULL,
28 };
29 #endif
30 
31 struct kvm_riscv_sbi_extension_entry {
32 	enum KVM_RISCV_SBI_EXT_ID ext_idx;
33 	const struct kvm_vcpu_sbi_extension *ext_ptr;
34 };
35 
36 static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
37 	{
38 		.ext_idx = KVM_RISCV_SBI_EXT_V01,
39 		.ext_ptr = &vcpu_sbi_ext_v01,
40 	},
41 	{
42 		.ext_idx = KVM_RISCV_SBI_EXT_MAX, /* Can't be disabled */
43 		.ext_ptr = &vcpu_sbi_ext_base,
44 	},
45 	{
46 		.ext_idx = KVM_RISCV_SBI_EXT_TIME,
47 		.ext_ptr = &vcpu_sbi_ext_time,
48 	},
49 	{
50 		.ext_idx = KVM_RISCV_SBI_EXT_IPI,
51 		.ext_ptr = &vcpu_sbi_ext_ipi,
52 	},
53 	{
54 		.ext_idx = KVM_RISCV_SBI_EXT_RFENCE,
55 		.ext_ptr = &vcpu_sbi_ext_rfence,
56 	},
57 	{
58 		.ext_idx = KVM_RISCV_SBI_EXT_SRST,
59 		.ext_ptr = &vcpu_sbi_ext_srst,
60 	},
61 	{
62 		.ext_idx = KVM_RISCV_SBI_EXT_HSM,
63 		.ext_ptr = &vcpu_sbi_ext_hsm,
64 	},
65 	{
66 		.ext_idx = KVM_RISCV_SBI_EXT_PMU,
67 		.ext_ptr = &vcpu_sbi_ext_pmu,
68 	},
69 	{
70 		.ext_idx = KVM_RISCV_SBI_EXT_DBCN,
71 		.ext_ptr = &vcpu_sbi_ext_dbcn,
72 	},
73 	{
74 		.ext_idx = KVM_RISCV_SBI_EXT_SUSP,
75 		.ext_ptr = &vcpu_sbi_ext_susp,
76 	},
77 	{
78 		.ext_idx = KVM_RISCV_SBI_EXT_STA,
79 		.ext_ptr = &vcpu_sbi_ext_sta,
80 	},
81 	{
82 		.ext_idx = KVM_RISCV_SBI_EXT_FWFT,
83 		.ext_ptr = &vcpu_sbi_ext_fwft,
84 	},
85 	{
86 		.ext_idx = KVM_RISCV_SBI_EXT_MPXY,
87 		.ext_ptr = &vcpu_sbi_ext_mpxy,
88 	},
89 	{
90 		.ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,
91 		.ext_ptr = &vcpu_sbi_ext_experimental,
92 	},
93 	{
94 		.ext_idx = KVM_RISCV_SBI_EXT_VENDOR,
95 		.ext_ptr = &vcpu_sbi_ext_vendor,
96 	},
97 };
98 
99 static const struct kvm_riscv_sbi_extension_entry *
riscv_vcpu_get_sbi_ext(struct kvm_vcpu * vcpu,unsigned long idx)100 riscv_vcpu_get_sbi_ext(struct kvm_vcpu *vcpu, unsigned long idx)
101 {
102 	const struct kvm_riscv_sbi_extension_entry *sext = NULL;
103 
104 	if (idx >= KVM_RISCV_SBI_EXT_MAX)
105 		return NULL;
106 
107 	for (int i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
108 		if (sbi_ext[i].ext_idx == idx) {
109 			sext = &sbi_ext[i];
110 			break;
111 		}
112 	}
113 
114 	return sext;
115 }
116 
riscv_vcpu_supports_sbi_ext(struct kvm_vcpu * vcpu,int idx)117 static bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx)
118 {
119 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
120 	const struct kvm_riscv_sbi_extension_entry *sext;
121 
122 	sext = riscv_vcpu_get_sbi_ext(vcpu, idx);
123 
124 	return sext && scontext->ext_status[sext->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
125 }
126 
kvm_riscv_vcpu_sbi_forward_handler(struct kvm_vcpu * vcpu,struct kvm_run * run,struct kvm_vcpu_sbi_return * retdata)127 int kvm_riscv_vcpu_sbi_forward_handler(struct kvm_vcpu *vcpu,
128 				       struct kvm_run *run,
129 				       struct kvm_vcpu_sbi_return *retdata)
130 {
131 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
132 
133 	vcpu->arch.sbi_context.return_handled = 0;
134 	vcpu->stat.ecall_exit_stat++;
135 	run->exit_reason = KVM_EXIT_RISCV_SBI;
136 	run->riscv_sbi.extension_id = cp->a7;
137 	run->riscv_sbi.function_id = cp->a6;
138 	run->riscv_sbi.args[0] = cp->a0;
139 	run->riscv_sbi.args[1] = cp->a1;
140 	run->riscv_sbi.args[2] = cp->a2;
141 	run->riscv_sbi.args[3] = cp->a3;
142 	run->riscv_sbi.args[4] = cp->a4;
143 	run->riscv_sbi.args[5] = cp->a5;
144 	run->riscv_sbi.ret[0] = SBI_ERR_NOT_SUPPORTED;
145 	run->riscv_sbi.ret[1] = 0;
146 	retdata->uexit = true;
147 	return 0;
148 }
149 
kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu * vcpu,struct kvm_run * run,u32 type,u64 reason)150 void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
151 				     struct kvm_run *run,
152 				     u32 type, u64 reason)
153 {
154 	unsigned long i;
155 	struct kvm_vcpu *tmp;
156 
157 	kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
158 		spin_lock(&tmp->arch.mp_state_lock);
159 		WRITE_ONCE(tmp->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED);
160 		spin_unlock(&tmp->arch.mp_state_lock);
161 	}
162 	kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
163 
164 	memset(&run->system_event, 0, sizeof(run->system_event));
165 	run->system_event.type = type;
166 	run->system_event.ndata = 1;
167 	run->system_event.data[0] = reason;
168 	run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
169 }
170 
kvm_riscv_vcpu_sbi_request_reset(struct kvm_vcpu * vcpu,unsigned long pc,unsigned long a1)171 void kvm_riscv_vcpu_sbi_request_reset(struct kvm_vcpu *vcpu,
172 				      unsigned long pc, unsigned long a1)
173 {
174 	spin_lock(&vcpu->arch.reset_state.lock);
175 	vcpu->arch.reset_state.pc = pc;
176 	vcpu->arch.reset_state.a1 = a1;
177 	spin_unlock(&vcpu->arch.reset_state.lock);
178 
179 	kvm_make_request(KVM_REQ_VCPU_RESET, vcpu);
180 }
181 
kvm_riscv_vcpu_sbi_load_reset_state(struct kvm_vcpu * vcpu)182 void kvm_riscv_vcpu_sbi_load_reset_state(struct kvm_vcpu *vcpu)
183 {
184 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
185 	struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
186 	struct kvm_vcpu_reset_state *reset_state = &vcpu->arch.reset_state;
187 
188 	cntx->a0 = vcpu->vcpu_id;
189 
190 	spin_lock(&vcpu->arch.reset_state.lock);
191 	cntx->sepc = reset_state->pc;
192 	cntx->a1 = reset_state->a1;
193 	spin_unlock(&vcpu->arch.reset_state.lock);
194 
195 	cntx->sstatus &= ~SR_SIE;
196 	csr->vsatp = 0;
197 }
198 
kvm_riscv_vcpu_sbi_return(struct kvm_vcpu * vcpu,struct kvm_run * run)199 int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
200 {
201 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
202 
203 	/* Handle SBI return only once */
204 	if (vcpu->arch.sbi_context.return_handled)
205 		return 0;
206 	vcpu->arch.sbi_context.return_handled = 1;
207 
208 	/* Update return values */
209 	cp->a0 = run->riscv_sbi.ret[0];
210 	cp->a1 = run->riscv_sbi.ret[1];
211 
212 	/* Move to next instruction */
213 	vcpu->arch.guest_context.sepc += 4;
214 
215 	return 0;
216 }
217 
riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu * vcpu,unsigned long reg_num,unsigned long reg_val)218 static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu,
219 					 unsigned long reg_num,
220 					 unsigned long reg_val)
221 {
222 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
223 	const struct kvm_riscv_sbi_extension_entry *sext;
224 
225 	if (reg_val != 1 && reg_val != 0)
226 		return -EINVAL;
227 
228 	sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
229 	if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
230 		return -ENOENT;
231 
232 	scontext->ext_status[sext->ext_idx] = (reg_val) ?
233 			KVM_RISCV_SBI_EXT_STATUS_ENABLED :
234 			KVM_RISCV_SBI_EXT_STATUS_DISABLED;
235 
236 	return 0;
237 }
238 
riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu * vcpu,unsigned long reg_num,unsigned long * reg_val)239 static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu,
240 					 unsigned long reg_num,
241 					 unsigned long *reg_val)
242 {
243 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
244 	const struct kvm_riscv_sbi_extension_entry *sext;
245 
246 	sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
247 	if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
248 		return -ENOENT;
249 
250 	*reg_val = scontext->ext_status[sext->ext_idx] ==
251 				KVM_RISCV_SBI_EXT_STATUS_ENABLED;
252 
253 	return 0;
254 }
255 
riscv_vcpu_set_sbi_ext_multi(struct kvm_vcpu * vcpu,unsigned long reg_num,unsigned long reg_val,bool enable)256 static int riscv_vcpu_set_sbi_ext_multi(struct kvm_vcpu *vcpu,
257 					unsigned long reg_num,
258 					unsigned long reg_val, bool enable)
259 {
260 	unsigned long i, ext_id;
261 
262 	if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST)
263 		return -ENOENT;
264 
265 	for_each_set_bit(i, &reg_val, BITS_PER_LONG) {
266 		ext_id = i + reg_num * BITS_PER_LONG;
267 		if (ext_id >= KVM_RISCV_SBI_EXT_MAX)
268 			break;
269 
270 		riscv_vcpu_set_sbi_ext_single(vcpu, ext_id, enable);
271 	}
272 
273 	return 0;
274 }
275 
riscv_vcpu_get_sbi_ext_multi(struct kvm_vcpu * vcpu,unsigned long reg_num,unsigned long * reg_val)276 static int riscv_vcpu_get_sbi_ext_multi(struct kvm_vcpu *vcpu,
277 					unsigned long reg_num,
278 					unsigned long *reg_val)
279 {
280 	unsigned long i, ext_id, ext_val;
281 
282 	if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST)
283 		return -ENOENT;
284 
285 	for (i = 0; i < BITS_PER_LONG; i++) {
286 		ext_id = i + reg_num * BITS_PER_LONG;
287 		if (ext_id >= KVM_RISCV_SBI_EXT_MAX)
288 			break;
289 
290 		ext_val = 0;
291 		riscv_vcpu_get_sbi_ext_single(vcpu, ext_id, &ext_val);
292 		if (ext_val)
293 			*reg_val |= KVM_REG_RISCV_SBI_MULTI_MASK(ext_id);
294 	}
295 
296 	return 0;
297 }
298 
kvm_riscv_vcpu_reg_indices_sbi_ext(struct kvm_vcpu * vcpu,u64 __user * uindices)299 int kvm_riscv_vcpu_reg_indices_sbi_ext(struct kvm_vcpu *vcpu, u64 __user *uindices)
300 {
301 	unsigned int n = 0;
302 
303 	for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
304 		u64 size = IS_ENABLED(CONFIG_32BIT) ?
305 			   KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
306 		u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT |
307 			  KVM_REG_RISCV_SBI_SINGLE | i;
308 
309 		if (!riscv_vcpu_supports_sbi_ext(vcpu, i))
310 			continue;
311 
312 		if (uindices) {
313 			if (put_user(reg, uindices))
314 				return -EFAULT;
315 			uindices++;
316 		}
317 
318 		n++;
319 	}
320 
321 	return n;
322 }
323 
kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)324 int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu,
325 				   const struct kvm_one_reg *reg)
326 {
327 	unsigned long __user *uaddr =
328 			(unsigned long __user *)(unsigned long)reg->addr;
329 	unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
330 					    KVM_REG_SIZE_MASK |
331 					    KVM_REG_RISCV_SBI_EXT);
332 	unsigned long reg_val, reg_subtype;
333 
334 	if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
335 		return -EINVAL;
336 
337 	if (vcpu->arch.ran_atleast_once)
338 		return -EBUSY;
339 
340 	reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
341 	reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
342 
343 	if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id)))
344 		return -EFAULT;
345 
346 	switch (reg_subtype) {
347 	case KVM_REG_RISCV_SBI_SINGLE:
348 		return riscv_vcpu_set_sbi_ext_single(vcpu, reg_num, reg_val);
349 	case KVM_REG_RISCV_SBI_MULTI_EN:
350 		return riscv_vcpu_set_sbi_ext_multi(vcpu, reg_num, reg_val, true);
351 	case KVM_REG_RISCV_SBI_MULTI_DIS:
352 		return riscv_vcpu_set_sbi_ext_multi(vcpu, reg_num, reg_val, false);
353 	default:
354 		return -ENOENT;
355 	}
356 
357 	return 0;
358 }
359 
kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)360 int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
361 				   const struct kvm_one_reg *reg)
362 {
363 	int rc;
364 	unsigned long __user *uaddr =
365 			(unsigned long __user *)(unsigned long)reg->addr;
366 	unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
367 					    KVM_REG_SIZE_MASK |
368 					    KVM_REG_RISCV_SBI_EXT);
369 	unsigned long reg_val, reg_subtype;
370 
371 	if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
372 		return -EINVAL;
373 
374 	reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
375 	reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
376 
377 	reg_val = 0;
378 	switch (reg_subtype) {
379 	case KVM_REG_RISCV_SBI_SINGLE:
380 		rc = riscv_vcpu_get_sbi_ext_single(vcpu, reg_num, &reg_val);
381 		break;
382 	case KVM_REG_RISCV_SBI_MULTI_EN:
383 	case KVM_REG_RISCV_SBI_MULTI_DIS:
384 		rc = riscv_vcpu_get_sbi_ext_multi(vcpu, reg_num, &reg_val);
385 		if (!rc && reg_subtype == KVM_REG_RISCV_SBI_MULTI_DIS)
386 			reg_val = ~reg_val;
387 		break;
388 	default:
389 		rc = -ENOENT;
390 	}
391 	if (rc)
392 		return rc;
393 
394 	if (copy_to_user(uaddr, &reg_val, KVM_REG_SIZE(reg->id)))
395 		return -EFAULT;
396 
397 	return 0;
398 }
399 
kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu * vcpu,u64 __user * uindices)400 int kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu *vcpu, u64 __user *uindices)
401 {
402 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
403 	const struct kvm_riscv_sbi_extension_entry *entry;
404 	const struct kvm_vcpu_sbi_extension *ext;
405 	unsigned long state_reg_count;
406 	int i, j, rc, count = 0;
407 	u64 reg;
408 
409 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
410 		entry = &sbi_ext[i];
411 		ext = entry->ext_ptr;
412 
413 		if (!ext->get_state_reg_count ||
414 		    scontext->ext_status[entry->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_ENABLED)
415 			continue;
416 
417 		state_reg_count = ext->get_state_reg_count(vcpu);
418 		if (!uindices)
419 			goto skip_put_user;
420 
421 		for (j = 0; j < state_reg_count; j++) {
422 			if (ext->get_state_reg_id) {
423 				rc = ext->get_state_reg_id(vcpu, j, &reg);
424 				if (rc)
425 					return rc;
426 			} else {
427 				reg = KVM_REG_RISCV |
428 				      (IS_ENABLED(CONFIG_32BIT) ?
429 				       KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64) |
430 				      KVM_REG_RISCV_SBI_STATE |
431 				      ext->state_reg_subtype | j;
432 			}
433 
434 			if (put_user(reg, uindices))
435 				return -EFAULT;
436 			uindices++;
437 		}
438 
439 skip_put_user:
440 		count += state_reg_count;
441 	}
442 
443 	return count;
444 }
445 
kvm_vcpu_sbi_find_ext_withstate(struct kvm_vcpu * vcpu,unsigned long subtype)446 static const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext_withstate(struct kvm_vcpu *vcpu,
447 									    unsigned long subtype)
448 {
449 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
450 	const struct kvm_riscv_sbi_extension_entry *entry;
451 	const struct kvm_vcpu_sbi_extension *ext;
452 	int i;
453 
454 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
455 		entry = &sbi_ext[i];
456 		ext = entry->ext_ptr;
457 
458 		if (ext->get_state_reg_count &&
459 		    ext->state_reg_subtype == subtype &&
460 		    scontext->ext_status[entry->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_ENABLED)
461 			return ext;
462 	}
463 
464 	return NULL;
465 }
466 
kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)467 int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
468 {
469 	unsigned long __user *uaddr =
470 			(unsigned long __user *)(unsigned long)reg->addr;
471 	unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
472 					    KVM_REG_SIZE_MASK |
473 					    KVM_REG_RISCV_SBI_STATE);
474 	const struct kvm_vcpu_sbi_extension *ext;
475 	unsigned long reg_subtype;
476 	void *reg_val;
477 	u64 data64;
478 	u32 data32;
479 	u16 data16;
480 	u8 data8;
481 
482 	switch (KVM_REG_SIZE(reg->id)) {
483 	case 1:
484 		reg_val = &data8;
485 		break;
486 	case 2:
487 		reg_val = &data16;
488 		break;
489 	case 4:
490 		reg_val = &data32;
491 		break;
492 	case 8:
493 		reg_val = &data64;
494 		break;
495 	default:
496 		return -EINVAL;
497 	}
498 
499 	if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id)))
500 		return -EFAULT;
501 
502 	reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
503 	reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
504 
505 	ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype);
506 	if (!ext || !ext->set_state_reg)
507 		return -EINVAL;
508 
509 	return ext->set_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val);
510 }
511 
kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)512 int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
513 {
514 	unsigned long __user *uaddr =
515 			(unsigned long __user *)(unsigned long)reg->addr;
516 	unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
517 					    KVM_REG_SIZE_MASK |
518 					    KVM_REG_RISCV_SBI_STATE);
519 	const struct kvm_vcpu_sbi_extension *ext;
520 	unsigned long reg_subtype;
521 	void *reg_val;
522 	u64 data64;
523 	u32 data32;
524 	u16 data16;
525 	u8 data8;
526 	int ret;
527 
528 	switch (KVM_REG_SIZE(reg->id)) {
529 	case 1:
530 		reg_val = &data8;
531 		break;
532 	case 2:
533 		reg_val = &data16;
534 		break;
535 	case 4:
536 		reg_val = &data32;
537 		break;
538 	case 8:
539 		reg_val = &data64;
540 		break;
541 	default:
542 		return -EINVAL;
543 	}
544 
545 	reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
546 	reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
547 
548 	ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype);
549 	if (!ext || !ext->get_state_reg)
550 		return -EINVAL;
551 
552 	ret = ext->get_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val);
553 	if (ret)
554 		return ret;
555 
556 	if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id)))
557 		return -EFAULT;
558 
559 	return 0;
560 }
561 
kvm_vcpu_sbi_find_ext(struct kvm_vcpu * vcpu,unsigned long extid)562 const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
563 				struct kvm_vcpu *vcpu, unsigned long extid)
564 {
565 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
566 	const struct kvm_riscv_sbi_extension_entry *entry;
567 	const struct kvm_vcpu_sbi_extension *ext;
568 	int i;
569 
570 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
571 		entry = &sbi_ext[i];
572 		ext = entry->ext_ptr;
573 
574 		if (ext->extid_start <= extid && ext->extid_end >= extid) {
575 			if (entry->ext_idx >= KVM_RISCV_SBI_EXT_MAX ||
576 			    scontext->ext_status[entry->ext_idx] ==
577 						KVM_RISCV_SBI_EXT_STATUS_ENABLED)
578 				return ext;
579 
580 			return NULL;
581 		}
582 	}
583 
584 	return NULL;
585 }
586 
kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu * vcpu,struct kvm_run * run)587 int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
588 {
589 	int ret = 1;
590 	bool next_sepc = true;
591 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
592 	const struct kvm_vcpu_sbi_extension *sbi_ext;
593 	struct kvm_cpu_trap utrap = {0};
594 	struct kvm_vcpu_sbi_return sbi_ret = {
595 		.out_val = 0,
596 		.err_val = 0,
597 		.utrap = &utrap,
598 	};
599 	bool ext_is_v01 = false;
600 
601 	sbi_ext = kvm_vcpu_sbi_find_ext(vcpu, cp->a7);
602 	if (sbi_ext && sbi_ext->handler) {
603 #ifdef CONFIG_RISCV_SBI_V01
604 		if (cp->a7 >= SBI_EXT_0_1_SET_TIMER &&
605 		    cp->a7 <= SBI_EXT_0_1_SHUTDOWN)
606 			ext_is_v01 = true;
607 #endif
608 		ret = sbi_ext->handler(vcpu, run, &sbi_ret);
609 	} else {
610 		/* Return error for unsupported SBI calls */
611 		cp->a0 = SBI_ERR_NOT_SUPPORTED;
612 		goto ecall_done;
613 	}
614 
615 	/*
616 	 * When the SBI extension returns a Linux error code, it exits the ioctl
617 	 * loop and forwards the error to userspace.
618 	 */
619 	if (ret < 0) {
620 		next_sepc = false;
621 		goto ecall_done;
622 	}
623 
624 	/* Handle special error cases i.e trap, exit or userspace forward */
625 	if (sbi_ret.utrap->scause) {
626 		/* No need to increment sepc or exit ioctl loop */
627 		ret = 1;
628 		sbi_ret.utrap->sepc = cp->sepc;
629 		kvm_riscv_vcpu_trap_redirect(vcpu, sbi_ret.utrap);
630 		next_sepc = false;
631 		goto ecall_done;
632 	}
633 
634 	/* Exit ioctl loop or Propagate the error code the guest */
635 	if (sbi_ret.uexit) {
636 		next_sepc = false;
637 		ret = 0;
638 	} else {
639 		cp->a0 = sbi_ret.err_val;
640 		ret = 1;
641 	}
642 ecall_done:
643 	if (next_sepc)
644 		cp->sepc += 4;
645 	/* a1 should only be updated when we continue the ioctl loop */
646 	if (!ext_is_v01 && ret == 1)
647 		cp->a1 = sbi_ret.out_val;
648 
649 	return ret;
650 }
651 
kvm_riscv_vcpu_sbi_init(struct kvm_vcpu * vcpu)652 void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu)
653 {
654 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
655 	const struct kvm_riscv_sbi_extension_entry *entry;
656 	const struct kvm_vcpu_sbi_extension *ext;
657 	int idx, i;
658 
659 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
660 		entry = &sbi_ext[i];
661 		ext = entry->ext_ptr;
662 		idx = entry->ext_idx;
663 
664 		if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status))
665 			continue;
666 
667 		if (ext->probe && !ext->probe(vcpu)) {
668 			scontext->ext_status[idx] = KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
669 			continue;
670 		}
671 
672 		scontext->ext_status[idx] = ext->default_disabled ?
673 					KVM_RISCV_SBI_EXT_STATUS_DISABLED :
674 					KVM_RISCV_SBI_EXT_STATUS_ENABLED;
675 
676 		if (ext->init && ext->init(vcpu) != 0)
677 			scontext->ext_status[idx] = KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
678 	}
679 }
680 
kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu * vcpu)681 void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu)
682 {
683 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
684 	const struct kvm_riscv_sbi_extension_entry *entry;
685 	const struct kvm_vcpu_sbi_extension *ext;
686 	int idx, i;
687 
688 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
689 		entry = &sbi_ext[i];
690 		ext = entry->ext_ptr;
691 		idx = entry->ext_idx;
692 
693 		if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status))
694 			continue;
695 
696 		if (scontext->ext_status[idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE ||
697 		    !ext->deinit)
698 			continue;
699 
700 		ext->deinit(vcpu);
701 	}
702 }
703 
kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu * vcpu)704 void kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu *vcpu)
705 {
706 	struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
707 	const struct kvm_riscv_sbi_extension_entry *entry;
708 	const struct kvm_vcpu_sbi_extension *ext;
709 	int idx, i;
710 
711 	for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
712 		entry = &sbi_ext[i];
713 		ext = entry->ext_ptr;
714 		idx = entry->ext_idx;
715 
716 		if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status))
717 			continue;
718 
719 		if (scontext->ext_status[idx] != KVM_RISCV_SBI_EXT_STATUS_ENABLED ||
720 		    !ext->reset)
721 			continue;
722 
723 		ext->reset(vcpu);
724 	}
725 }
726