Message ID | 20240705023854.1005258-2-lixianglai@loongson.cn (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Added Interrupt controller emulation for loongarch kvm | expand |
On 2024/7/5 上午10:38, Xianglai Li wrote: > 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: Tianrui Zhao <zhaotianrui@loongson.cn> > Signed-off-by: Xianglai Li <lixianglai@loongson.cn> > --- > Cc: Bibo Mao <maobibo@loongson.cn> > Cc: Huacai Chen <chenhuacai@kernel.org> > Cc: kvm@vger.kernel.org > Cc: loongarch@lists.linux.dev > Cc: Min Zhou <zhoumin@loongson.cn> > Cc: Paolo Bonzini <pbonzini@redhat.com> > Cc: Tianrui Zhao <zhaotianrui@loongson.cn> > Cc: WANG Xuerui <kernel@xen0n.name> > Cc: Xianglai li <lixianglai@loongson.cn> > > arch/loongarch/kvm/exit.c | 69 ++++++++++++++++++++++++++++----------- > include/linux/kvm_host.h | 1 + > 2 files changed, 51 insertions(+), 19 deletions(-) > > diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c > index a68573e091c0..e8e37e135dd1 100644 > --- a/arch/loongarch/kvm/exit.c > +++ b/arch/loongarch/kvm/exit.c > @@ -148,7 +148,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; > > /* > @@ -161,6 +161,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) { > @@ -194,15 +195,21 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) > break; > default: > ret = EMULATE_FAIL; > - break; > + return ret; How about directly return such as *return EMULATE_FAIL;* ? > } > > - 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); > - } > - vcpu->arch.io_gpr = rd; > + if (run->iocsr_io.is_write) { > + if (!kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val)) It exceeds 80 chars, it will be better if line wrapper is added. > + 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)) Ditto. > + ret = EMULATE_DONE; > + else > + /* Save register id for iocsr read completion */ > + vcpu->arch.io_gpr = rd; > } > > return ret; > @@ -438,19 +445,33 @@ 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; > trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len, > run->mmio.phys_addr, NULL); Should the trace function be called for KVM_MMIO_BUS also? I think the trace function should be called before kvm_io_bus_read. > - } else { > - 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 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; > + Empty line is not necessary from my view :) > return ret; > } > > @@ -591,19 +612,29 @@ 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; > trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, > run->mmio.phys_addr, data); Ditto, trace function should be put before kvm_io_bus_write. > - } else { > - 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 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; > } > > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index 692c01e41a18..f51b2e53d81c 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -219,6 +219,7 @@ enum kvm_bus { > KVM_PIO_BUS, > KVM_VIRTIO_CCW_NOTIFY_BUS, > KVM_FAST_MMIO_BUS, > + KVM_IOCSR_BUS, > KVM_NR_BUSES > }; I just think this patch should be after PCH/EXTIOI/IPI is created and IOCSR/MMIO space is registered in kernel space.It is only my points, I am not good at this:( Regards Bibo Mao > >
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index a68573e091c0..e8e37e135dd1 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -148,7 +148,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; /* @@ -161,6 +161,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) { @@ -194,15 +195,21 @@ 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); - } - vcpu->arch.io_gpr = rd; + if (run->iocsr_io.is_write) { + 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; } return ret; @@ -438,19 +445,33 @@ 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; trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len, run->mmio.phys_addr, NULL); - } else { - 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 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; } @@ -591,19 +612,29 @@ 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; trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, run->mmio.phys_addr, data); - } else { - 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 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; } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 692c01e41a18..f51b2e53d81c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -219,6 +219,7 @@ enum kvm_bus { KVM_PIO_BUS, KVM_VIRTIO_CCW_NOTIFY_BUS, KVM_FAST_MMIO_BUS, + KVM_IOCSR_BUS, KVM_NR_BUSES };