Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

RISC-V: KVM: Handle WFI exits for VCPU

We get illegal instruction trap whenever Guest/VM executes WFI
instruction.

This patch handles WFI trap by blocking the trapped VCPU using
kvm_vcpu_block() API. The blocked VCPU will be automatically
resumed whenever a VCPU interrupt is injected from user-space
or from in-kernel IRQCHIP emulation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

authored by

Anup Patel and committed by
Anup Patel
5a5d79ac 9f701326

+76
+76
arch/riscv/kvm/vcpu_exit.c
··· 12 12 #include <linux/kvm_host.h> 13 13 #include <asm/csr.h> 14 14 15 + #define INSN_OPCODE_MASK 0x007c 16 + #define INSN_OPCODE_SHIFT 2 17 + #define INSN_OPCODE_SYSTEM 28 18 + 19 + #define INSN_MASK_WFI 0xffffffff 20 + #define INSN_MATCH_WFI 0x10500073 21 + 15 22 #define INSN_MATCH_LB 0x3 16 23 #define INSN_MASK_LB 0x707f 17 24 #define INSN_MATCH_LH 0x1003 ··· 122 115 #define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \ 123 116 (s32)(((insn) >> 7) & 0x1f)) 124 117 #define MASK_FUNCT3 0x7000 118 + 119 + static int truly_illegal_insn(struct kvm_vcpu *vcpu, 120 + struct kvm_run *run, 121 + ulong insn) 122 + { 123 + struct kvm_cpu_trap utrap = { 0 }; 124 + 125 + /* Redirect trap to Guest VCPU */ 126 + utrap.sepc = vcpu->arch.guest_context.sepc; 127 + utrap.scause = EXC_INST_ILLEGAL; 128 + utrap.stval = insn; 129 + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); 130 + 131 + return 1; 132 + } 133 + 134 + static int system_opcode_insn(struct kvm_vcpu *vcpu, 135 + struct kvm_run *run, 136 + ulong insn) 137 + { 138 + if ((insn & INSN_MASK_WFI) == INSN_MATCH_WFI) { 139 + vcpu->stat.wfi_exit_stat++; 140 + if (!kvm_arch_vcpu_runnable(vcpu)) { 141 + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); 142 + kvm_vcpu_block(vcpu); 143 + vcpu->arch.srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 144 + kvm_clear_request(KVM_REQ_UNHALT, vcpu); 145 + } 146 + vcpu->arch.guest_context.sepc += INSN_LEN(insn); 147 + return 1; 148 + } 149 + 150 + return truly_illegal_insn(vcpu, run, insn); 151 + } 152 + 153 + static int virtual_inst_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, 154 + struct kvm_cpu_trap *trap) 155 + { 156 + unsigned long insn = trap->stval; 157 + struct kvm_cpu_trap utrap = { 0 }; 158 + struct kvm_cpu_context *ct; 159 + 160 + if (unlikely(INSN_IS_16BIT(insn))) { 161 + if (insn == 0) { 162 + ct = &vcpu->arch.guest_context; 163 + insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, 164 + ct->sepc, 165 + &utrap); 166 + if (utrap.scause) { 167 + utrap.sepc = ct->sepc; 168 + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); 169 + return 1; 170 + } 171 + } 172 + if (INSN_IS_16BIT(insn)) 173 + return truly_illegal_insn(vcpu, run, insn); 174 + } 175 + 176 + switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) { 177 + case INSN_OPCODE_SYSTEM: 178 + return system_opcode_insn(vcpu, run, insn); 179 + default: 180 + return truly_illegal_insn(vcpu, run, insn); 181 + } 182 + } 125 183 126 184 static int emulate_load(struct kvm_vcpu *vcpu, struct kvm_run *run, 127 185 unsigned long fault_addr, unsigned long htinst) ··· 668 596 ret = -EFAULT; 669 597 run->exit_reason = KVM_EXIT_UNKNOWN; 670 598 switch (trap->scause) { 599 + case EXC_VIRTUAL_INST_FAULT: 600 + if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV) 601 + ret = virtual_inst_fault(vcpu, run, trap); 602 + break; 671 603 case EXC_INST_GUEST_PAGE_FAULT: 672 604 case EXC_LOAD_GUEST_PAGE_FAULT: 673 605 case EXC_STORE_GUEST_PAGE_FAULT: