[v14,21/30] LoongArch: KVM: Implement handle iocsr exception
Commit Message
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
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
>
>
在 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
>>
>>
@@ -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)
@@ -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;
+}