Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756980AbcCRGMM (ORCPT ); Fri, 18 Mar 2016 02:12:12 -0400 Received: from mail-by2on0058.outbound.protection.outlook.com ([207.46.100.58]:3904 "EHLO na01-by2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752595AbcCRGLe (ORCPT ); Fri, 18 Mar 2016 02:11:34 -0400 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 v3 09/12] svm: Add VMEXIT handlers for AVIC Date: Fri, 18 Mar 2016 01:09:45 -0500 Message-ID: <1458281388-14452-10-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1458281388-14452-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1458281388-14452-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: SG2PR04CA0047.apcprd04.prod.outlook.com (25.169.49.143) To BY1PR12MB0437.namprd12.prod.outlook.com (25.162.147.139) X-MS-Office365-Filtering-Correlation-Id: 3be215bc-0d74-4a43-5471-08d34ef4270b X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;2:1AXcoRwspJvSNwj6aM8MJR03GzXjqjhlLbPNAl9qj+2pNGGqhKspHV1adBREXXVNXTZU7wVXnJQRhPvNKiT8XJFVLA6gaPq3Qlec7RbZRVd6K5X2xOzHOxo3iqf101SG+3va/KbvA3TotFjMZZewy8WP4rUvRy6zanqHLs5GQA1OrMnnhlFmIVCgDIIaOEW8;3:trN5Chg+DBZSRp0mQPwErL8ypW4acsjRsjBvOrgQmfQkqIK2zVCdzyYBEl87vOV7O1IQ1P3etMGSc1F8BShDn6sAiM8JsvWdwXD+lPAX+slR1NadNnHc3GsaVp3v9Vvn;25:V1MlWDMsgE3PunDFt2OxNh0YJ393CIJWY6CSiv5EdTAgsDNKRkeL6nxF/UJLO5ocaqgk7LAz0OMotsNmr38Y8WCvV+XRHcjUIWRlSvsRPxAmsgUf8zhhvqCZ9PSQdh8k8ECbiLsFFkZTeqfoBDo+6Koj22XDb/WVES14gLFb8cRyH3SrmsvgJXHIEfukJ+szqTQ6YXGoLP+u49514zXdAY6O08RXjg+9Qg5QPqH4TarU8A34C2O9gHp1/jneZuPcUFlY9afH4MDeDxweon5A6dFW7tgh8I30alMZ9MRdQtAlcxUVDzjp8RWcp4e76+lNT6UdBvaC15OIXhB/WtBXNtpwRBbYQyUbGYsyVbjsh9fQDPCUmNpnqHJRvL+ZW7HfqaeUeIehsWtFQHQSw2F6YR6ExT3WEG0QUXsgcG3s3etDtHc1c8W9dyN2kvl/3LhatolkUZapmpE/IyzhJFl2Y8Fk/WdCd/T/sjnNh4MefO4enQguW84F82Ra0oojU8XisRlrOs1CJa/EvZagDeD54w== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY1PR12MB0437; X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;20:X+VrdKEPy2ULkb6tbcx/9m6HlsJjvUhCmhfzPmzXKaUt/vPdgO9gQePAycf2XLusdoLczhSX2rXkg9G6GdV3cb+V66iHR0l4BTuYFZPjY4b+Mmyp2bULxmbUZukWo4TiMzr0t7WcK47yhazJ9XHpw9br/LccuOfMr0glbuYe3/1qLgU1MioRImS/t2eHu90awTVBk1MdyqlRNgufH3y9SnuCLFTh9z7ZwbzPZx2JQNXYMAdLJxoJIyMJ2jNyF1Qyz3DPtBx48sYk5y6mYEkuAoRFUGLC+3xr7XLAqSarlPdVNIEvxMUof++QNFn7LdAyodiCVpQavrcJoZYbGqZD1pppaUBzegoicvSjizguWEabtaEWUhkjMOvmWmcIGz/jrSjREh6n1HIDIu5W6ugVx7Tc0VN1C6w0HGyQ9OUGr+YvODURP0Mp72qHEfn1vIkfqUE5iNqoe+SLby9znDtRdWZmmc8gb35XwaLdH7PcDIu+Ywfc9RjoDrARliRtyqYT;4:obkkGa0G1ZbSPLvtSA81ir6ybgAhK+Mf4H4JcaMktZdDmwCNPc9hnLTu29KTlisdsi+DXVd3jplfwkuGf0aTgAaYuq6QPNxaHqnECrTp9pU7DQ0b12LM6ir/SNuCHOxWVOVKQgcVtUCfK/APt0/LiGtq6uA4XBnPYuaQDcd8FQ/5Lz487tSX17m8N80i6sxD+ujzxMciiyBGiXn2+rEvXEDTk3UojNQ1dEl3bHcOuV+0hSTr7RP2Qs3oQvypwKqrxe7Hhbx6D9m4LRzsM/bUE+LRw/ww35DhwXoTGrpV1PSeu6aWTi8ZUdTjk6MXiptgNul44aQG9E2YD0FDTNV2ma/fcTtB4Mj6FQmgHyUnjJpPoPoArMC1h2e0pspybQwA X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(8121501046)(5005006)(10201501046)(3002001);SRVR:BY1PR12MB0437;BCL:0;PCL:0;RULEID:;SRVR:BY1PR12MB0437; X-Forefront-PRVS: 088552DE73 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(4630300001)(6009001)(6069001)(189998001)(66066001)(19580395003)(19580405001)(47776003)(42186005)(3846002)(5001770100001)(50226001)(6116002)(2201001)(86362001)(575784001)(586003)(229853001)(2950100001)(36756003)(5004730100002)(77096005)(81166005)(5003940100001)(4326007)(50466002)(92566002)(48376002)(5008740100001)(76176999)(50986999);DIR:OUT;SFP:1101;SCL:1;SRVR:BY1PR12MB0437;H:localhost.localdomain;FPR:;SPF:None;MLV:sfv;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;23:xK2C88d8lqSoW/IIB/9giqNkzc2Y/BT2SOyyPWMtDMD1RTX3mOgmIc6egSfdQ3HHDuMClKb4RdnnbEctrF9/7J3qJN8FY41brw2HfkvuO0/peESwQSCqiK/qKMINuDHcW0xcYxxoWzKI5YLkJTM/QMLDZsttSXVU0rEJ/PrKEP0XNnl0Exhpa4mWnL8yW1JVfaHZ4qeg4uqJpO4iSfXYICd1uxCxw6/zFFdkXJCPPhhIjivu5yyG7kGrmoRhk1t2QiC+/7nL01duPYlJIs4UAkC/+cIRfCYlUtv0wDQM32H0+6Bqbo1vxB2D/ad4+dYTv7O7qvBMdbt9anHSAIiXoEh41dt22SUDZzDf3gfllmSD6LVwyjciOwmhaLVad93W3l9IelosOvSn7xzM8URVAUWG1Uz5NAiAMlhwLM0VGk0llN0+Ma/gCkEFZ3SkGbmxhh4mFlhYb2DQOucszSTUydStn6yQtVntvX4Iea2OJycvYcrxGKimCIhMaxn8HZI0Bz+clot88UmRE9ppTLI2mHlufGxmUJ3IeWDc8pOK5AUtLbfJy9ubGVhbV+1gi0WJgOV3lMvrQA/AT0QKgXqRDi4//t3KKQPUIHku3OJDQA80zLMqs6ZsEgx0PyXBfqcIBWJ1xWijeujdPEQ4tShjtUXrd4uDEWHDe6BU2TF2rdXQPV3fqqdkbw+EsIicyDjhCIx2F43B7265p7vgmFP0BTtl9Eca//bd5tVbfgb8/1atmo/qHKHbEdQiw/2VFepwEHO2ycOxx04tWTQuLZ1j6vm9E7H+Ov1yKC91h2VcG572I+ILFANVGgLtZTz1RuMfuZ3FStiPxG+eS5VEHDSY9Wy5mmJYyQjBKZkMBGCR6ykgf7mEx22Uxf/r4sdY+6Tm X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;5:q2VvzNwx/4QQuPQtF2p9Eqc37qFPelnVkLH54YCE2oR5ALzOqUC8xWbA3o/hLtvoiDEaT2NKkLU5wLjJiDs14z6/fGI84E1eueOZ2w8LW+K4Bwp4V2mNdrdgHTaSJcOiq+l2FBVugX8pOeMK741bgQ==;24:CzVzhn4q4txMyfSTax0PNOpjrEqFWk68igQJy1zbBV5CX/Z42BwKv4cOBCWx5L2pueejlHZL75XLqT69ghad67aPgQhF0Lnslh1KqfoEL1s=;20:fXQXMROrUAJyRUoRgccQcu+3pEb79aYslC2P55OF9b5zYYG0htscFAABfJWMSHOLcnhs7AD6P+ks8U80JfYR8CbZ6X3W5l+NJ5/pSzzNIuMYZZRz2egC4C6aEfyQC/h9uRwNYfpEVOeEpBO1PvwHrtlbUlORJayb85ArmE+D4BUetfRnDzqH3rE6qbOZmvbIBEzCUvfFhaYEQoB6ZNISP12wt/g90jDEbZzQr7549hVlnIqU9/8XVeE4rf3s2Per X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Mar 2016 06:11:29.3880 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY1PR12MB0437 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9189 Lines: 326 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/lapic.h | 3 + arch/x86/kvm/svm.c | 244 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 8a4add8..131b0b9 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_INCOMPLETE_IPI 0x401 +#define SVM_EXIT_AVIC_UNACCELERATED_ACCESS 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_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \ + { SVM_EXIT_AVIC_UNACCELERATED_ACCESS, "avic_unaccelerated_access" } #endif /* _UAPI__SVM_H */ diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 7bf8184..ed23af0 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -9,6 +9,9 @@ #define KVM_APIC_SIPI 1 #define KVM_APIC_LVT_NUM 6 +#define KVM_APIC_SHORT_MASK 0xc0000 +#define KVM_APIC_DEST_MASK 0x800 + struct kvm_timer { struct hrtimer timer; s64 period; /* unit: ns */ diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8e31ad3..6303147 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3508,6 +3508,248 @@ static int mwait_interception(struct vcpu_svm *svm) return nop_interception(svm); } +enum avic_ipi_failure_cause { + AVIC_IPI_FAILURE_INVALID_INT_TYPE, + AVIC_IPI_FAILURE_TARGET_NOT_RUNNING, + AVIC_IPI_FAILURE_INVALID_TARGET, + AVIC_IPI_FAILURE_INVALID_BACKING_PAGE, +}; + +static int avic_incomplete_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; + + trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index); + + switch (id) { + case AVIC_IPI_FAILURE_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_IPI_FAILURE_TARGET_NOT_RUNNING: { + 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) { + bool m = kvm_apic_match_dest(vcpu, apic, + icrl & KVM_APIC_SHORT_MASK, + GET_APIC_DEST_FIELD(icrh), + icrl & KVM_APIC_DEST_MASK); + + if (m && !avic_vcpu_is_running(vcpu)) + kvm_vcpu_wake_up(vcpu); + } + break; + } + case AVIC_IPI_FAILURE_INVALID_TARGET: + break; + case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE: + WARN_ONCE(1, "Invalid backing page\n"); + break; + default: + pr_err("Unknown IPI interception\n"); + } + + return 1; +} + +static u32 *avic_get_log_apic_id_entry(struct kvm_vcpu *vcpu, u8 mda, bool flat) +{ + struct kvm_arch *vm_data = &vcpu->kvm->arch; + int index; + u32 *avic_log_ait; + + if (flat) { /* flat */ + if (mda > 7) + return NULL; + index = mda; + } else { /* cluster */ + int apic_id = mda & 0xf; + int cluster_id = (mda & 0xf0) >> 8; + + if (apic_id > 4 || cluster_id >= 0xf) + return NULL; + index = (cluster_id << 2) + apic_id; + } + avic_log_ait = (u32 *) page_address(vm_data->avic_log_apic_id_table_page); + + return &avic_log_ait[index]; +} + +static int avic_handle_ldr_write(struct kvm_vcpu *vcpu, u8 g_phy_apic_id, + u8 log_apic_id) +{ + u32 mod; + u32 *entry; + struct vcpu_svm *svm = to_svm(vcpu); + + if (!svm) + return -EINVAL; + + mod = (kvm_apic_get_reg(svm->vcpu.arch.apic, APIC_DFR) >> 28) & 0xf; + entry = avic_get_log_apic_id_entry(vcpu, log_apic_id, (mod == 0xf)); + if (!entry) + return -EINVAL; + + *entry &= ~AVIC_LOG_APIC_ID__GUEST_PHY_APIC_ID_MSK; + *entry |= (g_phy_apic_id & AVIC_LOG_APIC_ID__GUEST_PHY_APIC_ID_MSK); + *entry |= AVIC_LOG_APIC_ID__VALID_MSK; + + return 0; +} + +static int avic_unaccel_trap_write(struct vcpu_svm *svm) +{ + u32 offset = svm->vmcb->control.exit_info_1 & 0xFF0; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + u32 reg = kvm_apic_get_reg(apic, offset); + + switch (offset) { + case APIC_ID: { + u32 aid = (reg >> 24) & 0xff; + u64 *o_ent = avic_get_phy_apic_id_entry(&svm->vcpu, + svm->vcpu.vcpu_id); + u64 *n_ent = avic_get_phy_apic_id_entry(&svm->vcpu, aid); + + if (!n_ent || !o_ent) + return 0; + + /* We need to move phy_apic_entry to new offset */ + *n_ent = *o_ent; + *((u64 *)o_ent) = 0ULL; + svm->avic_phy_apic_id_cache = n_ent; + break; + } + case APIC_LDR: { + int ret, lid; + int dlid = (reg >> 24) & 0xff; + + if (!dlid) + return 0; + + lid = ffs(dlid) - 1; + ret = avic_handle_ldr_write(&svm->vcpu, svm->vcpu.vcpu_id, lid); + if (ret) + return 0; + + break; + } + case APIC_DFR: { + struct kvm_arch *vm_data = &svm->vcpu.kvm->arch; + u32 mod = (reg >> 28) & 0xf; + + /* + * 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_apic_id_table_page)); + vm_data->ldr_mode = mod; + } + break; + } + default: + break; + } + + kvm_lapic_reg_write(apic, offset, reg); + + return 1; +} + +static bool is_avic_unaccelerated_access_trap(u32 offset) +{ + bool ret = false; + + 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: + ret = true; + break; + default: + break; + } + return ret; +} + +#define AVIC_UNACCEL_ACCESS_WRITE_MSK 1 +#define AVIC_UNACCEL_ACCESS_OFFSET_MSK 0xFF0 +#define AVIC_UNACCEL_ACCESS_VECTOR_MSK 0xFFFFFFFF + +static int avic_unaccelerated_access_interception(struct vcpu_svm *svm) +{ + int ret = 0; + u32 offset = svm->vmcb->control.exit_info_1 & + AVIC_UNACCEL_ACCESS_OFFSET_MSK; + u32 vector = svm->vmcb->control.exit_info_2 & + AVIC_UNACCEL_ACCESS_VECTOR_MSK; + bool write = (svm->vmcb->control.exit_info_1 >> 32) & + AVIC_UNACCEL_ACCESS_WRITE_MSK; + bool trap = is_avic_unaccelerated_access_trap(offset); + + trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset, + trap, write, vector); + + /** + * AVIC does not support x2APIC registers, and we only advertise + * xAPIC when enable AVIC. Therefore, access to these registers + * will not be supported. + */ + if (offset >= 0x400) { + WARN(1, "Unsupported APIC offset %#x\n", offset); + return ret; + } + + if (trap) { + /* Handling Trap */ + if (!write) /* Trap read should never happens */ + BUG(); + ret = avic_unaccel_trap_write(svm); + } else { + /* Handling Fault */ + ret = (emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE); + } + + return ret; +} + static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR0] = cr_interception, [SVM_EXIT_READ_CR3] = cr_interception, @@ -3571,6 +3813,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_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, + [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, }; static void dump_vmcb(struct kvm_vcpu *vcpu) -- 1.9.1