[v14,21/30] LoongArch: KVM: Implement handle iocsr exception

Message ID 20230619083255.3841777-22-zhaotianrui@loongson.cn
State New
Headers
Series Add KVM LoongArch support |

Commit Message

zhaotianrui June 19, 2023, 8:32 a.m. UTC
  Implement kvm handle vcpu iocsr exception, setting the iocsr info into
vcpu_run and return to user space to handle it.

Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
---
 arch/loongarch/include/asm/inst.h | 16 ++++++
 arch/loongarch/kvm/exit.c         | 92 +++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+)
  

Comments

Huacai Chen June 19, 2023, 10:13 a.m. UTC | #1
Hi, Tianrui,

On Mon, Jun 19, 2023 at 4:33 PM Tianrui Zhao <zhaotianrui@loongson.cn> wrote:
>
> Implement kvm handle vcpu iocsr exception, setting the iocsr info into
> vcpu_run and return to user space to handle it.
>
> Reviewed-by: Bibo Mao <maobibo@loongson.cn>
> Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
> ---
>  arch/loongarch/include/asm/inst.h | 16 ++++++
>  arch/loongarch/kvm/exit.c         | 92 +++++++++++++++++++++++++++++++
>  2 files changed, 108 insertions(+)
>
> diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
> index b09887ffcd15..db5857796432 100644
> --- a/arch/loongarch/include/asm/inst.h
> +++ b/arch/loongarch/include/asm/inst.h
> @@ -56,6 +56,14 @@ enum reg2_op {
>         revbd_op        = 0x0f,
>         revh2w_op       = 0x10,
>         revhd_op        = 0x11,
> +       iocsrrdb_op     = 0x19200,
> +       iocsrrdh_op     = 0x19201,
> +       iocsrrdw_op     = 0x19202,
> +       iocsrrdd_op     = 0x19203,
> +       iocsrwrb_op     = 0x19204,
> +       iocsrwrh_op     = 0x19205,
> +       iocsrwrw_op     = 0x19206,
> +       iocsrwrd_op     = 0x19207,
>  };
>
>  enum reg2i5_op {
> @@ -298,6 +306,13 @@ struct reg3sa2_format {
>         unsigned int opcode : 15;
>  };
>
> +struct reg2csr_format {
> +       unsigned int rd : 5;
> +       unsigned int rj : 5;
> +       unsigned int csr : 14;
> +       unsigned int opcode : 8;
> +};
Put it before reg3_format.

> +
>  union loongarch_instruction {
>         unsigned int word;
>         struct reg0i15_format   reg0i15_format;
> @@ -313,6 +328,7 @@ union loongarch_instruction {
>         struct reg2bstrd_format reg2bstrd_format;
>         struct reg3_format      reg3_format;
>         struct reg3sa2_format   reg3sa2_format;
> +       struct reg2csr_format   reg2csr_format;
The same, thanks.

Huacai
>  };
>
>  #define LOONGARCH_INSN_SIZE    sizeof(union loongarch_instruction)
> diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
> index 18635333fc9a..32edd915ebcb 100644
> --- a/arch/loongarch/kvm/exit.c
> +++ b/arch/loongarch/kvm/exit.c
> @@ -96,3 +96,95 @@ static int _kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
>
>         return EMULATE_DONE;
>  }
> +
> +int _kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
> +{
> +       u32 rd, rj, opcode;
> +       u32 addr;
> +       unsigned long val;
> +       int ret;
> +
> +       /*
> +        * Each IOCSR with different opcode
> +        */
> +       rd = inst.reg2_format.rd;
> +       rj = inst.reg2_format.rj;
> +       opcode = inst.reg2_format.opcode;
> +       addr = vcpu->arch.gprs[rj];
> +       ret = EMULATE_DO_IOCSR;
> +       run->iocsr_io.phys_addr = addr;
> +       run->iocsr_io.is_write = 0;
> +
> +       /* LoongArch is Little endian */
> +       switch (opcode) {
> +       case iocsrrdb_op:
> +               run->iocsr_io.len = 1;
> +               break;
> +       case iocsrrdh_op:
> +               run->iocsr_io.len = 2;
> +               break;
> +       case iocsrrdw_op:
> +               run->iocsr_io.len = 4;
> +               break;
> +       case iocsrrdd_op:
> +               run->iocsr_io.len = 8;
> +               break;
> +       case iocsrwrb_op:
> +               run->iocsr_io.len = 1;
> +               run->iocsr_io.is_write = 1;
> +               break;
> +       case iocsrwrh_op:
> +               run->iocsr_io.len = 2;
> +               run->iocsr_io.is_write = 1;
> +               break;
> +       case iocsrwrw_op:
> +               run->iocsr_io.len = 4;
> +               run->iocsr_io.is_write = 1;
> +               break;
> +       case iocsrwrd_op:
> +               run->iocsr_io.len = 8;
> +               run->iocsr_io.is_write = 1;
> +               break;
> +       default:
> +               ret = EMULATE_FAIL;
> +               break;
> +       }
> +
> +       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;
> +       }
> +
> +       return ret;
> +}
> +
> +int _kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
> +{
> +       unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
> +       enum emulation_result er = EMULATE_DONE;
> +
> +       switch (run->iocsr_io.len) {
> +       case 8:
> +               *gpr = *(s64 *)run->iocsr_io.data;
> +               break;
> +       case 4:
> +               *gpr = *(int *)run->iocsr_io.data;
> +               break;
> +       case 2:
> +               *gpr = *(short *)run->iocsr_io.data;
> +               break;
> +       case 1:
> +               *gpr = *(char *) run->iocsr_io.data;
> +               break;
> +       default:
> +               kvm_err("Bad IOCSR length: %d,addr is 0x%lx",
> +                               run->iocsr_io.len, vcpu->arch.badv);
> +               er = EMULATE_FAIL;
> +               break;
> +       }
> +
> +       return er;
> +}
> --
> 2.39.1
>
>
  
zhaotianrui June 20, 2023, 1:56 a.m. UTC | #2
在 2023/6/19 下午6:13, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Mon, Jun 19, 2023 at 4:33 PM Tianrui Zhao <zhaotianrui@loongson.cn> wrote:
>> Implement kvm handle vcpu iocsr exception, setting the iocsr info into
>> vcpu_run and return to user space to handle it.
>>
>> Reviewed-by: Bibo Mao <maobibo@loongson.cn>
>> Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
>> ---
>>   arch/loongarch/include/asm/inst.h | 16 ++++++
>>   arch/loongarch/kvm/exit.c         | 92 +++++++++++++++++++++++++++++++
>>   2 files changed, 108 insertions(+)
>>
>> diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
>> index b09887ffcd15..db5857796432 100644
>> --- a/arch/loongarch/include/asm/inst.h
>> +++ b/arch/loongarch/include/asm/inst.h
>> @@ -56,6 +56,14 @@ enum reg2_op {
>>          revbd_op        = 0x0f,
>>          revh2w_op       = 0x10,
>>          revhd_op        = 0x11,
>> +       iocsrrdb_op     = 0x19200,
>> +       iocsrrdh_op     = 0x19201,
>> +       iocsrrdw_op     = 0x19202,
>> +       iocsrrdd_op     = 0x19203,
>> +       iocsrwrb_op     = 0x19204,
>> +       iocsrwrh_op     = 0x19205,
>> +       iocsrwrw_op     = 0x19206,
>> +       iocsrwrd_op     = 0x19207,
>>   };
>>
>>   enum reg2i5_op {
>> @@ -298,6 +306,13 @@ struct reg3sa2_format {
>>          unsigned int opcode : 15;
>>   };
>>
>> +struct reg2csr_format {
>> +       unsigned int rd : 5;
>> +       unsigned int rj : 5;
>> +       unsigned int csr : 14;
>> +       unsigned int opcode : 8;
>> +};
> Put it before reg3_format.
Thanks, I will re-order it.
>
>> +
>>   union loongarch_instruction {
>>          unsigned int word;
>>          struct reg0i15_format   reg0i15_format;
>> @@ -313,6 +328,7 @@ union loongarch_instruction {
>>          struct reg2bstrd_format reg2bstrd_format;
>>          struct reg3_format      reg3_format;
>>          struct reg3sa2_format   reg3sa2_format;
>> +       struct reg2csr_format   reg2csr_format;
> The same, thanks.
>
> Huacai
I will exchange them too.

Thanks
Tianrui Zhao
>>   };
>>
>>   #define LOONGARCH_INSN_SIZE    sizeof(union loongarch_instruction)
>> diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
>> index 18635333fc9a..32edd915ebcb 100644
>> --- a/arch/loongarch/kvm/exit.c
>> +++ b/arch/loongarch/kvm/exit.c
>> @@ -96,3 +96,95 @@ static int _kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
>>
>>          return EMULATE_DONE;
>>   }
>> +
>> +int _kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
>> +{
>> +       u32 rd, rj, opcode;
>> +       u32 addr;
>> +       unsigned long val;
>> +       int ret;
>> +
>> +       /*
>> +        * Each IOCSR with different opcode
>> +        */
>> +       rd = inst.reg2_format.rd;
>> +       rj = inst.reg2_format.rj;
>> +       opcode = inst.reg2_format.opcode;
>> +       addr = vcpu->arch.gprs[rj];
>> +       ret = EMULATE_DO_IOCSR;
>> +       run->iocsr_io.phys_addr = addr;
>> +       run->iocsr_io.is_write = 0;
>> +
>> +       /* LoongArch is Little endian */
>> +       switch (opcode) {
>> +       case iocsrrdb_op:
>> +               run->iocsr_io.len = 1;
>> +               break;
>> +       case iocsrrdh_op:
>> +               run->iocsr_io.len = 2;
>> +               break;
>> +       case iocsrrdw_op:
>> +               run->iocsr_io.len = 4;
>> +               break;
>> +       case iocsrrdd_op:
>> +               run->iocsr_io.len = 8;
>> +               break;
>> +       case iocsrwrb_op:
>> +               run->iocsr_io.len = 1;
>> +               run->iocsr_io.is_write = 1;
>> +               break;
>> +       case iocsrwrh_op:
>> +               run->iocsr_io.len = 2;
>> +               run->iocsr_io.is_write = 1;
>> +               break;
>> +       case iocsrwrw_op:
>> +               run->iocsr_io.len = 4;
>> +               run->iocsr_io.is_write = 1;
>> +               break;
>> +       case iocsrwrd_op:
>> +               run->iocsr_io.len = 8;
>> +               run->iocsr_io.is_write = 1;
>> +               break;
>> +       default:
>> +               ret = EMULATE_FAIL;
>> +               break;
>> +       }
>> +
>> +       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;
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +int _kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
>> +{
>> +       unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
>> +       enum emulation_result er = EMULATE_DONE;
>> +
>> +       switch (run->iocsr_io.len) {
>> +       case 8:
>> +               *gpr = *(s64 *)run->iocsr_io.data;
>> +               break;
>> +       case 4:
>> +               *gpr = *(int *)run->iocsr_io.data;
>> +               break;
>> +       case 2:
>> +               *gpr = *(short *)run->iocsr_io.data;
>> +               break;
>> +       case 1:
>> +               *gpr = *(char *) run->iocsr_io.data;
>> +               break;
>> +       default:
>> +               kvm_err("Bad IOCSR length: %d,addr is 0x%lx",
>> +                               run->iocsr_io.len, vcpu->arch.badv);
>> +               er = EMULATE_FAIL;
>> +               break;
>> +       }
>> +
>> +       return er;
>> +}
>> --
>> 2.39.1
>>
>>
  

Patch

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index b09887ffcd15..db5857796432 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -56,6 +56,14 @@  enum reg2_op {
 	revbd_op	= 0x0f,
 	revh2w_op	= 0x10,
 	revhd_op	= 0x11,
+	iocsrrdb_op     = 0x19200,
+	iocsrrdh_op     = 0x19201,
+	iocsrrdw_op     = 0x19202,
+	iocsrrdd_op     = 0x19203,
+	iocsrwrb_op     = 0x19204,
+	iocsrwrh_op     = 0x19205,
+	iocsrwrw_op     = 0x19206,
+	iocsrwrd_op     = 0x19207,
 };
 
 enum reg2i5_op {
@@ -298,6 +306,13 @@  struct reg3sa2_format {
 	unsigned int opcode : 15;
 };
 
+struct reg2csr_format {
+	unsigned int rd : 5;
+	unsigned int rj : 5;
+	unsigned int csr : 14;
+	unsigned int opcode : 8;
+};
+
 union loongarch_instruction {
 	unsigned int word;
 	struct reg0i15_format	reg0i15_format;
@@ -313,6 +328,7 @@  union loongarch_instruction {
 	struct reg2bstrd_format	reg2bstrd_format;
 	struct reg3_format	reg3_format;
 	struct reg3sa2_format	reg3sa2_format;
+	struct reg2csr_format   reg2csr_format;
 };
 
 #define LOONGARCH_INSN_SIZE	sizeof(union loongarch_instruction)
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index 18635333fc9a..32edd915ebcb 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -96,3 +96,95 @@  static int _kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
 
 	return EMULATE_DONE;
 }
+
+int _kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	u32 rd, rj, opcode;
+	u32 addr;
+	unsigned long val;
+	int ret;
+
+	/*
+	 * Each IOCSR with different opcode
+	 */
+	rd = inst.reg2_format.rd;
+	rj = inst.reg2_format.rj;
+	opcode = inst.reg2_format.opcode;
+	addr = vcpu->arch.gprs[rj];
+	ret = EMULATE_DO_IOCSR;
+	run->iocsr_io.phys_addr = addr;
+	run->iocsr_io.is_write = 0;
+
+	/* LoongArch is Little endian */
+	switch (opcode) {
+	case iocsrrdb_op:
+		run->iocsr_io.len = 1;
+		break;
+	case iocsrrdh_op:
+		run->iocsr_io.len = 2;
+		break;
+	case iocsrrdw_op:
+		run->iocsr_io.len = 4;
+		break;
+	case iocsrrdd_op:
+		run->iocsr_io.len = 8;
+		break;
+	case iocsrwrb_op:
+		run->iocsr_io.len = 1;
+		run->iocsr_io.is_write = 1;
+		break;
+	case iocsrwrh_op:
+		run->iocsr_io.len = 2;
+		run->iocsr_io.is_write = 1;
+		break;
+	case iocsrwrw_op:
+		run->iocsr_io.len = 4;
+		run->iocsr_io.is_write = 1;
+		break;
+	case iocsrwrd_op:
+		run->iocsr_io.len = 8;
+		run->iocsr_io.is_write = 1;
+		break;
+	default:
+		ret = EMULATE_FAIL;
+		break;
+	}
+
+	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;
+	}
+
+	return ret;
+}
+
+int _kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
+	enum emulation_result er = EMULATE_DONE;
+
+	switch (run->iocsr_io.len) {
+	case 8:
+		*gpr = *(s64 *)run->iocsr_io.data;
+		break;
+	case 4:
+		*gpr = *(int *)run->iocsr_io.data;
+		break;
+	case 2:
+		*gpr = *(short *)run->iocsr_io.data;
+		break;
+	case 1:
+		*gpr = *(char *) run->iocsr_io.data;
+		break;
+	default:
+		kvm_err("Bad IOCSR length: %d,addr is 0x%lx",
+				run->iocsr_io.len, vcpu->arch.badv);
+		er = EMULATE_FAIL;
+		break;
+	}
+
+	return er;
+}