On Wed, Jan 8, 2020 at 6:52 PM Alexandru Elisei <alexandru.elisei@xxxxxxx> wrote: > > Hi, > > On 12/25/19 3:00 AM, Anup Patel wrote: > > This patch implements kvm_cpu__<xyz> Guest/VM VCPU arch functions. > > > > These functions mostly deal with: > > 1. VCPU allocation and initialization > > 2. VCPU reset > > 3. VCPU show/dump code > > 4. VCPU show/dump registers > > > > We also save RISC-V ISA, XLEN, and TIMEBASE frequency for each VCPU > > so that it can be later used for generating Guest/VM FDT. > > > > Signed-off-by: Anup Patel <anup.patel@xxxxxxx> > > --- > > riscv/include/kvm/kvm-cpu-arch.h | 4 + > > riscv/kvm-cpu.c | 307 ++++++++++++++++++++++++++++++- > > 2 files changed, 304 insertions(+), 7 deletions(-) > > > > diff --git a/riscv/include/kvm/kvm-cpu-arch.h b/riscv/include/kvm/kvm-cpu-arch.h > > index 09a50e8..035965e 100644 > > --- a/riscv/include/kvm/kvm-cpu-arch.h > > +++ b/riscv/include/kvm/kvm-cpu-arch.h > > @@ -14,6 +14,10 @@ struct kvm_cpu { > > > > unsigned long cpu_id; > > > > + unsigned long riscv_xlen; > > + unsigned long riscv_isa; > > + unsigned long riscv_timebase; > > + > > struct kvm *kvm; > > int vcpu_fd; > > struct kvm_run *kvm_run; > > diff --git a/riscv/kvm-cpu.c b/riscv/kvm-cpu.c > > index e4b8fa5..1565275 100644 > > --- a/riscv/kvm-cpu.c > > +++ b/riscv/kvm-cpu.c > > @@ -17,10 +17,84 @@ int kvm_cpu__get_debug_fd(void) > > return debug_fd; > > } > > > > +static __u64 __kvm_reg_id(__u64 type, __u64 idx) > > +{ > > + __u64 id = KVM_REG_RISCV | type | idx; > > + > > + if (sizeof(unsigned long) == 8) > > This looks fragile. As far as I know, according to C99 the minimum width of > unsigned long is 32 bits. Why not use __riscv_xlen instead? Good suggestion. I will use __riscv_xlen here. > > Thanks, > Alex > > + id |= KVM_REG_SIZE_U64; > > + else > > + id |= KVM_REG_SIZE_U32; > > + > > + return id; > > +} > > + > > +#define RISCV_CONFIG_REG(name) __kvm_reg_id(KVM_REG_RISCV_CONFIG, \ > > + KVM_REG_RISCV_CONFIG_REG(name)) > > + > > +#define RISCV_CORE_REG(name) __kvm_reg_id(KVM_REG_RISCV_CORE, \ > > + KVM_REG_RISCV_CORE_REG(name)) > > + > > +#define RISCV_CSR_REG(name) __kvm_reg_id(KVM_REG_RISCV_CSR, \ > > + KVM_REG_RISCV_CSR_REG(name)) > > + > > +#define RISCV_TIMER_REG(name) __kvm_reg_id(KVM_REG_RISCV_TIMER, \ > > + KVM_REG_RISCV_TIMER_REG(name)) > > + > > struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) > > { > > - /* TODO: */ > > - return NULL; > > + struct kvm_cpu *vcpu; > > + unsigned long timebase = 0, isa = 0; > > + int coalesced_offset, mmap_size; > > + struct kvm_one_reg reg; > > + > > + vcpu = calloc(1, sizeof(struct kvm_cpu)); > > + if (!vcpu) > > + return NULL; > > + > > + vcpu->vcpu_fd = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, cpu_id); > > + if (vcpu->vcpu_fd < 0) > > + die_perror("KVM_CREATE_VCPU ioctl"); > > + > > + reg.id = RISCV_CONFIG_REG(isa); > > + reg.addr = (unsigned long)&isa; > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (config.isa)"); > > + > > + reg.id = RISCV_TIMER_REG(frequency); > > + reg.addr = (unsigned long)&timebase; > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (config.timebase)"); > > + > > + mmap_size = ioctl(kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0); > > + if (mmap_size < 0) > > + die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl"); > > + > > + vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, > > + vcpu->vcpu_fd, 0); > > + if (vcpu->kvm_run == MAP_FAILED) > > + die("unable to mmap vcpu fd"); > > + > > + coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, > > + KVM_CAP_COALESCED_MMIO); > > + if (coalesced_offset) > > + vcpu->ring = (void *)vcpu->kvm_run + > > + (coalesced_offset * PAGE_SIZE); > > + > > + reg.id = RISCV_CONFIG_REG(isa); > > + reg.addr = (unsigned long)&isa; > > + if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®) < 0) > > + die("KVM_SET_ONE_REG failed (config.isa)"); > > + > > + /* Populate the vcpu structure. */ > > + vcpu->kvm = kvm; > > + vcpu->cpu_id = cpu_id; > > + vcpu->riscv_isa = isa; > > + vcpu->riscv_xlen = __riscv_xlen; > > + vcpu->riscv_timebase = timebase; > > + vcpu->is_running = true; > > + > > + return vcpu; > > } > > > > void kvm_cpu__arch_nmi(struct kvm_cpu *cpu) > > @@ -29,7 +103,7 @@ void kvm_cpu__arch_nmi(struct kvm_cpu *cpu) > > > > void kvm_cpu__delete(struct kvm_cpu *vcpu) > > { > > - /* TODO: */ > > + free(vcpu); > > } > > > > bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu) > > @@ -40,12 +114,43 @@ bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu) > > > > void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu) > > { > > - /* TODO: */ > > } > > > > void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu) > > { > > - /* TODO: */ > > + struct kvm *kvm = vcpu->kvm; > > + struct kvm_mp_state mp_state; > > + struct kvm_one_reg reg; > > + unsigned long data; > > + > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_MP_STATE, &mp_state) < 0) > > + die_perror("KVM_GET_MP_STATE failed"); > > + > > + /* > > + * If MP state is stopped then it means Linux KVM RISC-V emulates > > + * SBI v0.2 (or higher) with HART power managment and give VCPU > > + * will power-up at boot-time by boot VCPU. For such VCPU, we > > + * don't update PC, A0 and A1 here. > > + */ > > + if (mp_state.mp_state == KVM_MP_STATE_STOPPED) > > + return; > > + > > + reg.addr = (unsigned long)&data; > > + > > + data = kvm->arch.kern_guest_start; > > + reg.id = RISCV_CORE_REG(regs.pc); > > + if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®) < 0) > > + die_perror("KVM_SET_ONE_REG failed (pc)"); > > + > > + data = vcpu->cpu_id; > > + reg.id = RISCV_CORE_REG(regs.a0); > > + if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®) < 0) > > + die_perror("KVM_SET_ONE_REG failed (a0)"); > > + > > + data = kvm->arch.dtb_guest_start; > > + reg.id = RISCV_CORE_REG(regs.a1); > > + if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®) < 0) > > + die_perror("KVM_SET_ONE_REG failed (a1)"); > > } > > > > int kvm_cpu__get_endianness(struct kvm_cpu *vcpu) > > @@ -55,10 +160,198 @@ int kvm_cpu__get_endianness(struct kvm_cpu *vcpu) > > > > void kvm_cpu__show_code(struct kvm_cpu *vcpu) > > { > > - /* TODO: */ > > + struct kvm_one_reg reg; > > + unsigned long data; > > + int debug_fd = kvm_cpu__get_debug_fd(); > > + > > + reg.addr = (unsigned long)&data; > > + > > + dprintf(debug_fd, "\n*PC:\n"); > > + reg.id = RISCV_CORE_REG(regs.pc); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (show_code @ PC)"); > > + > > + kvm__dump_mem(vcpu->kvm, data, 32, debug_fd); > > + > > + dprintf(debug_fd, "\n*RA:\n"); > > + reg.id = RISCV_CORE_REG(regs.ra); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (show_code @ RA)"); > > + > > + kvm__dump_mem(vcpu->kvm, data, 32, debug_fd); > > } > > > > void kvm_cpu__show_registers(struct kvm_cpu *vcpu) > > { > > - /* TODO: */ > > + struct kvm_one_reg reg; > > + unsigned long data; > > + int debug_fd = kvm_cpu__get_debug_fd(); > > + > > + reg.addr = (unsigned long)&data; > > + dprintf(debug_fd, "\n Registers:\n"); > > + > > + reg.id = RISCV_CORE_REG(mode); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (mode)"); > > + dprintf(debug_fd, " MODE: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.pc); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (pc)"); > > + dprintf(debug_fd, " PC: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.ra); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (ra)"); > > + dprintf(debug_fd, " RA: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.sp); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (sp)"); > > + dprintf(debug_fd, " SP: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.gp); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (gp)"); > > + dprintf(debug_fd, " GP: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.tp); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (tp)"); > > + dprintf(debug_fd, " TP: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t0); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t0)"); > > + dprintf(debug_fd, " T0: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t1); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t1)"); > > + dprintf(debug_fd, " T1: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t2); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t2)"); > > + dprintf(debug_fd, " T2: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s0); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s0)"); > > + dprintf(debug_fd, " S0: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s1); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s1)"); > > + dprintf(debug_fd, " S1: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a0); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a0)"); > > + dprintf(debug_fd, " A0: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a1); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a1)"); > > + dprintf(debug_fd, " A1: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a2); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a2)"); > > + dprintf(debug_fd, " A2: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a3); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a3)"); > > + dprintf(debug_fd, " A3: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a4); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a4)"); > > + dprintf(debug_fd, " A4: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a5); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a5)"); > > + dprintf(debug_fd, " A5: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a6); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a6)"); > > + dprintf(debug_fd, " A6: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.a7); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (a7)"); > > + dprintf(debug_fd, " A7: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s2); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s2)"); > > + dprintf(debug_fd, " S2: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s3); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s3)"); > > + dprintf(debug_fd, " S3: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s4); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s4)"); > > + dprintf(debug_fd, " S4: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s5); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s5)"); > > + dprintf(debug_fd, " S5: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s6); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s6)"); > > + dprintf(debug_fd, " S6: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s7); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s7)"); > > + dprintf(debug_fd, " S7: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s8); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s8)"); > > + dprintf(debug_fd, " S8: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s9); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s9)"); > > + dprintf(debug_fd, " S9: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s10); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s10)"); > > + dprintf(debug_fd, " S10: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.s11); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (s11)"); > > + dprintf(debug_fd, " S11: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t3); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t3)"); > > + dprintf(debug_fd, " T3: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t4); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t4)"); > > + dprintf(debug_fd, " T4: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t5); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t5)"); > > + dprintf(debug_fd, " T5: 0x%lx\n", data); > > + > > + reg.id = RISCV_CORE_REG(regs.t6); > > + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®) < 0) > > + die("KVM_GET_ONE_REG failed (t6)"); > > + dprintf(debug_fd, " T6: 0x%lx\n", data); > > } Regards, Anup