KVM: PPC: Book3S PR: Refactor program interrupt related code into separate function
The function kvmppc_handle_exit_pr() is quite huge and thus hard to read, and even contains a "spaghetti-code"-like goto between the different case labels of the big switch statement. This can be made much more readable by moving the code related to injecting program interrupts / instruction emulation into a separate function instead. Signed-off-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
8464c8842d
commit
fcd4f3c6d1
|
@ -902,6 +902,69 @@ static void kvmppc_clear_debug(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
}
|
||||
|
||||
static int kvmppc_exit_pr_progint(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned int exit_nr)
|
||||
{
|
||||
enum emulation_result er;
|
||||
ulong flags;
|
||||
u32 last_inst;
|
||||
int emul, r;
|
||||
|
||||
/*
|
||||
* shadow_srr1 only contains valid flags if we came here via a program
|
||||
* exception. The other exceptions (emulation assist, FP unavailable,
|
||||
* etc.) do not provide flags in SRR1, so use an illegal-instruction
|
||||
* exception when injecting a program interrupt into the guest.
|
||||
*/
|
||||
if (exit_nr == BOOK3S_INTERRUPT_PROGRAM)
|
||||
flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
|
||||
else
|
||||
flags = SRR1_PROGILL;
|
||||
|
||||
emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
|
||||
if (emul != EMULATE_DONE)
|
||||
return RESUME_GUEST;
|
||||
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR) {
|
||||
#ifdef EXIT_DEBUG
|
||||
pr_info("Userspace triggered 0x700 exception at\n 0x%lx (0x%x)\n",
|
||||
kvmppc_get_pc(vcpu), last_inst);
|
||||
#endif
|
||||
if ((last_inst & 0xff0007ff) != (INS_DCBZ & 0xfffffff7)) {
|
||||
kvmppc_core_queue_program(vcpu, flags);
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
}
|
||||
|
||||
vcpu->stat.emulated_inst_exits++;
|
||||
er = kvmppc_emulate_instruction(run, vcpu);
|
||||
switch (er) {
|
||||
case EMULATE_DONE:
|
||||
r = RESUME_GUEST_NV;
|
||||
break;
|
||||
case EMULATE_AGAIN:
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
case EMULATE_FAIL:
|
||||
pr_crit("%s: emulation at %lx failed (%08x)\n",
|
||||
__func__, kvmppc_get_pc(vcpu), last_inst);
|
||||
kvmppc_core_queue_program(vcpu, flags);
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
case EMULATE_DO_MMIO:
|
||||
run->exit_reason = KVM_EXIT_MMIO;
|
||||
r = RESUME_HOST_NV;
|
||||
break;
|
||||
case EMULATE_EXIT_USER:
|
||||
r = RESUME_HOST_NV;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned int exit_nr)
|
||||
{
|
||||
|
@ -1044,71 +1107,8 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
break;
|
||||
case BOOK3S_INTERRUPT_PROGRAM:
|
||||
case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
|
||||
{
|
||||
enum emulation_result er;
|
||||
ulong flags;
|
||||
u32 last_inst;
|
||||
int emul;
|
||||
|
||||
program_interrupt:
|
||||
/*
|
||||
* shadow_srr1 only contains valid flags if we came here via
|
||||
* a program exception. The other exceptions (emulation assist,
|
||||
* FP unavailable, etc.) do not provide flags in SRR1, so use
|
||||
* an illegal-instruction exception when injecting a program
|
||||
* interrupt into the guest.
|
||||
*/
|
||||
if (exit_nr == BOOK3S_INTERRUPT_PROGRAM)
|
||||
flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
|
||||
else
|
||||
flags = SRR1_PROGILL;
|
||||
|
||||
emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
|
||||
if (emul != EMULATE_DONE) {
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR) {
|
||||
#ifdef EXIT_DEBUG
|
||||
pr_info("Userspace triggered 0x700 exception at\n 0x%lx (0x%x)\n",
|
||||
kvmppc_get_pc(vcpu), last_inst);
|
||||
#endif
|
||||
if ((last_inst & 0xff0007ff) !=
|
||||
(INS_DCBZ & 0xfffffff7)) {
|
||||
kvmppc_core_queue_program(vcpu, flags);
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vcpu->stat.emulated_inst_exits++;
|
||||
er = kvmppc_emulate_instruction(run, vcpu);
|
||||
switch (er) {
|
||||
case EMULATE_DONE:
|
||||
r = RESUME_GUEST_NV;
|
||||
break;
|
||||
case EMULATE_AGAIN:
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
case EMULATE_FAIL:
|
||||
printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
|
||||
__func__, kvmppc_get_pc(vcpu), last_inst);
|
||||
kvmppc_core_queue_program(vcpu, flags);
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
case EMULATE_DO_MMIO:
|
||||
run->exit_reason = KVM_EXIT_MMIO;
|
||||
r = RESUME_HOST_NV;
|
||||
break;
|
||||
case EMULATE_EXIT_USER:
|
||||
r = RESUME_HOST_NV;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
r = kvmppc_exit_pr_progint(run, vcpu, exit_nr);
|
||||
break;
|
||||
}
|
||||
case BOOK3S_INTERRUPT_SYSCALL:
|
||||
{
|
||||
u32 last_sc;
|
||||
|
@ -1185,7 +1185,7 @@ program_interrupt:
|
|||
emul = kvmppc_get_last_inst(vcpu, INST_GENERIC,
|
||||
&last_inst);
|
||||
if (emul == EMULATE_DONE)
|
||||
goto program_interrupt;
|
||||
r = kvmppc_exit_pr_progint(run, vcpu, exit_nr);
|
||||
else
|
||||
r = RESUME_GUEST;
|
||||
|
||||
|
|
Loading…
Reference in New Issue