From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760293AbcCDUuh (ORCPT ); Fri, 4 Mar 2016 15:50:37 -0500 Received: from mail-bn1bon0072.outbound.protection.outlook.com ([157.56.111.72]:52864 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1758341AbcCDUtO (ORCPT ); Fri, 4 Mar 2016 15:49:14 -0500 Authentication-Results: redhat.com; dkim=none (message not signed) header.d=none;redhat.com; dmarc=none action=none header.from=amd.com; From: Suravee Suthikulpanit To: , , , , , CC: , , , , Suravee Suthikulpanit Subject: [PART1 RFC v2 07/10] svm: Add VMEXIT handlers for AVIC Date: Fri, 4 Mar 2016 14:46:05 -0600 Message-ID: <1457124368-2025-8-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1457124368-2025-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1457124368-2025-1-git-send-email-Suravee.Suthikulpanit@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [124.121.8.20] X-ClientProxiedBy: SINPR01CA0045.apcprd01.prod.exchangelabs.com (10.141.109.45) To SN1PR12MB0445.namprd12.prod.outlook.com (25.162.105.139) X-MS-Office365-Filtering-Correlation-Id: 1c583acd-7087-45c2-f890-08d3446e6fc7 X-Microsoft-Exchange-Diagnostics: 1;SN1PR12MB0445;2:JlA5cyGwV1ozVHpUstlO89WOfTBvwLev5Zq7M0am31iKHSC8ZmL/YfynpjBa+wcMsHlDUD47MFFVu3FxAQm2UdrBbO0sM89EtmRXXJ1ixzuH6UyTStTzBtALuikbXMW9EzUpX/tNxwSwqfFl3rQfFRJOlp/loMauaTa3SVxzMO9F5Y0moLJIFe9dwf8iyK1O;3:gwsnVd05NCtdtzE8BA5kcVXnraosknxFYtFll6lrwT8jlVLJOPeu7aybQC3uvJzBlaDWUMCwSM7THNZbukNEIoDIYiZ78yuKhGD69sW3JEYue9aWB5Em3ynYR7el+LZ0;25:ua6s2xkEkBNeHOmG6dZAcEsU7dKlyPmpnjgllcaDEEg0rfixNVJsIlyz0BuvlHhaRjAbStFK7J412HgNktMvXLyKEx+Ri0z5ENiYmnVFNeO4oqFyrQGH6LSoRDJkaMq7AbBqyaCypzttb4E8p2DCvGTzHQg46zCctpdNWmKWAgxy7EKAvwjbyIkcC8dIRQnnbbGmnW7YJCXLNTtF17aV2w5uB3OZLEs5EUwzRvmNunHb3fOjup3AZJZvW5xIjDEylKxXkrYPT6BkpmGd/SOYAonAvBJYo/TQPui+B/zMu1v1GyvdvBoL+MDB4G77N3qirYF4tgJLlz3wxaZmXRy49w== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SN1PR12MB0445; X-Microsoft-Exchange-Diagnostics: 1;SN1PR12MB0445;20:CarK4EPSZKjVU4iQ6+vjuPbV3+JtW9eCuK/USUkuWPADe5vda83DWoNJKwCFVd/C+AeTU5nCHYREfbJiCJpX4PO3Kbr03UKIDztYNZ9VPyt6lo44CPzy6iBLiVzUujLKVfyEev8mXn+qhJlklk8j62BGqhef9HUttJs9izaBigFe5j2rboS+/eLYk9m8IRoG8Zbew7zEhwq0Td/bdZ+HBUrCbjxrz3nj7jSawXgHYXQ/iR2lwe5NzZ/jo03tWXF6ps5eo/N1ZD3WKZ8ReA9gVF91P22LuSO2KLHTR1mDXajo59lac8RO5eIMjKo3nuyZFefVEPELMOW/5EFS3j6VP5MeSRzTAmUvyijpHGucH3grGaDewjJ/Lcs5lEsnlcDFcFdx17SUT3llVd4SVhKLDhrXb0V8UoUkPQ+YSu+1qas6ODlwRNPUmrf79RSH3kaqU320bM5lkWsH20nQSyUZEnwVmuyZNwcDgTIhegELnktIEvY/e4MgOnjbr4sQNU3D;4:hV9wyrvRTmqBCCgWP1aX2r9vulDnp7aST4+M3p7UsiL7g9pNgD8I48YCf9ZxMsUZXQpwF0ULxSxflJ4ubZYqygqaBwz42Fv0d5Goc2oRfPunXbS3tZOuAhjTrr8RiOqWrY6dLnThE54D9AV8fO7X4JPK/kQpp4L57UZDMGnOB0p89b9qip9jM7oRnMP1yJJLEWMbm68NlvuEBSQ3WwzqV+thNq+0ZzUjHBGrPeeJUyGa0hX7Pwn6ntyAoHhP76h/Fxn33PlX5nHMa9or8y/V+3fyZAo1qb7ulaXZWIqE8dnEZGAuUh+lStauv7ROGtETJvPNrYZ0o07CAYXZZjdjH54oBwxJX1P1FLsuvomPysfbbA9XqvI/rtKamm1D4W3T X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046);SRVR:SN1PR12MB0445;BCL:0;PCL:0;RULEID:;SRVR:SN1PR12MB0445; X-Forefront-PRVS: 0871917CDA X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(4630300001)(6069001)(6009001)(77096005)(5001770100001)(87976001)(48376002)(47776003)(229853001)(36756003)(2201001)(66066001)(81166005)(50466002)(2950100001)(5004730100002)(189998001)(40100003)(50226001)(5003940100001)(122386002)(5008740100001)(19580405001)(2906002)(19580395003)(86362001)(4326007)(42186005)(50986999)(6116002)(3846002)(1096002)(92566002)(586003)(76176999);DIR:OUT;SFP:1101;SCL:1;SRVR:SN1PR12MB0445;H:localhost.localdomain;FPR:;SPF:None;MLV:sfv;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;SN1PR12MB0445;23:f+in9ZHwyi0qbjSKeGa8Va0G9iUeDbCkOBJuyAGDM?= =?us-ascii?Q?kBIYbBhIgaMSihhdTnapm5atvnm/ToLQoLEL+RwniVpUFIuw0qEHfJnUAObC?= =?us-ascii?Q?vgjNvlzykMQIrGxWu6X44yBtXUkBsvlK9jb8gztuSHLmTE0T97oqVdtFFgRB?= =?us-ascii?Q?/EBsyfJpRtFjgKF4IprxQtaCM2w9C4ebbPi7ntDxE2AHlWzGY/Tl2mq+oDeq?= =?us-ascii?Q?5bGTtctj3cexu25DddE08TdUfpGyh28mjnN+bOBXyeVrUFyq5L1GrUfyuPYS?= =?us-ascii?Q?2fachmsJi0s0P+CvXZdYDy+2zlI1Hw0SHyytlKCLgHwAcS/5uYwcG5wiCilM?= =?us-ascii?Q?7nT0WtKdrKGqJR9p3HbULZG99GqMUkin0eAUxrwFGX3aHNaVcjG1oDvkQfwc?= =?us-ascii?Q?EVLcQIe5QXcfSzF49R4GjOLn6QWzRaYcJ+q+lbx/yqSy4YaTp/FoxqGViSSz?= =?us-ascii?Q?eqhD/5TX+1DAGB4DfyHxZpVCJym7gRGK3Q+h8rSbG1Dq5bbF7Q2rijaF+LE8?= =?us-ascii?Q?FddSI3mWiafgN6+ms2sBm1cLcWwbt3dG4RZTLsAp0ecdDJ5IR9o64nA/hWvu?= =?us-ascii?Q?gwKyvhXFMepE1s5WaS6x5H8Uy65c4gsWUY5hxPqAPCxrnFxhE8JulC/r1zyr?= =?us-ascii?Q?L5ji272f4dd0B/9Rx/N6BjZwspsDhn9ZM5qmcYisPQWr0hiv3UO46YAEc+MV?= =?us-ascii?Q?HXU5wd0Za+rKSjnb4CBz+wYi7fnCBiuBZF7vBNFb+t4MbaG3mzPnUtLMIGxE?= =?us-ascii?Q?h4A5CWv9/W2mz9CYLeD/2V27Gu3KqUFUSqkppAgn/dL5ERy/Yj9bg9u6/1a0?= =?us-ascii?Q?R8TyjKf4XNP7oOghYxYMel9l9LLXXfrf49j8uOnLpLA/7ABZdxFyorRPABvs?= =?us-ascii?Q?OsCgszz5MMU1LiktO77XdsEUTDgnsoeVPmn7v17EH9wjBKHKeibYbS6mqHZr?= =?us-ascii?Q?WmgLaTeIHnLf6IWQc3Lewsir7YKpT4xRCzzqW4x1g=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;SN1PR12MB0445;5:mcP0qmdvhpwT46wOISJGRYc1yIcwjOUB3csphhhOPdS2IIcXgusE28+noKMFeaL3zoD8jsQm2CeTyfqYu3NmqTFHojB7fViyFJr8F2Bxe3qTFlNeLGPVGdAyPEbISBL34q4GqANkoi6/GJ7eB5GVKA==;24:WdpAVse/8MGLTrzafNMUkgL5d/rADPqKz1DSjGz1ftxWdXFMQAXr60g6LfTzfLOnxvdNzRBOr/udDSSfocPxMPGqPrQBJvmDr4+zoIts7I0=;20:z19a8ADsqcJPkFzmXSbSIgSi41eweTLMihbdZfCytpMMx7iAmhCnQlIi8gAy026hREgXxKtLVtiC4gxsoAHKWvxkSIV7+EADR+nlEPvTUml81L5jmAKzftxcwbca2n4xHKFoAdn56hU4VS1r4+fcOf35DdADosukosA2Vg5gRqvAdOWAXESCxmzHZIVxltA8ucqaw+yy97vYfOZ0c+k0dUOpQjWk8CEA7eB803DgciGP2SmFwstVN97wD1HoJWtw X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Mar 2016 20:49:06.9650 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1PR12MB0445 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suravee Suthikulpanit 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 | 260 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 1 deletion(-) 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 8f11200..a177781 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3690,6 +3690,264 @@ 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, +}; + +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_MASK 0x800 +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("%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: { + int i; + struct kvm_vcpu *vcpu; + struct kvm *kvm = svm->vcpu.kvm; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + + /* + * At this point, we expect that the AVIC HW has already + * set the appropriate IRR bits on the valid target + * vcpus. So, we just need to kick the appropriate vcpu. + */ + kvm_for_each_vcpu(i, vcpu, kvm) { + if (!kvm_apic_match_dest(vcpu, apic, + icrl & APIC_SHORT_MASK, + GET_APIC_DEST_FIELD(icrh), + icrl & APIC_DEST_MASK)) + continue; + + kvm_vcpu_kick(vcpu); + } + break; + } + case AVIC_INCMP_IPI_ERR_INV_TARGET: + pr_err("%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("%s: Invalid bk page (icr=%#08x:%08x, idx=%u)\n", + __func__, icrh, icrl, index); + BUG(); + break; + default: + pr_err("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("%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("%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("%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("%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("%s: TMICT=%#x,%#x\n", __func__, val, reg); + break; + } + case APIC_ESR: { + u32 val = kvm_apic_get_reg(apic, APIC_ESR); + + pr_debug("%s: ESR=%#x,%#x\n", __func__, val, reg); + break; + } + case APIC_LVTERR: { + u32 val = kvm_apic_get_reg(apic, APIC_LVTERR); + + pr_debug("%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("%s: offset=%x\n", __func__, offset); + + switch (offset) { + case APIC_TMCCT: { + if (kvm_lapic_reg_read(apic, offset, 4, &val)) + return 0; + + pr_debug("%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("%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("%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("%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, @@ -3753,6 +4011,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) -- 1.9.1