blob: bcc06c0dd618757c844a54cfc86c0bc8c9beab58 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 - os kernal
* Author: fire3 <fire3@example.com> yangzh <yangzh@gmail.com>
* linhn <linhn@example.com>
*/
#include <asm/kvm_emulate.h>
#include <linux/errno.h>
#include <linux/err.h>
void sw64_decode(struct kvm_vcpu *vcpu, unsigned int insn, struct kvm_run *run)
{
int opc, ra;
opc = (insn >> 26) & 0x3f;
ra = (insn >> 21) & 0x1f;
switch (opc) {
case 0x20: /* LDBU */
run->mmio.is_write = 0;
run->mmio.len = 1;
vcpu->arch.mmio_decode.rt = ra;
break;
case 0x21: /* LDHU */
run->mmio.is_write = 0;
run->mmio.len = 2;
vcpu->arch.mmio_decode.rt = ra;
break;
case 0x22: /* LDW */
run->mmio.is_write = 0;
run->mmio.len = 4;
vcpu->arch.mmio_decode.rt = ra;
break;
case 0x23: /* LDL */
case 0x24: /* LDL_U */
run->mmio.is_write = 0;
run->mmio.len = 8;
vcpu->arch.mmio_decode.rt = ra;
break;
case 0x28: /* STB */
run->mmio.is_write = 1;
*(unsigned long *)run->mmio.data = vcpu_get_reg(vcpu, ra) & 0xffUL;
run->mmio.len = 1;
break;
case 0x29: /* STH */
run->mmio.is_write = 1;
*(unsigned long *)run->mmio.data = vcpu_get_reg(vcpu, ra) & 0xffffUL;
run->mmio.len = 2;
break;
case 0x2a: /* STW */
run->mmio.is_write = 1;
*(unsigned long *)run->mmio.data = vcpu_get_reg(vcpu, ra) & 0xffffffffUL;
run->mmio.len = 4;
break;
case 0x2b: /* STL */
case 0x2c: /* STL_U */
run->mmio.is_write = 1;
*(unsigned long *)run->mmio.data = vcpu_get_reg(vcpu, ra);
run->mmio.len = 8;
break;
default:
printk("Miss done opc %d\n", opc);
break;
}
}
/*
* Virtual Interrupts.
*/
unsigned int interrupt_pending(struct kvm_vcpu *vcpu, bool *more)
{
unsigned int irq;
DECLARE_BITMAP(blk, SWVM_IRQS);
bitmap_copy(blk, vcpu->arch.irqs_pending, SWVM_IRQS);
irq = find_last_bit(blk, SWVM_IRQS);
return irq;
}
void clear_vcpu_irq(struct kvm_vcpu *vcpu)
{
vcpu->arch.vcb.vcpu_irq = 0xffffffffffffffffUL;
}
void inject_vcpu_irq(struct kvm_vcpu *vcpu, unsigned int irq)
{
vcpu->arch.vcb.vcpu_irq = irq;
}
/*
* This actually diverts the Guest to running an interrupt handler, once an
* interrupt has been identified by interrupt_pending().
*/
void try_deliver_interrupt(struct kvm_vcpu *vcpu, unsigned int irq, bool more)
{
BUG_ON(irq >= SWVM_IRQS);
/* Otherwise we check if they have interrupts disabled. */
if (vcpu->arch.vcb.vcpu_irq_disabled) {
clear_vcpu_irq(vcpu);
return;
}
/* If they don't have a handler (yet?), we just ignore it */
if (vcpu->arch.vcb.ent_int != 0) {
/* OK, mark it no longer pending and deliver it. */
clear_bit(irq, (vcpu->arch.irqs_pending));
/*
* set_guest_interrupt() takes the interrupt descriptor and a
* flag to say whether this interrupt pushes an error code onto
* the stack as well: virtual interrupts never do.
*/
inject_vcpu_irq(vcpu, irq);
}
}