From patchwork Mon Oct 16 15:58:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dongjiu Geng X-Patchwork-Id: 10009059 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A0EDF601D5 for ; Mon, 16 Oct 2017 16:00:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93632285DD for ; Mon, 16 Oct 2017 16:00:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 881AA28614; Mon, 16 Oct 2017 16:00:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D74D5285DD for ; Mon, 16 Oct 2017 16:00:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753080AbdJPQAf (ORCPT ); Mon, 16 Oct 2017 12:00:35 -0400 Received: from szxga05-in.huawei.com ([45.249.212.191]:8060 "EHLO szxga05-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752968AbdJPQAd (ORCPT ); Mon, 16 Oct 2017 12:00:33 -0400 Received: from 172.30.72.59 (EHLO DGGEMS401-HUB.china.huawei.com) ([172.30.72.59]) by dggrg05-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJG05677; Tue, 17 Oct 2017 00:00:25 +0800 (CST) Received: from SHA150392835-N.china.huawei.com (10.45.126.227) by DGGEMS401-HUB.china.huawei.com (10.3.19.201) with Microsoft SMTP Server id 14.3.301.0; Mon, 16 Oct 2017 23:58:54 +0800 From: Dongjiu Geng To: , , , , , , , , , , , Subject: [PATCH v2] arm/arm64: KVM: set right LR register value for 32 bit guest when inject abort Date: Mon, 16 Oct 2017 23:58:40 +0800 Message-ID: <20171016155840.33584-1-gengdongjiu@huawei.com> X-Mailer: git-send-email 2.11.0.windows.1 MIME-Version: 1.0 X-Originating-IP: [10.45.126.227] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090206.59E4D79A.0133, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: fefe1e8c11749a7fcd6f070b53576ba9 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When a exception is trapped to EL2, hardware uses ELR_ELx to hold the current fault instruction address. If KVM wants to inject a abort to 32 bit guest, it needs to set the LR register for the guest to emulate this abort happened in the guest. Because ARM32 architecture is pipelined execution, so the LR value has an offset to the fault instruction address. The offsets applied to Link value for exceptions as shown below, which should be added for the ARM32 link register(LR). Table taken from ARMv8 ARM DDI0487B-B, table G1-10: Exception Offset, for PE state of: A32 T32 Undefined Instruction +4 +2 Prefetch Abort +4 +4 Data Abort +8 +8 IRQ or FIQ +4 +4 Signed-off-by: Dongjiu Geng Tested-by: Haibin Zhang --- Note: now only test it in the arm64 host because there is no arm32 host environment, firstly send the patch out for review. In the arm64 platform, to the undefined instruction injection: 1. Guest OS call SMC(Secure Monitor Call) instruction in the address 0xc025405c, then Guest traps to hypervisor c0254050: e59d5028 ldr r5, [sp, #40] ; 0x28 c0254054: e3a03001 mov r3, #1 c0254058: e1a01003 mov r1, r3 c025405c: e1600070 smc 0 c0254060: e30a0270 movw r0, #41584 ; 0xa270 c0254064: e34c00bf movt r0, #49343 ; 0xc0bf 2. KVM injects undefined abort to guest 3. We will find the fault PC is 0xc0254058, not 0xc025405c. [ 12.348072] Internal error: Oops - undefined instruction: 0 [#1] SMP ARM [ 12.349786] Modules linked in: [ 12.350563] CPU: 1 PID: 71 Comm: cat Not tainted 4.1.0-dirty #25 [ 12.352061] Hardware name: Generic DT based system [ 12.353275] task: d9d08000 ti: d9cfe000 task.ti: d9cfe000 [ 12.354637] PC is at proc_dointvec+0x20/0x60 [ 12.355717] LR is at proc_sys_call_handler+0xb0/0xc4 [ 12.356972] pc : [] lr : [] psr: a0060013 [ 12.356972] sp : d9cffe90 ip : c0254038 fp : 00000001 [ 12.359824] r10: d9cfff80 r9 : 00000004 r8 : 00000000 [ 12.361132] r7 : bec21cb0 r6 : d9cffec4 r5 : d9cfff80 r4 : c0e82de0 [ 12.362766] r3 : 00000001 r2 : bec21cb0 r1 : 00000001 r0 : c0e82de0 [ 12.364400] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 12.366183] Control: 10c5383d Table: 59d3406a DAC: 00000015 [ 12.367623] Process cat (pid: 71, stack limit = 0xd9cfe220) 4. After correct the LR register, it will have right value [ 125.763370] Internal error: Oops - undefined instruction: 0 [#2] SMP ARM [ 125.767010] Modules linked in: [ 125.768472] CPU: 1 PID: 74 Comm: cat Tainted: G D 4.1.0-dirty #25 [ 125.771854] Hardware name: Generic DT based system [ 125.774053] task: db0bb900 ti: d9d10000 task.ti: d9d10000 [ 125.776821] PC is at proc_dointvec+0x24/0x60 [ 125.778919] LR is at proc_sys_call_handler+0xb0/0xc4 [ 125.781269] pc : [] lr : [] psr: a0060013 [ 125.781269] sp : d9d11e90 ip : c0254038 fp : 00000001 [ 125.786581] r10: d9d11f80 r9 : 00000004 r8 : 00000000 [ 125.789673] r7 : be92ccb0 r6 : d9d11ec4 r5 : d9d11f80 r4 : c0e82de0 [ 125.792828] r3 : 00000001 r2 : be92ccb0 r1 : 00000001 r0 : c0e82de0 [ 125.795890] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user For other exception injection, such as Data/Prefetch abort, also needs to correct --- arch/arm/kvm/emulate.c | 4 ++-- arch/arm64/kvm/inject_fault.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index 0064b86..2419328 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c @@ -227,7 +227,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu) u32 return_offset = (is_thumb) ? 2 : 4; kvm_update_psr(vcpu, UND_MODE); - *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset; + *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset; /* Branch to exception vector */ *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset; @@ -242,7 +242,7 @@ static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr) unsigned long cpsr = *vcpu_cpsr(vcpu); bool is_thumb = (cpsr & PSR_T_BIT); u32 vect_offset; - u32 return_offset = (is_thumb) ? 4 : 0; + u32 return_offset = (is_pabt) ? 4 : 8; bool is_lpae; kvm_update_psr(vcpu, ABT_MODE); diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index da6a8cf..0416f18 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -33,12 +33,26 @@ #define LOWER_EL_AArch64_VECTOR 0x400 #define LOWER_EL_AArch32_VECTOR 0x600 +/* + * Table taken from ARMv8 ARM DDI0487B-B, table G1-10. + */ +static u8 return_offsets[8][2] = { + [0] = { 0, 0 }, /* Reset, unused */ + [1] = { 4, 2 }, /* Undefined */ + [2] = { 0, 0 }, /* SVC, unused */ + [3] = { 4, 4 }, /* Prefetch abort */ + [4] = { 8, 8 }, /* Data abort */ + [5] = { 0, 0 }, /* HVC, unused */ + [6] = { 4, 4 }, /* IRQ, unused */ + [7] = { 4, 4 }, /* FIQ, unused */ +}; + static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset) { unsigned long cpsr; unsigned long new_spsr_value = *vcpu_cpsr(vcpu); bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT); - u32 return_offset = (is_thumb) ? 4 : 0; + u32 return_offset = return_offsets[vect_offset >> 2][is_thumb]; u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR); cpsr = mode | COMPAT_PSR_I_BIT;