Commit 59b3f87e authored by Xianglai Li's avatar Xianglai Li
Browse files

LoongArch: KVM: Add iocsr and mmio bus simulation in kernel

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IB8FOC



------------------------------------------

Add iocsr and mmio memory read and write simulation to the kernel.
When the VM accesses the device address space through iocsr
instructions or mmio, it does not need to return to the qemu
user mode but directly completes the access in the kernel mode.

Signed-off-by: default avatarTianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent 40d8143f
Loading
Loading
Loading
Loading
+51 −19
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
{
	int ret;
	unsigned long val;
	unsigned long *val;
	u32 addr, rd, rj, opcode;

	/*
@@ -128,6 +128,7 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
	ret = EMULATE_DO_IOCSR;
	run->iocsr_io.phys_addr = addr;
	run->iocsr_io.is_write = 0;
	val = &vcpu->arch.gprs[rd];

	/* LoongArch is Little endian */
	switch (opcode) {
@@ -161,14 +162,20 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
		break;
	default:
		ret = EMULATE_FAIL;
		break;
		return ret;
	}

	if (ret == EMULATE_DO_IOCSR) {
	if (run->iocsr_io.is_write) {
			val = vcpu->arch.gprs[rd];
			memcpy(run->iocsr_io.data, &val, run->iocsr_io.len);
		}
		if (!kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val))
			ret = EMULATE_DONE;
		else
			/* Save data and let user space to write it */
			memcpy(run->iocsr_io.data, val, run->iocsr_io.len);
	} else {
		if (!kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val))
			ret = EMULATE_DONE;
		else
			/* Save register id for iocsr read completion */
			vcpu->arch.io_gpr = rd;
	}

@@ -457,16 +464,30 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
	}

	if (ret == EMULATE_DO_MMIO) {
		/*
		 * if mmio device such as pch pic is emulated in KVM,
		 * it need not return to user space to handle the mmio
		 * exception.
		 */
		ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, vcpu->arch.badv,
				run->mmio.len, &vcpu->arch.gprs[rd]);
		if (!ret) {
			update_pc(&vcpu->arch);
			vcpu->mmio_needed = 0;
			return EMULATE_DONE;
		}

		/* Set for kvm_complete_mmio_read() use */
		vcpu->arch.io_gpr = rd;
		run->mmio.is_write = 0;
		vcpu->mmio_is_write = 0;
	} else {
		return EMULATE_DO_MMIO;
	}

	kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
			inst.word, vcpu->arch.pc, vcpu->arch.badv);
	kvm_arch_vcpu_dump_regs(vcpu);
	vcpu->mmio_needed = 0;
	}

	return ret;
}
@@ -605,16 +626,27 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
	}

	if (ret == EMULATE_DO_MMIO) {
		/*
		 * if mmio device such as pch pic is emulated in KVM,
		 * it need not return to user space to handle the mmio
		 * exception.
		 */
		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, vcpu->arch.badv,
				run->mmio.len, data);
		if (!ret)
			return EMULATE_DONE;

		run->mmio.is_write = 1;
		vcpu->mmio_needed = 1;
		vcpu->mmio_is_write = 1;
	} else {
		return EMULATE_DO_MMIO;
	}

	vcpu->arch.pc = curr_pc;
	kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
			inst.word, vcpu->arch.pc, vcpu->arch.badv);
	kvm_arch_vcpu_dump_regs(vcpu);
	/* Rollback PC if emulation was unsuccessful */
	}

	return ret;
}
+1 −0
Original line number Diff line number Diff line
@@ -216,6 +216,7 @@ enum kvm_bus {
	KVM_PIO_BUS,
	KVM_VIRTIO_CCW_NOTIFY_BUS,
	KVM_FAST_MMIO_BUS,
	KVM_IOCSR_BUS,
	KVM_NR_BUSES
};