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
127127 /* CPU CSR context upon Guest VCPU reset */
128128 struct kvm_vcpu_csr guest_reset_csr;
129129
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+
130145 /* Don't run the VCPU (blocked) */
131146 bool pause;
132147
@@ -150,4 +165,12 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, · 17 unmodified lines
150165
151166 static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) {}
152167
168+int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
169+int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
170+void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu);
171+void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu);
172+bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask);
173+void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu);
174+void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu);
175+
153176 #endif /* __RISCV_KVM_HOST_H__ */
arch/riscv/include/uapi/asm/kvm.h+3−0
@@ -18,6 +18,9 @@ · 17 unmodified lines
1818
1919 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
2020
21+#define KVM_INTERRUPT_SET -1U
22+#define KVM_INTERRUPT_UNSET -2U
23+
2124 /* for KVM_GET_REGS and KVM_SET_REGS */
2225 struct kvm_regs {
2326 };
arch/riscv/kvm/vcpu.c+171−13
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include <linux/err.h>
1212 #include <linux/kdebug.h>
1313 #include <linux/module.h>
14+#include <linux/percpu.h>
1415 #include <linux/uaccess.h>
1516 #include <linux/vmalloc.h>
1617 #include <linux/sched/signal.h>
@@ -57,6 +58,9 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) · 40 unmodified lines
5758 memcpy(csr, reset_csr, sizeof(*csr));
5859
5960 memcpy(cntx, reset_cntx, sizeof(*cntx));
61+
62+ WRITE_ONCE(vcpu->arch.irqs_pending, 0);
63+ WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
6064 }
6165
6266 int 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
100104
101105 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
102106 {
103− /* TODO: */
104− return 0;
107+ return kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER);
105108 }
106109
107110 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
@@ -114,20 +117,18 @@ void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) · 6 unmodified lines
114117
115118 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
116119 {
117− /* TODO: */
118− return 0;
120+ return (kvm_riscv_vcpu_has_interrupts(vcpu, -1UL) &&
121+ !vcpu->arch.power_off && !vcpu->arch.pause);
119122 }
120123
121124 int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
122125 {
123− /* TODO: */
124− return 0;
126+ return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
125127 }
126128
127129 bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
128130 {
129− /* TODO: */
130− return false;
131+ return (vcpu->arch.guest_context.sstatus & SR_SPP) ? true : false;
131132 }
132133
133134 vm_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
138139 long kvm_arch_vcpu_async_ioctl(struct file *filp,
139140 unsigned int ioctl, unsigned long arg)
140141 {
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+
142157 return -ENOIOCTLCMD;
143158 }
144159
@@ -187,18 +202,123 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) · 42 unmodified lines
187202 return -EINVAL;
188203 }
189204
205+void 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+
219+void 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+
243+int 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+
259+int 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+
273+bool 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+
281+void 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+
288+void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
289+{
290+ vcpu->arch.power_off = false;
291+ kvm_vcpu_wake_up(vcpu);
292+}
293+
190294 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
191295 struct kvm_mp_state *mp_state)
192296 {
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+
194302 return 0;
195303 }
196304
197305 int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
198306 struct kvm_mp_state *mp_state)
199307 {
200− /* TODO: */
201− return 0;
308+ int ret = 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;
202322 }
203323
204324 int 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
222342
223343 static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
224344 {
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+
367+static 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);
226372 }
227373
228374 int 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
286432 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx);
287433 smp_mb__after_srcu_read_unlock();
288434
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+
289444 if (ret <= 0 ||
290445 kvm_request_pending(vcpu)) {
291446 vcpu->mode = OUTSIDE_GUEST_MODE;
@@ -313,6 +468,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) · 21 unmodified lines
313468 trap.htval = csr_read(CSR_HTVAL);
314469 trap.htinst = csr_read(CSR_HTINST);
315470
471+ /* Syncup interrupts state with HW */
472+ kvm_riscv_vcpu_sync_interrupts(vcpu);
473+
316474 /*
317475 * We may have taken a host interrupt in VS/VU-mode (i.e.
318476 * 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