mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
LoongArch: KVM: Implement handle iocsr exception
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> Tested-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
da50f5a693
commit
81efe043a3
@ -65,6 +65,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 {
|
||||
@ -318,6 +326,13 @@ struct reg2bstrd_format {
|
||||
unsigned int opcode : 10;
|
||||
};
|
||||
|
||||
struct reg2csr_format {
|
||||
unsigned int rd : 5;
|
||||
unsigned int rj : 5;
|
||||
unsigned int csr : 14;
|
||||
unsigned int opcode : 8;
|
||||
};
|
||||
|
||||
struct reg3_format {
|
||||
unsigned int rd : 5;
|
||||
unsigned int rj : 5;
|
||||
@ -346,6 +361,7 @@ union loongarch_instruction {
|
||||
struct reg2i14_format reg2i14_format;
|
||||
struct reg2i16_format reg2i16_format;
|
||||
struct reg2bstrd_format reg2bstrd_format;
|
||||
struct reg2csr_format reg2csr_format;
|
||||
struct reg3_format reg3_format;
|
||||
struct reg3sa2_format reg3sa2_format;
|
||||
};
|
||||
|
@ -103,3 +103,94 @@ 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)
|
||||
{
|
||||
int ret;
|
||||
unsigned long val;
|
||||
u32 addr, rd, rj, opcode;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
enum emulation_result er = EMULATE_DONE;
|
||||
unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
|
||||
|
||||
switch (run->iocsr_io.len) {
|
||||
case 1:
|
||||
*gpr = *(s8 *)run->iocsr_io.data;
|
||||
break;
|
||||
case 2:
|
||||
*gpr = *(s16 *)run->iocsr_io.data;
|
||||
break;
|
||||
case 4:
|
||||
*gpr = *(s32 *)run->iocsr_io.data;
|
||||
break;
|
||||
case 8:
|
||||
*gpr = *(s64 *)run->iocsr_io.data;
|
||||
break;
|
||||
default:
|
||||
kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n",
|
||||
run->iocsr_io.len, vcpu->arch.badv);
|
||||
er = EMULATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return er;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user