From patchwork Fri Feb 12 13:59:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Suthikulpanit, Suravee" X-Patchwork-Id: 61847 Delivered-To: patch@linaro.org Received: by 10.112.43.199 with SMTP id y7csp840193lbl; Fri, 12 Feb 2016 06:01:06 -0800 (PST) X-Received: by 10.67.1.237 with SMTP id bj13mr2339298pad.130.1455285665706; Fri, 12 Feb 2016 06:01:05 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m80si20170081pfi.252.2016.02.12.06.01.05; Fri, 12 Feb 2016 06:01:05 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752908AbcBLOA7 (ORCPT + 30 others); Fri, 12 Feb 2016 09:00:59 -0500 Received: from mail-bn1bon0090.outbound.protection.outlook.com ([157.56.111.90]:25929 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752882AbcBLOA4 (ORCPT ); Fri, 12 Feb 2016 09:00:56 -0500 Authentication-Results: 8bytes.org; dkim=none (message not signed) header.d=none; 8bytes.org; dmarc=none action=none header.from=amd.com; Received: from localhost.localdomain (124.121.8.20) by BY1PR12MB0440.namprd12.prod.outlook.com (10.162.147.141) with Microsoft SMTP Server (TLS) id 15.1.403.16; Fri, 12 Feb 2016 14:00:44 +0000 From: Suravee Suthikulpanit To: , , , CC: , , , , Suravee Suthikulpanit , Suravee Suthikulpanit Subject: [PART1 RFC 5/9] svm: Add VMEXIT handlers for AVIC Date: Fri, 12 Feb 2016 20:59:30 +0700 Message-ID: <1455285574-27892-6-git-send-email-suravee.suthikulpanit@amd.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1455285574-27892-1-git-send-email-suravee.suthikulpanit@amd.com> References: <1455285574-27892-1-git-send-email-suravee.suthikulpanit@amd.com> MIME-Version: 1.0 X-Originating-IP: [124.121.8.20] X-ClientProxiedBy: SG2PR03CA0036.apcprd03.prod.outlook.com (25.160.233.46) To BY1PR12MB0440.namprd12.prod.outlook.com (25.162.147.141) X-MS-Office365-Filtering-Correlation-Id: 57f63a47-9c35-489d-e75a-08d333b4eb6e X-Microsoft-Exchange-Diagnostics: 1; BY1PR12MB0440; 2:BHx/opDhy/Gk8+fI6otZctYwqTSw9oHZ1VfiXvXitVqAChEoBwlplyHrJ/LnyaIm/lTAO3y+i2FXV+Ve4+fPZ4EVY+7krWa277C+tRw7QFOASh/os4IfedAzQ5kN0rSp1mZRTSMAKSIPdoW95REirV93GUwa3etZA3dG+3XgGT/mLjXKtN9V8kzj6oGP2Tb3; 3:qGho5te6FemVLodCuFzDEOFGrtOHOVlfjoObp9tydBhXtTSvq3Ee3q6U5bHGOZ1bYrnxgZDJjZ7ta6ehrbyM0Y0Epp5vV6F4lx6tY8UdmqWv6rfoVIukZnFkUjN4c8ED; 25:iCENBcAxvEqyNpBMuQmXyKhvrh6gGdF10bCtI4XAq5qj5kD+xGA9+yrziSyu/ufcr6Xp1ARvthKz1KmgqDqlj9ylp4oV8vpdtQ/DJONwTJPU5XCYEIQi6L6AI6zZ/u3EAWVlWeWjU3jT3mXYcRUf/N9NflL0e/fX+zMdP9W4491AvOQ56+dUvmjrqlmZ6SFG3zcWQkTvEtkoxg83ZfiIgCS263i4YEigeMkN2B3i4yH2If+7Qg3SsFwziOMdLt4pFohFu46eHyHJawLHGKQAMff+eFn7Ok4dok2n2CDqK2XKbNf2CX+8IqCAXy4opi6P X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY1PR12MB0440; X-Microsoft-Exchange-Diagnostics: 1; BY1PR12MB0440; 20:b+DguvpcsX/wKtbEqg24idQ0I2SGQ4pMUhhtAe+g0pHi4sQciD+Zq7no7rLbWGZX6lqE1/PhMpskP7AKLo4gFyxbvkrQcV34LTxIRswAoZ+bBT8bTkmQpFwowST2pnOCeWuLyOxwV9HHwEk97nyjJskVLdKw4fB23mPbSPSH78t0EbPDQ+IyO6X6hQ6gkvNIjiH4IFLF2sonJ/ccdzrOeq7F1hMxPf2NXh38kuA6o9cuBZferU3JunDZo4NAYMSAYpiGGuRX6Ni9q6qOdgPpJRUhGxtPwp3C3cL2Y/mY6z+MgLKRL91dw7ijrua6agtYVoZfumlhhMh6an8A2+NWCSAwV5JJJpSrrN3vsakN6nEE//qKq+xrwuCNbhveoxofZnKB8S0Svkg6sGxOAI7acPEjMBX+uHnFlU7IdkVPIv68YMaaq5bzvTya/tlY9pUYKVYehGKtUc5IuBhQbNK2htHA+fEQpi/FvfxYoifuxp9XpIhULtFTdIYG5GM/gnAr; 4:c++/x56WyoOY+jI1RAcd8taIyllfMjYIFgaMxlmieNi/zdPOv29hULeo9IJxNVAgL9WCk9sEkSRp9UN2PZ35Xaasbd6AlCKvtC5L2vCGvgdGhlva5ZayGFWqWM8K3g5jdXG2kGM6rnKTVDrXoAUhJVGerPnaEQU1KpEX21EUJb6T6z7sS+61rmQyikgbVP5xB4aTDnAp4uU9lNaqZU2b7P8r2GbaPF7Cl4GF9bgemHJ10iZ8kiwDOn075HnL90CVKnk8Q8zYhNp/UtKGOJYwo4dmftSXvwWEzttxAaxQDOGjORx3MxxCyEi7FxVGFge7/p6kxRNMVjMGL7FWelbCCJLtS1eNI77j6gnuCf++Y0YVBjB3lOJB+++IS9b3GtZTAPtLD2mlVIR7lHNql09rUYIQgLl4Y83qkHu6qp4EoFs= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046); SRVR:BY1PR12MB0440; BCL:0; PCL:0; RULEID:; SRVR:BY1PR12MB0440; X-Forefront-PRVS: 0850800A29 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6009001)(6069001)(2201001)(36756003)(48376002)(586003)(40100003)(92566002)(3846002)(5003940100001)(77096005)(229853001)(2950100001)(19580395003)(19580405001)(6116002)(5004730100002)(189998001)(4326007)(42186005)(66066001)(50226001)(87976001)(5008740100001)(5001770100001)(122386002)(33646002)(50466002)(76176999)(50986999)(86362001)(5001960100002)(47776003)(1096002)(2906002); DIR:OUT; SFP:1101; SCL:1; SRVR:BY1PR12MB0440; H:localhost.localdomain; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY1PR12MB0440; 23:zsrUEWjSlxX3mUOm1eO1cgz4dtXA2rrfcPPZO9Nv1?= =?us-ascii?Q?GO0fcru50255aPDj2QsQfL/0Y9C+zZDYXlUhy+bqNCpnxOPV1GP3VP9zsx1F?= =?us-ascii?Q?q16pDq6x5IsfF7860hwA8sHdGQiMd7Lsu+IJWwhdZbBw0px1xpJhWzWT9QaI?= =?us-ascii?Q?roIm+XOuwpfkT/x5Z3dgXIxgMruT+lVWoOR6ZKDtY8agp1AUhpUbI5tyZLQP?= =?us-ascii?Q?+FyLAUdPnOhX3cufq054FH7M+Y9rulzD27pJcQ4yw3IOXI2P7b5x0gaEa4GQ?= =?us-ascii?Q?6aVyEiK9LdJq5sTySRVXl42YzuNdLv0CjSP+zRVDGblC42SrJWghoVJFGWQw?= =?us-ascii?Q?Nk1gfI7R2UbDXRpdcx/UZPbpg/9j0/g6VGn6ejjX1y++wZ/gXO/nsR47zDTf?= =?us-ascii?Q?mqKKwC7aTt7dR0xkzqUXvtZeJ3N4W80J9wo0xhvELRdHzWl4g8Na6uR9f/kT?= =?us-ascii?Q?6kGadwcrGc/WkhRqRmVuZFaQjJSSBEGI2sMDdz50IvRPexm3bP7wcgvKtN4/?= =?us-ascii?Q?ho09CHF8RUFhxv1pEGMdlatSZG/59NspQ5UkVm+5FgbfzYMfXxgBoOD8/4VL?= =?us-ascii?Q?OnTWZc+znqwZ31+HU4xJQbmosMaa6tchY/G1t8L5qpN671CjIhXT5Vh3ufyD?= =?us-ascii?Q?6dbrTWJ6wwxYkdDUe75A1ttt1YAWrwt78gtBMMoF07cfzej1yCskYduqCedH?= =?us-ascii?Q?8XID9lxDKtIalUdi2F9rouUWmSL2De06+wf0XtHB97ZCmWnfs7Aftg5k1W7m?= =?us-ascii?Q?+SfPABRrwXVnFpPq80BC8Nke2ccppBXuh9WzLziK99C3IznETED8Ee7SDE55?= =?us-ascii?Q?tMqgBh6meTQd8Ezq1nTtHKqAW0oCDhPD7lLSQ4YB9WH1seFqNke1O8xhj2tM?= =?us-ascii?Q?D6WN0Y217HoKEJ2fXdmEGkUfkv85eGS15X1fvKJHRaNObQ2MhGG0J/ZV+es9?= =?us-ascii?Q?aF85rEojSrMkPwCzWHHXtczQZWMTEn5BWJUx3jvuw=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY1PR12MB0440; 5:yFlEUTLATYPSVDqvwfQsK4yG/Y7bziBcpPOCZRScEKBptAMKFeurv5WemGDcRsHsodi1ktdvYlC54BmFbWBoanury0KalPXQqTVhUNtPTGqStLRuIdOlcu3Z/XUTefPb1Z96gAkz12ZI3EEUWjOcVw==; 24:MNSzFg9tkcZfQNqPUf4gEJEXxYIfcdLUDeCeceZyNpBKJndNfl2rcTbKFGs/kfj3r6XYUsdByr1hOQFgopO3I4QX9gMUGkKFq0EVCz4iMcg=; 20:Ot0uIvNvpcARvRCDjRkctLDG0aiMu6JQvnqvsMlFGs2dgiWp39Pe6jQ02rPy+8q0gBjhoJmA5eaLdBO2xve4DO9uI+ucBbf+UyC/9cBx/6b5Hz20Qza+jxjuwkJp2v2+4XLDRfqcHwXG/OUx7hzk0m/1vq4qpJ3IzEFb5f0CjJEp0nAqd2mTTtJyOSx2EARBsaHOcy8ZsxBVljCL/jpvPRGyfhz+0UfmuJKJwVKFSP/NjsXrTpcVuM1XfjOIUzyT X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Feb 2016 14:00:44.5006 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY1PR12MB0440 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Introduce VMEXIT handlers, avic_incp_ipi_interception() and avic_noaccel_interception(). Signed-off-by: Suravee Suthikulpanit --- arch/x86/include/uapi/asm/svm.h | 9 +- arch/x86/kvm/svm.c | 241 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 1 deletion(-) -- 1.9.1 diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 8a4add8..ebfdf8d 100644 --- a/arch/x86/include/uapi/asm/svm.h +++ b/arch/x86/include/uapi/asm/svm.h @@ -73,6 +73,8 @@ #define SVM_EXIT_MWAIT_COND 0x08c #define SVM_EXIT_XSETBV 0x08d #define SVM_EXIT_NPF 0x400 +#define SVM_EXIT_AVIC_INCMP_IPI 0x401 +#define SVM_EXIT_AVIC_NOACCEL 0x402 #define SVM_EXIT_ERR -1 @@ -107,8 +109,10 @@ { SVM_EXIT_SMI, "smi" }, \ { SVM_EXIT_INIT, "init" }, \ { SVM_EXIT_VINTR, "vintr" }, \ + { SVM_EXIT_CR0_SEL_WRITE, "cr0_sec_write" }, \ { SVM_EXIT_CPUID, "cpuid" }, \ { SVM_EXIT_INVD, "invd" }, \ + { SVM_EXIT_PAUSE, "pause" }, \ { SVM_EXIT_HLT, "hlt" }, \ { SVM_EXIT_INVLPG, "invlpg" }, \ { SVM_EXIT_INVLPGA, "invlpga" }, \ @@ -127,7 +131,10 @@ { SVM_EXIT_MONITOR, "monitor" }, \ { SVM_EXIT_MWAIT, "mwait" }, \ { SVM_EXIT_XSETBV, "xsetbv" }, \ - { SVM_EXIT_NPF, "npf" } + { SVM_EXIT_NPF, "npf" }, \ + { SVM_EXIT_RSM, "rsm" }, \ + { SVM_EXIT_AVIC_INCMP_IPI, "avic_incomp_ipi" }, \ + { SVM_EXIT_AVIC_NOACCEL, "avic_noaccel" } #endif /* _UAPI__SVM_H */ diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 9440b48..bedf52b 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3667,6 +3667,245 @@ static int mwait_interception(struct vcpu_svm *svm) return nop_interception(svm); } +enum avic_incmp_ipi_err_code { + AVIC_INCMP_IPI_ERR_INVALID_INT_TYPE, + AVIC_INCMP_IPI_ERR_TARGET_NOT_RUN, + AVIC_INCMP_IPI_ERR_INV_TARGET, + AVIC_INCMP_IPI_ERR_INV_BK_PAGE, +}; + +static int avic_incomp_ipi_interception(struct vcpu_svm *svm) +{ + u32 icrh = svm->vmcb->control.exit_info_1 >> 32; + u32 icrl = svm->vmcb->control.exit_info_1; + u32 id = svm->vmcb->control.exit_info_2 >> 32; + u32 index = svm->vmcb->control.exit_info_2 && 0xFF; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + + pr_debug("SVM: %s: cpu=%#x, vcpu=%#x, " + "icrh:icrl=%#010x:%08x, id=%u, index=%u\n", + __func__, svm->vcpu.cpu, svm->vcpu.vcpu_id, + icrh, icrl, id, index); + + switch (id) { + case AVIC_INCMP_IPI_ERR_INVALID_INT_TYPE: + /* + * AVIC hardware handles the generation of + * IPIs when the specified Message Type is Fixed + * (also known as fixed delivery mode) and + * the Trigger Mode is edge-triggered. The hardware + * also supports self and broadcast delivery modes + * specified via the Destination Shorthand(DSH) + * field of the ICRL. Logical and physical APIC ID + * formats are supported. All other IPI types cause + * a #VMEXIT, which needs to emulated. + */ + kvm_lapic_reg_write(apic, APIC_ICR2, icrh); + kvm_lapic_reg_write(apic, APIC_ICR, icrl); + break; + case AVIC_INCMP_IPI_ERR_TARGET_NOT_RUN: + kvm_lapic_reg_write(apic, APIC_ICR2, icrh); + kvm_lapic_reg_write(apic, APIC_ICR, icrl); + break; + case AVIC_INCMP_IPI_ERR_INV_TARGET: + pr_err("SVM: %s: Invalid IPI target (icr=%#08x:%08x, idx=%u)\n", + __func__, icrh, icrl, index); + BUG(); + break; + case AVIC_INCMP_IPI_ERR_INV_BK_PAGE: + pr_err("SVM: %s: Invalid bk page (icr=%#08x:%08x, idx=%u)\n", + __func__, icrh, icrl, index); + BUG(); + break; + default: + pr_err("SVM: Unknown IPI interception\n"); + } + + return 1; +} + +static int avic_noaccel_trap_write(struct vcpu_svm *svm) +{ + u32 offset = svm->vmcb->control.exit_info_1 & 0xFF0; + struct svm_vm_data *vm_data = svm->vcpu.kvm->arch.arch_data; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + u32 reg = *avic_get_bk_page_entry(svm, offset); + + pr_debug("SVN: %s: offset=%#x, val=%#x, (cpu=%x) (vcpu_id=%x)\n", + __func__, offset, reg, svm->vcpu.cpu, svm->vcpu.vcpu_id); + + switch (offset) { + case APIC_ID: { + u32 aid = (reg >> 24) & 0xff; + struct svm_avic_phy_ait_entry *o_ent = + avic_get_phy_ait_entry(&svm->vcpu, svm->vcpu.vcpu_id); + struct svm_avic_phy_ait_entry *n_ent = + avic_get_phy_ait_entry(&svm->vcpu, aid); + + if (!n_ent || !o_ent) + return 0; + + pr_debug("SVN: %s: APIC_ID=%#x (id=%x)\n", __func__, reg, aid); + + /* We need to move phy_apic_entry to new offset */ + *n_ent = *o_ent; + *((u64 *)o_ent) = 0ULL; + break; + } + case APIC_LDR: { + int ret, lid; + int dlid = (reg >> 24) & 0xff; + + if (!dlid) + return 0; + + lid = ffs(dlid) - 1; + pr_debug("SVM: %s: LDR=%0#10x (lid=%x)\n", __func__, reg, lid); + ret = avic_init_log_apic_entry(&svm->vcpu, svm->vcpu.vcpu_id, + lid); + if (ret) + return 0; + + break; + } + case APIC_DFR: { + u32 mod = (*avic_get_bk_page_entry(svm, offset) >> 28) & 0xf; + + pr_debug("SVM: %s: DFR=%#x (%s)\n", __func__, + mod, mod == 0xf? "flat": "cluster"); + + /* + * We assume that all local APICs are using the same type. + * If this changes, we need to rebuild the AVIC logical + * APID id table with subsequent write to APIC_LDR. + */ + if (vm_data->ldr_mode != mod) { + clear_page(page_address(vm_data->avic_log_ait_page)); + vm_data->ldr_mode = mod; + } + break; + } + case APIC_TMICT: { + u32 val = kvm_apic_get_reg(apic, APIC_TMICT); + + pr_debug("SVM: %s: TMICT=%#x,%#x\n", __func__, val, reg); + break; + } + case APIC_ESR: { + u32 val = kvm_apic_get_reg(apic, APIC_ESR); + + pr_debug("SVM: %s: ESR=%#x,%#x\n", __func__, val, reg); + break; + } + case APIC_LVTERR: { + u32 val = kvm_apic_get_reg(apic, APIC_LVTERR); + + pr_debug("SVM: %s: LVTERR=%#x,%#x\n", __func__, val, reg); + break; + } + default: + break; + } + + kvm_lapic_reg_write(apic, offset, reg); + + return 1; +} + +static int avic_noaccel_fault_read(struct vcpu_svm *svm) +{ + u32 val; + u32 offset = svm->vmcb->control.exit_info_1 & 0xFF0; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + + pr_debug("SVM: %s: offset=%x\n", __func__, offset); + + switch (offset) { + case APIC_TMCCT: { + if (kvm_lapic_reg_read(apic, offset, 4, &val)) + return 0; + + pr_debug("SVM: %s: TMCCT: rip=%#lx, next_rip=%#llx, val=%#x)\n", + __func__, kvm_rip_read(&svm->vcpu), svm->next_rip, val); + + *avic_get_bk_page_entry(svm, offset) = val; + break; + } + default: + pr_debug("SVM: %s: (rip=%#lx), offset=%#x\n", __func__, + kvm_rip_read(&svm->vcpu), offset); + break; + } + + return 1; +} + +static int avic_noaccel_fault_write(struct vcpu_svm *svm) +{ + u32 offset = svm->vmcb->control.exit_info_1 & 0xFF0; + + pr_debug("SVM: %s: offset=%x\n", __func__, offset); + + switch (offset) { + case APIC_ARBPRI: /* APR: Arbitration Priority Register */ + case APIC_TMCCT: /* Timer Current Count */ + /* TODO */ + break; + default: + BUG(); + } + + return 1; +} + +static int avic_noaccel_interception(struct vcpu_svm *svm) +{ + int ret = 0; + u32 offset = svm->vmcb->control.exit_info_1 & 0xFF0; + u32 rw = (svm->vmcb->control.exit_info_1 >> 32) & 0x1; + u32 vector = svm->vmcb->control.exit_info_2 & 0xFFFFFFFF; + + pr_debug("SVM: %s: offset=%#x, rw=%#x, vector=%#x, vcpu_id=%#x, cpu=%#x\n", + __func__, offset, rw, vector, svm->vcpu.vcpu_id, svm->vcpu.cpu); + + BUG_ON (offset >= 0x400); + + switch(offset) { + case APIC_ID: + case APIC_EOI: + case APIC_RRR: + case APIC_LDR: + case APIC_DFR: + case APIC_SPIV: + case APIC_ESR: + case APIC_ICR: + case APIC_LVTT: + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_LVT0: + case APIC_LVT1: + case APIC_LVTERR: + case APIC_TMICT: + case APIC_TDCR: { + /* Handling Trap */ + if (!rw) /* Trap read should never happens */ + BUG(); + ret = avic_noaccel_trap_write(svm); + break; + } + default: { + /* Handling Fault */ + if (rw) + ret = avic_noaccel_fault_write(svm); + else + ret = avic_noaccel_fault_read(svm); + skip_emulated_instruction(&svm->vcpu); + } + } + + return ret; +} + static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR0] = cr_interception, [SVM_EXIT_READ_CR3] = cr_interception, @@ -3730,6 +3969,8 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_XSETBV] = xsetbv_interception, [SVM_EXIT_NPF] = pf_interception, [SVM_EXIT_RSM] = emulate_on_interception, + [SVM_EXIT_AVIC_INCMP_IPI] = avic_incomp_ipi_interception, + [SVM_EXIT_AVIC_NOACCEL] = avic_noaccel_interception, }; static void dump_vmcb(struct kvm_vcpu *vcpu)