From: Jintack Lim <jintack.lim@xxxxxxxxxx> Rework the system instruction emulation framework to handle potentially all system instruction traps other than MSR/MRS instructions. Those system instructions would be AT and TLBI instructions controlled by HCR_EL2.NV, AT, and TTLB bits. Signed-off-by: Jintack Lim <jintack.lim@xxxxxxxxxx> [Changed to use a generic forward_traps wrapper for forward_nv_traps] Signed-off-by: Christoffer Dall <christoffer.dall@xxxxxxx> Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx> --- arch/arm64/kvm/sys_regs.c | 62 ++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 8fbb04ddde11..0d5b7a7c76de 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1656,7 +1656,6 @@ static bool access_sp_el1(struct kvm_vcpu *vcpu, return true; } - /* This function is to support the recursive nested virtualization */ static bool forward_nv1_traps(struct kvm_vcpu *vcpu, struct sys_reg_params *p) { @@ -1703,6 +1702,12 @@ static bool access_spsr_el2(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { + if (el12_reg(p) && forward_nv_traps(vcpu)) + return false; + + if (!el12_reg(p) && forward_nv1_traps(vcpu, p)) + return false; + if (p->is_write) vcpu_write_sys_reg(vcpu, p->regval, SPSR_EL2); else @@ -1786,10 +1791,6 @@ static bool access_id_aa64pfr0_el1(struct kvm_vcpu *v, * more demanding guest... */ static const struct sys_reg_desc sys_reg_descs[] = { - { SYS_DESC(SYS_DC_ISW), access_dcsw }, - { SYS_DESC(SYS_DC_CSW), access_dcsw }, - { SYS_DESC(SYS_DC_CISW), access_dcsw }, - DBG_BCR_BVR_WCR_WVR_EL1(0), DBG_BCR_BVR_WCR_WVR_EL1(1), { SYS_DESC(SYS_MDCCINT_EL1), trap_debug_regs, reset_val, MDCCINT_EL1, 0 }, @@ -2134,6 +2135,14 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_SP_EL2), NULL, reset_unknown, SP_EL2 }, }; +#define SYS_INSN_TO_DESC(insn, access_fn, forward_fn) \ + { SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) } +static struct sys_reg_desc sys_insn_descs[] = { + { SYS_DESC(SYS_DC_ISW), access_dcsw }, + { SYS_DESC(SYS_DC_CSW), access_dcsw }, + { SYS_DESC(SYS_DC_CISW), access_dcsw }, +}; + static bool trap_dbgidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -2755,38 +2764,22 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu, return 1; } -static int emulate_tlbi(struct kvm_vcpu *vcpu, - struct sys_reg_params *params) +static int emulate_sys_instr(struct kvm_vcpu *vcpu, struct sys_reg_params *p) { - /* TODO: support tlbi instruction emulation*/ - kvm_inject_undefined(vcpu); - return 1; -} - -static int emulate_at(struct kvm_vcpu *vcpu, - struct sys_reg_params *params) -{ - /* TODO: support address translation instruction emulation */ - kvm_inject_undefined(vcpu); - return 1; -} - -static int emulate_sys_instr(struct kvm_vcpu *vcpu, - struct sys_reg_params *params) -{ - int ret = 0; - - /* TLB maintenance instructions*/ - if (params->CRn == 0b1000) - ret = emulate_tlbi(vcpu, params); - /* Address Translation instructions */ - else if (params->CRn == 0b0111 && params->CRm == 0b1000) - ret = emulate_at(vcpu, params); + const struct sys_reg_desc *r; - if (ret) - kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + /* Search from the system instruction table. */ + r = find_reg(p, sys_insn_descs, ARRAY_SIZE(sys_insn_descs)); - return ret; + if (likely(r)) { + perform_access(vcpu, p, r); + } else { + kvm_err("Unsupported guest sys instruction at: %lx\n", + *vcpu_pc(vcpu)); + print_sys_reg_instr(p); + kvm_inject_undefined(vcpu); + } + return 1; } static void reset_sys_reg_descs(struct kvm_vcpu *vcpu, @@ -3282,6 +3275,7 @@ void kvm_sys_reg_table_init(void) BUG_ON(check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs))); BUG_ON(check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs))); BUG_ON(check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs))); + BUG_ON(check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs))); /* We abuse the reset function to overwrite the table itself. */ for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) -- 2.20.1