From patchwork Wed May 4 19:09:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Suthikulpanit, Suravee" X-Patchwork-Id: 67174 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp358386qge; Wed, 4 May 2016 12:12:37 -0700 (PDT) X-Received: by 10.98.46.130 with SMTP id u124mr11855881pfu.134.1462389157391; Wed, 04 May 2016 12:12:37 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id vq9si6333483pab.209.2016.05.04.12.12.37; Wed, 04 May 2016 12:12:37 -0700 (PDT) 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; dkim=pass header.i=@amdcloud.onmicrosoft.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 S1755594AbcEDTMf (ORCPT + 29 others); Wed, 4 May 2016 15:12:35 -0400 Received: from mail-bn1bon0098.outbound.protection.outlook.com ([157.56.111.98]:47936 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754537AbcEDTLF (ORCPT ); Wed, 4 May 2016 15:11:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:To:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=ndFsRInx4UcFZ8E7WA00sPILUYQwSTi9MJroijhCuVM=; b=nLnvf5SJ2mw47ibzXE5PEdzKCLYmJPid3vKPHzOQkU8aod2e9TFZVGxmM7SVWWPMYwC3N7eQPnZfop/DQsh6Lhwgu6kwwxkdTC/G5XklCVQij5/6B4jKyewfmnofquF11FHUZHYHcinEHzxpw3pr15tkCCd0Mzx9EyR5Ngl/bik= Authentication-Results: redhat.com; dkim=none (message not signed) header.d=none; redhat.com; dmarc=none action=none header.from=amd.com; Received: from ssuthiku-cz-dev.amd.com (165.204.77.1) by BLUPR12MB0433.namprd12.prod.outlook.com (10.162.92.139) with Microsoft SMTP Server (TLS) id 15.1.477.8; Wed, 4 May 2016 19:11:00 +0000 From: Suravee Suthikulpanit To: , , , , , CC: , , , , Suravee Suthikulpanit Subject: [PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC Date: Wed, 4 May 2016 14:09:48 -0500 Message-ID: <1462388992-25242-10-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1462388992-25242-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1462388992-25242-1-git-send-email-Suravee.Suthikulpanit@amd.com> MIME-Version: 1.0 X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: BY2PR21CA0014.namprd21.prod.outlook.com (10.162.74.152) To BLUPR12MB0433.namprd12.prod.outlook.com (10.162.92.139) X-MS-Office365-Filtering-Correlation-Id: ff432cdf-aeff-4dd1-320c-08d3744fd532 X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0433; 2:67jlAQlkA3DnwzgmvXqQ2pXWEnT9SC3DlqFg3uZVmB/TFLYx1PtKW4AIRxCEIGDLYa02kEpVf576yriRV9iFCTcNY806JiXbRyy3VB1FAiMIrJIIc9Ot7O8JAVYsDfuuex2aAHSOVwbahcO1vIR6OnTLFL21om4RUHouFG7E4hKiYu2NAIX5llDDRHIrXjgU; 3:9GgQtVodRaOj2SDmCMfG49Rl1RKWb6hNhmqnlzZ0wpMYoSviGVAR2qyMCrtSnIqPiMosxO1qGxwoPmEtfIAkOGyv6RiBKFIy0VY7btTcu5iR5fT8N4LxYeaVY7j6Vd9T; 25:yXjx9Y8lclm7PeotM5W5GqGTs6aDQwNl8bv/6GnEergmMrLan6h/mCXTP9bQiaFLXjz7j7PiueaSrADVL0yc+osZsR1tpLof/swYgYYTaZ5I5dqJfML94rme35Q6xuZbcvPcbbMH+K/BT4FgqtkB3EExC5xgvVmJgTdOMIdabHpne2MW8hAGqzTQOTFIYUuBQc75Y4yPRn+PrYa2Yq9dTkEKS93Tap5xPo/tFcYTdD3W2OZqE6/6/B2v1wf8qnz9a0oFK+gaXLMFgLXyfWpxedzG9aXzQqN4WOVVKnSnCLtqjmxzuk07O+0bpIGLpUessRAn4B+/dAslGGvdEGQJIw== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0433; X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0433; 20:wnLdjzESSNU5P3nACaxGmbF1Ow2jx7Xs4WnkxyiZfV9Ms+Dh+laSi9tct+N/RExDOhEBlja7oSkX9kKMdyvbzpQXRLEef10e7DiKSGdJ96t7poV2GdoYEQNzznOJox2cM0kOFjgbjOPndRroMhU4dVLPy1jQ8trkKZEwMpnHQJYM+p5wdrE/YPNTaQfAH24WUDwmC3OqMajdUeuywFJ62EXrSd+d3MZ5bEvpWgqKLSiUvJt/mz7p+ZbAlfscTu9gmr+yYCVnTKfVH990N5Gkc4f2GRbq6wKO997N3vg9vMYNMEi4x+EA+rxcUKFXaX3zgjaqkxGf+v9pwaEWLOqNlpBZeyRbjXQ6Bw+ccfn4qCYvuSxPdMjqM0fHiByw/nyRcijeENX7XkfV8lI5N6pEWO+7+m92B5241B8EN47bYPEnsIN9BGxnjCmmIX9x0X2/HHdRsIcBZSd2iz4ocBbxCBxdPxVZh+TVGjJ3F2d/sRkYPR3k4F0/XMd/EjdP4vKy; 4:6PSKscMa7Qo1VanfrFD59huOO5G45CYHeM/F1fNtZcaBlDVwku+p2gqURWHHgqHVAlcK7g3tFXh4jdTN1Iozw+hcHxLTjbxQUEZBsQCRqDI3gUJ0Wyafj3OhqyHtOGXiCeuXv02/jA82LOXw234/hxyJ33LaKqpTIHKa9bkOsihAUM0E9WVao48Uk5Q0oWoZrL1+u3ipU8E0Yx0zqAZC/ncRzVNGtyHouy8LmcxtDWMbs0OOAFUtGfYgHlUj9vy3aJpvwikins2HG0rm/AOrk33n/047IORht4dAkLgznroe92nLaAOiMYNoPRVnY5xH9KAjLdfTGFW2geNDJeYGghDMqgWxWoqD7HhR6qHjz5rJtXDM9A6K8N65Z3SKo9DxxeVO3/gmEkQ4esXvbvBJ7gBcdxToQDWNLMGADnqNkKFg6iItkgjlUKEBsALM7oXJ X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(9101528026)(9101521098)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6055026); SRVR:BLUPR12MB0433; BCL:0; PCL:0; RULEID:; SRVR:BLUPR12MB0433; X-Forefront-PRVS: 093290AD39 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(50986999)(76176999)(50226002)(47776003)(66066001)(229853001)(36756003)(189998001)(19580395003)(19580405001)(2906002)(2950100001)(5003940100001)(53416004)(2201001)(5004730100002)(92566002)(4326007)(5001770100001)(77096005)(586003)(42186005)(5008740100001)(81166005)(48376002)(3846002)(6116002)(575784001)(86362001)(50466002); DIR:OUT; SFP:1101; SCL:1; SRVR:BLUPR12MB0433; H:ssuthiku-cz-dev.amd.com; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0433; 23:OYSMnnU8QYJn3odtEyOXD3XAzh9ztKPVEbRyyx9HkeK+4S5ce3Vssplr1h3pgCj03t/Dpz205cTaV6aMAj5Ld+DLXhWhH7OOFGEoY7ro62nV+gwAihavUCcowT9vjf0eSMpAR/1P87DI+WVX9+651e34eZNe8e0+JeJBgFMpq5hz3fxpqOnAFpIdc8rLVZ3HoLK5dMsoRwx149gaYWygFlNXJfRGzqCFjIGwASYMvcyHT1+j6oWFyrrciUSiRVrqBmH4VBtXW4pl9L38aBwOTfGSDIuH6Od727iIN4fZUfMpMZx/bh2py8z0WCkPTsIFny/6SQ9IdjIEFZPIppIOitkivRhzK2n8HJqBR5bwxyfhBvu7+6wE7sj1Jn0H81rD80XzDi0UXFZro/Q60prH7bukqVrrRFXHyFbpGUgYtgQMSP7UX55p1Ay86zd7ahRE2iU/eggecKWHHGr/FeyWfZXISzaoT7BX/CPIKM2yD2tLXUc+2uivM0+yXlrUimCKEL1Xj1cZkp/IMSKK95/3OL5FRRL2NEdkLgUo9VMIU9rlrJzyeF6m/y/J2jAoQbT6Thike7VSLzXOVTXKHPyRTWrafCRB705tS8Y5wZHAZh8yrI89LUHQLwZOWD3jaXIZNZSqhl2DftC6is4jtPPc0H59YNGXV2rYz8Evb6gPnnRKcXH9wqd094Exrmr0cs+/KvmGJHpTYNSuGU3RKww7InTGK3nX+upZCsuY/Nl9U0wqIt42F4D5zNKvH0ZSsFPyOtK7Aa/2qq0Fm1xQcrW/S/kQnFuW0qnaXXa0dbYp5DBN8sQg/Yb6do8bMqExzzR4LyWp8KN1ZMMzREwU+GvrA9yKDRLqAxut5pUOWa/vy8paPd1e3Tj6aGK4+UdciHp3J1a1IyOgvABV9IB9QTZGBg== X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0433; 5:E+9pGWh/aGw0UB/9BWBlwCOrfjaKoV2MDgCv909zWWGetJCarmaTqNhrjy2Oy1oPl106RBfk2+HzKIa173MTlTJ5n9Y4fsQY1Hgw7tXZl6HAcMGZFaa6QkFDmBwf7mQOEeAlcPkq86QuVRQBqDSOZg==; 24:CzwOgCm3GKXPDxI+j4FwTPfGkxG2tDJDg8Jk6tzbMlBuF1WuayAnIUIKxxH3GQg4OxOBybs7tygDxsh8e3ZGLXS3q3GS9v75/q705WdnENA=; 7:zM4SMobep7B4xYOKv/bGLb6mBX9pquiXx9/K2hI3zF5hBIjwFyvwzgqMgzL5vGR/0b0wAWkipTP2fHYGucie5I9cwYQFZJ+dPi6I+uohR0zZlEL7FA4R6g/LDpYzdzyh7PSSH9/Er902KW5zLwqEPl5/DUmsUzgbt1sdt6Yctug=; 20:VUG7vUTVH3nvdcHog14dO47TDn7l7qJuk7bJMX5AyKZ58Roxk14L5Q5fQfLx9xBYCrNnbicN1UQSfZ3HjKmSduWkwgMRDBrPXZqxudlMVRsmOww7VsscRkoMw8lUxbApLAYyE3KknaQjltqgug1MEq6o1ohHwz5lSbKlfvf+CXFuGzj3fpDgaf611FkO41nBlCI5KguNO0zLj1U8NLvQlAcplIMf95YFVmiQ9q8UjV71E2pR/4bPiR5OxIZJ53J5 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 May 2016 19:11:00.0883 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BLUPR12MB0433 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suravee Suthikulpanit This patch introduces VMEXIT handlers, avic_incomplete_ipi_interception() and avic_unaccelerated_access_interception() along with two trace points (trace_kvm_avic_incomplete_ipi and trace_kvm_avic_unaccelerated_access). Signed-off-by: Suravee Suthikulpanit --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/include/uapi/asm/svm.h | 9 +- arch/x86/kvm/lapic.h | 3 + arch/x86/kvm/svm.c | 279 ++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/trace.h | 57 ++++++++ arch/x86/kvm/x86.c | 2 + 6 files changed, 350 insertions(+), 1 deletion(-) -- 1.9.1 diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1ff2d46..a87e825 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -776,6 +776,7 @@ struct kvm_arch { bool disabled_lapic_found; /* Struct members for AVIC */ + u32 ldr_mode; struct page *avic_logical_id_table_page; struct page *avic_physical_id_table_page; }; diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 8a4add8..b9e9bb2 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_sel_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 bbe5d12..891c6da 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 3a97874..90b34fa 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -91,6 +91,10 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); */ #define AVIC_MAX_PHYSICAL_ID_COUNT 255 +#define AVIC_UNACCEL_ACCESS_WRITE_MASK 1 +#define AVIC_UNACCEL_ACCESS_OFFSET_MASK 0xFF0 +#define AVIC_UNACCEL_ACCESS_VECTOR_MASK 0xFFFFFFFF + static bool erratum_383_found __read_mostly; static const u32 host_save_user_msrs[] = { @@ -176,6 +180,7 @@ struct vcpu_svm { /* cached guest cpuid flags for faster access */ bool nrips_enabled : 1; + u32 ldr_reg; struct page *avic_backing_page; u64 *avic_physical_id_cache; }; @@ -3491,6 +3496,278 @@ 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_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat) +{ + struct kvm_arch *vm_data = &vcpu->kvm->arch; + int index; + u32 *logical_apic_id_table; + int dlid = GET_APIC_LOGICAL_ID(ldr); + + if (!dlid) + return NULL; + + if (flat) { /* flat */ + index = ffs(dlid) - 1; + if (index > 7) + return NULL; + } else { /* cluster */ + int cluster = (dlid & 0xf0) >> 4; + int apic = ffs(dlid & 0x0f) - 1; + + if ((apic < 0) || (apic > 7) || + (cluster >= 0xf)) + return NULL; + index = (cluster << 2) + apic; + } + + logical_apic_id_table = (u32 *) page_address(vm_data->avic_logical_id_table_page); + + return &logical_apic_id_table[index]; +} + +static int avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr, + bool valid) +{ + bool flat; + u32 *entry, new_entry; + + flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT; + entry = avic_get_logical_id_entry(vcpu, ldr, flat); + if (!entry) + return -EINVAL; + + new_entry = READ_ONCE(*entry); + new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; + new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK); + if (valid) + new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK; + else + new_entry &= ~AVIC_LOGICAL_ID_ENTRY_VALID_MASK; + WRITE_ONCE(*entry, new_entry); + + return 0; +} + +static int avic_handle_ldr_update(struct kvm_vcpu *vcpu) +{ + int ret; + struct vcpu_svm *svm = to_svm(vcpu); + u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR); + + if (!ldr) + return 1; + + ret = avic_ldr_write(vcpu, vcpu->vcpu_id, ldr, true); + if (ret && svm->ldr_reg) { + avic_ldr_write(vcpu, 0, svm->ldr_reg, false); + svm->ldr_reg = 0; + } else { + svm->ldr_reg = ldr; + } + return ret; +} + +static int avic_handle_apic_id_update(struct kvm_vcpu *vcpu) +{ + u64 *old, *new; + struct vcpu_svm *svm = to_svm(vcpu); + u32 apic_id_reg = kvm_lapic_get_reg(vcpu->arch.apic, APIC_ID); + u32 id = (apic_id_reg >> 24) & 0xff; + + if (vcpu->vcpu_id == id) + return 0; + + old = avic_get_physical_id_entry(vcpu, vcpu->vcpu_id); + new = avic_get_physical_id_entry(vcpu, id); + if (!new || !old) + return 1; + + /* We need to move physical_id_entry to new offset */ + *new = *old; + *old = 0ULL; + to_svm(vcpu)->avic_physical_id_cache = new; + + /* + * Also update the guest physical APIC ID in the logical + * APIC ID table entry if already setup the LDR. + */ + if (svm->ldr_reg) + avic_handle_ldr_update(vcpu); + + return 0; +} + +static int avic_handle_dfr_update(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct kvm_arch *vm_data = &vcpu->kvm->arch; + u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR); + u32 mod = (dfr >> 28) & 0xf; + + /* + * We assume that all local APICs are using the same type. + * If this changes, we need to flush the AVIC logical + * APID id table. + */ + if (vm_data->ldr_mode == mod) + return 0; + + clear_page(page_address(vm_data->avic_logical_id_table_page)); + vm_data->ldr_mode = mod; + + if (svm->ldr_reg) + avic_handle_ldr_update(vcpu); + return 0; +} + +static int avic_unaccel_trap_write(struct vcpu_svm *svm) +{ + struct kvm_lapic *apic = svm->vcpu.arch.apic; + u32 offset = svm->vmcb->control.exit_info_1 & + AVIC_UNACCEL_ACCESS_OFFSET_MASK; + + switch (offset) { + case APIC_ID: + if (avic_handle_apic_id_update(&svm->vcpu)) + return 0; + break; + case APIC_LDR: + if (avic_handle_ldr_update(&svm->vcpu)) + return 0; + break; + case APIC_DFR: + avic_handle_dfr_update(&svm->vcpu); + break; + default: + break; + } + + kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset)); + + 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; +} + +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_MASK; + u32 vector = svm->vmcb->control.exit_info_2 & + AVIC_UNACCEL_ACCESS_VECTOR_MASK; + bool write = (svm->vmcb->control.exit_info_1 >> 32) & + AVIC_UNACCEL_ACCESS_WRITE_MASK; + bool trap = is_avic_unaccelerated_access_trap(offset); + + trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset, + trap, write, vector); + if (trap) { + /* Handling Trap */ + WARN_ONCE(!write, "svm: Handling trap read.\n"); + 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, @@ -3554,6 +3831,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) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index b72743c..8de9250 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1291,6 +1291,63 @@ TRACE_EVENT(kvm_hv_stimer_cleanup, __entry->vcpu_id, __entry->timer_index) ); +/* + * Tracepoint for AMD AVIC + */ +TRACE_EVENT(kvm_avic_incomplete_ipi, + TP_PROTO(u32 vcpu, u32 icrh, u32 icrl, u32 id, u32 index), + TP_ARGS(vcpu, icrh, icrl, id, index), + + TP_STRUCT__entry( + __field(u32, vcpu) + __field(u32, icrh) + __field(u32, icrl) + __field(u32, id) + __field(u32, index) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->icrh = icrh; + __entry->icrl = icrl; + __entry->id = id; + __entry->index = index; + ), + + TP_printk("vcpu=%u, icrh:icrl=%#010x:%08x, id=%u, index=%u\n", + __entry->vcpu, __entry->icrh, __entry->icrl, + __entry->id, __entry->index) +); + +TRACE_EVENT(kvm_avic_unaccelerated_access, + TP_PROTO(u32 vcpu, u32 offset, bool ft, bool rw, u32 vec), + TP_ARGS(vcpu, offset, ft, rw, vec), + + TP_STRUCT__entry( + __field(u32, vcpu) + __field(u32, offset) + __field(bool, ft) + __field(bool, rw) + __field(u32, vec) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->offset = offset; + __entry->ft = ft; + __entry->rw = rw; + __entry->vec = vec; + ), + + TP_printk("vcpu=%u, offset=%#x(%s), %s, %s, vec=%#x\n", + __entry->vcpu, + __entry->offset, + __print_symbolic(__entry->offset, kvm_trace_symbol_apic), + __entry->ft ? "trap" : "fault", + __entry->rw ? "write" : "read", + __entry->vec) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bbdcaa8..336a2b9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8434,3 +8434,5 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi);