History

RISC-V: KVM: Implement VCPU interrupts and requests handling

This patch implements VCPU interrupts and requests which are both asynchronous events. The VCPU interrupts can be set/unset using KVM_INTERRUPT ioctl from user-space. In future, the in-kernel IRQCHIP emulation will use kvm_riscv_vcpu_set_interrupt() and kvm_riscv_vcpu_unset_interrupt() functions to set/unset VCPU interrupts. Important VCPU requests implemented by this patch are: KVM_REQ_SLEEP - set whenever VCPU itself goes to sleep state KVM_REQ_VCPU_RESET - set whenever VCPU reset is requested The WFI trap-n-emulate (added later) will use KVM_REQ_SLEEP request and kvm_riscv_vcpu_has_interrupt() function. The KVM_REQ_VCPU_RESET request will be used by SBI emulation (added later) to power-up a VCPU in power-off state. The user-space can use the GET_MPSTATE/SET_MPSTATE ioctls to get/set power state of a VCPU.

Anup Patel committed 5 years ago

Commit cce69af1 parent a33c72f3 files · +197 −13Browse files

Unified · Split

3 files
  1. arch/riscv/include/asm/kvm_host.h +23 −0
  2. arch/riscv/include/uapi/asm/kvm.h +3 −0
  3. arch/riscv/kvm/vcpu.c +171 −13
arch/riscv/include/asm/kvm_host.h+23−0
@@ -127,6 +127,21 @@ struct kvm_vcpu_arch { · 126 unmodified lines
127 /* CPU CSR context upon Guest VCPU reset */127 /* CPU CSR context upon Guest VCPU reset */
128 struct kvm_vcpu_csr guest_reset_csr;128 struct kvm_vcpu_csr guest_reset_csr;
129 129
130 /*
131 * VCPU interrupts
132 *
133 * We have a lockless approach for tracking pending VCPU interrupts
134 * implemented using atomic bitops. The irqs_pending bitmap represent
135 * pending interrupts whereas irqs_pending_mask represent bits changed
136 * in irqs_pending. Our approach is modeled around multiple producer
137 * and single consumer problem where the consumer is the VCPU itself.
138 */
139 unsigned long irqs_pending;
140 unsigned long irqs_pending_mask;
141
142 /* VCPU power-off state */
143 bool power_off;
144
130 /* Don't run the VCPU (blocked) */145 /* Don't run the VCPU (blocked) */
131 bool pause;146 bool pause;
132 147
@@ -150,4 +165,12 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, · 17 unmodified lines
150 165
151static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) {}166static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) {}
152 167
168int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
169int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
170void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu);
171void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu);
172bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask);
173void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu);
174void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu);
175
153#endif /* __RISCV_KVM_HOST_H__ */176#endif /* __RISCV_KVM_HOST_H__ */
arch/riscv/include/uapi/asm/kvm.h+3−0
@@ -18,6 +18,9 @@ · 17 unmodified lines
18 18
19#define KVM_COALESCED_MMIO_PAGE_OFFSET 119#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
20 20
21#define KVM_INTERRUPT_SET -1U
22#define KVM_INTERRUPT_UNSET -2U
23
21/* for KVM_GET_REGS and KVM_SET_REGS */24/* for KVM_GET_REGS and KVM_SET_REGS */
22struct kvm_regs {25struct kvm_regs {
23};26};
arch/riscv/kvm/vcpu.c+171−13
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include <linux/err.h>11#include <linux/err.h>
12#include <linux/kdebug.h>12#include <linux/kdebug.h>
13#include <linux/module.h>13#include <linux/module.h>
14#include <linux/percpu.h>
14#include <linux/uaccess.h>15#include <linux/uaccess.h>
15#include <linux/vmalloc.h>16#include <linux/vmalloc.h>
16#include <linux/sched/signal.h>17#include <linux/sched/signal.h>
@@ -57,6 +58,9 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) · 40 unmodified lines
57 memcpy(csr, reset_csr, sizeof(*csr));58 memcpy(csr, reset_csr, sizeof(*csr));
58 59
59 memcpy(cntx, reset_cntx, sizeof(*cntx));60 memcpy(cntx, reset_cntx, sizeof(*cntx));
61
62 WRITE_ONCE(vcpu->arch.irqs_pending, 0);
63 WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
60}64}
61 65
62int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)66int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
@@ -100,8 +104,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) · 37 unmodified lines
100 104
101int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)105int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
102{106{
103 /* TODO: */107 return kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER);
104 return 0;
105}108}
106 109
107void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)110void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
@@ -114,20 +117,18 @@ void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) · 6 unmodified lines
114 117
115int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)118int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
116{119{
117 /* TODO: */120 return (kvm_riscv_vcpu_has_interrupts(vcpu, -1UL) &&
118 return 0;121 !vcpu->arch.power_off && !vcpu->arch.pause);
119}122}
120 123
121int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)124int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
122{125{
123 /* TODO: */126 return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
124 return 0;
125}127}
126 128
127bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)129bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
128{130{
129 /* TODO: */131 return (vcpu->arch.guest_context.sstatus & SR_SPP) ? true : false;
130 return false;
131}132}
132 133
133vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)134vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
@@ -138,7 +139,21 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) · 4 unmodified lines
138long kvm_arch_vcpu_async_ioctl(struct file *filp,139long kvm_arch_vcpu_async_ioctl(struct file *filp,
139 unsigned int ioctl, unsigned long arg)140 unsigned int ioctl, unsigned long arg)
140{141{
141 /* TODO; */142 struct kvm_vcpu *vcpu = filp->private_data;
143 void __user *argp = (void __user *)arg;
144
145 if (ioctl == KVM_INTERRUPT) {
146 struct kvm_interrupt irq;
147
148 if (copy_from_user(&irq, argp, sizeof(irq)))
149 return -EFAULT;
150
151 if (irq.irq == KVM_INTERRUPT_SET)
152 return kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT);
153 else
154 return kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);
155 }
156
142 return -ENOIOCTLCMD;157 return -ENOIOCTLCMD;
143}158}
144 159
@@ -187,18 +202,123 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) · 42 unmodified lines
187 return -EINVAL;202 return -EINVAL;
188}203}
189 204
205void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
206{
207 struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
208 unsigned long mask, val;
209
210 if (READ_ONCE(vcpu->arch.irqs_pending_mask)) {
211 mask = xchg_acquire(&vcpu->arch.irqs_pending_mask, 0);
212 val = READ_ONCE(vcpu->arch.irqs_pending) & mask;
213
214 csr->hvip &= ~mask;
215 csr->hvip |= val;
216 }
217}
218
219void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
220{
221 unsigned long hvip;
222 struct kvm_vcpu_arch *v = &vcpu->arch;
223 struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
224
225 /* Read current HVIP and VSIE CSRs */
226 csr->vsie = csr_read(CSR_VSIE);
227
228 /* Sync-up HVIP.VSSIP bit changes does by Guest */
229 hvip = csr_read(CSR_HVIP);
230 if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
231 if (hvip & (1UL << IRQ_VS_SOFT)) {
232 if (!test_and_set_bit(IRQ_VS_SOFT,
233 &v->irqs_pending_mask))
234 set_bit(IRQ_VS_SOFT, &v->irqs_pending);
235 } else {
236 if (!test_and_set_bit(IRQ_VS_SOFT,
237 &v->irqs_pending_mask))
238 clear_bit(IRQ_VS_SOFT, &v->irqs_pending);
239 }
240 }
241}
242
243int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
244{
245 if (irq != IRQ_VS_SOFT &&
246 irq != IRQ_VS_TIMER &&
247 irq != IRQ_VS_EXT)
248 return -EINVAL;
249
250 set_bit(irq, &vcpu->arch.irqs_pending);
251 smp_mb__before_atomic();
252 set_bit(irq, &vcpu->arch.irqs_pending_mask);
253
254 kvm_vcpu_kick(vcpu);
255
256 return 0;
257}
258
259int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
260{
261 if (irq != IRQ_VS_SOFT &&
262 irq != IRQ_VS_TIMER &&
263 irq != IRQ_VS_EXT)
264 return -EINVAL;
265
266 clear_bit(irq, &vcpu->arch.irqs_pending);
267 smp_mb__before_atomic();
268 set_bit(irq, &vcpu->arch.irqs_pending_mask);
269
270 return 0;
271}
272
273bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask)
274{
275 unsigned long ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
276 << VSIP_TO_HVIP_SHIFT) & mask;
277
278 return (READ_ONCE(vcpu->arch.irqs_pending) & ie) ? true : false;
279}
280
281void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
282{
283 vcpu->arch.power_off = true;
284 kvm_make_request(KVM_REQ_SLEEP, vcpu);
285 kvm_vcpu_kick(vcpu);
286}
287
288void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
289{
290 vcpu->arch.power_off = false;
291 kvm_vcpu_wake_up(vcpu);
292}
293
190int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,294int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
191 struct kvm_mp_state *mp_state)295 struct kvm_mp_state *mp_state)
192{296{
193 /* TODO: */297 if (vcpu->arch.power_off)
298 mp_state->mp_state = KVM_MP_STATE_STOPPED;
299 else
300 mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
301
194 return 0;302 return 0;
195}303}
196 304
197int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,305int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
198 struct kvm_mp_state *mp_state)306 struct kvm_mp_state *mp_state)
199{307{
200 /* TODO: */308 int ret = 0;
201 return 0;309
310 switch (mp_state->mp_state) {
311 case KVM_MP_STATE_RUNNABLE:
312 vcpu->arch.power_off = false;
313 break;
314 case KVM_MP_STATE_STOPPED:
315 kvm_riscv_vcpu_power_off(vcpu);
316 break;
317 default:
318 ret = -EINVAL;
319 }
320
321 return ret;
202}322}
203 323
204int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,324int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
@@ -222,7 +342,33 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) · 17 unmodified lines
222 342
223static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)343static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
224{344{
225 /* TODO: */345 struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);
346
347 if (kvm_request_pending(vcpu)) {
348 if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
349 rcuwait_wait_event(wait,
350 (!vcpu->arch.power_off) && (!vcpu->arch.pause),
351 TASK_INTERRUPTIBLE);
352
353 if (vcpu->arch.power_off || vcpu->arch.pause) {
354 /*
355 * Awaken to handle a signal, request to
356 * sleep again later.
357 */
358 kvm_make_request(KVM_REQ_SLEEP, vcpu);
359 }
360 }
361
362 if (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))
363 kvm_riscv_reset_vcpu(vcpu);
364 }
365}
366
367static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
368{
369 struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
370
371 csr_write(CSR_HVIP, csr->hvip);
226}372}
227 373
228int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)374int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
@@ -286,6 +432,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) · 57 unmodified lines
286 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx);432 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx);
287 smp_mb__after_srcu_read_unlock();433 smp_mb__after_srcu_read_unlock();
288 434
435 /*
436 * We might have got VCPU interrupts updated asynchronously
437 * so update it in HW.
438 */
439 kvm_riscv_vcpu_flush_interrupts(vcpu);
440
441 /* Update HVIP CSR for current CPU */
442 kvm_riscv_update_hvip(vcpu);
443
289 if (ret <= 0 ||444 if (ret <= 0 ||
290 kvm_request_pending(vcpu)) {445 kvm_request_pending(vcpu)) {
291 vcpu->mode = OUTSIDE_GUEST_MODE;446 vcpu->mode = OUTSIDE_GUEST_MODE;
@@ -313,6 +468,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) · 21 unmodified lines
313 trap.htval = csr_read(CSR_HTVAL);468 trap.htval = csr_read(CSR_HTVAL);
314 trap.htinst = csr_read(CSR_HTINST);469 trap.htinst = csr_read(CSR_HTINST);
315 470
471 /* Syncup interrupts state with HW */
472 kvm_riscv_vcpu_sync_interrupts(vcpu);
473
316 /*474 /*
317 * We may have taken a host interrupt in VS/VU-mode (i.e.475 * We may have taken a host interrupt in VS/VU-mode (i.e.
318 * while executing the guest). This interrupt is still476 * while executing the guest). This interrupt is still

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t