From patchwork Fri Sep 21 14:25:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brijesh Singh X-Patchwork-Id: 973248 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=amd.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=amdcloud.onmicrosoft.com header.i=@amdcloud.onmicrosoft.com header.b="2neYb1YK"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42Gwvw0jZ9z9sBn for ; Sat, 22 Sep 2018 00:29:16 +1000 (AEST) Received: from localhost ([::1]:55913 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g3MQj-0004In-MZ for incoming@patchwork.ozlabs.org; Fri, 21 Sep 2018 10:29:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36485) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g3MNP-0001eK-L2 for qemu-devel@nongnu.org; Fri, 21 Sep 2018 10:25:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g3MNL-0001JN-Is for qemu-devel@nongnu.org; Fri, 21 Sep 2018 10:25:47 -0400 Received: from mail-bn3nam01on0080.outbound.protection.outlook.com ([104.47.33.80]:16765 helo=NAM01-BN3-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1g3MNL-0001IV-Bt for qemu-devel@nongnu.org; Fri, 21 Sep 2018 10:25:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=V4BkeUAzXAQvATOWDyJv7YM2nsjazmHL1n0gGnprKuU=; b=2neYb1YKcX/J31+7NFyBQuoCSle78XFmjkE6L2VdVHVd6NZZk1NMimkYZ7mEbGiECnLdwlPW9ufS77mar/Pf26kexumVSBLGgmvr1iVhhvMFZeQVuwO4wF1tAMaZZ9qGAIzUWzcUWJleG3rHWOgXqYGCgqLWNT3P7Q5bu6VnkWk= Received: from DM6PR12MB2682.namprd12.prod.outlook.com (20.176.116.31) by DM6PR12MB2651.namprd12.prod.outlook.com (20.176.116.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1143.18; Fri, 21 Sep 2018 14:25:40 +0000 Received: from DM6PR12MB2682.namprd12.prod.outlook.com ([fe80::7c34:f2e8:a8a9:cab8]) by DM6PR12MB2682.namprd12.prod.outlook.com ([fe80::7c34:f2e8:a8a9:cab8%2]) with mapi id 15.20.1143.017; Fri, 21 Sep 2018 14:25:40 +0000 From: "Singh, Brijesh" To: "qemu-devel@nongnu.org" Thread-Topic: [PATCH v3 6/9] x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled Thread-Index: AQHUUbb4lKxHtzItIU60icXqywCTsA== Date: Fri, 21 Sep 2018 14:25:40 +0000 Message-ID: <1537539920-30662-7-git-send-email-brijesh.singh@amd.com> References: <1537539920-30662-1-git-send-email-brijesh.singh@amd.com> In-Reply-To: <1537539920-30662-1-git-send-email-brijesh.singh@amd.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: DM5PR21CA0008.namprd21.prod.outlook.com (2603:10b6:3:ac::18) To DM6PR12MB2682.namprd12.prod.outlook.com (2603:10b6:5:4a::31) authentication-results: spf=none (sender IP is ) smtp.mailfrom=brijesh.singh@amd.com; x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [165.204.77.1] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM6PR12MB2651; 20:4VZ2H6aEWLMuEqgTZeASrFtqq2eHK1ESqvNnn5XsvaJ70vE/Ym+PA2y5TLX53nMgTCD/V0JArkZ2jbJxjG/WwZ5mGjONbxwPyqmmp12KN8LT5/iM5ZderKikpMWj6wAWWDBnm5md3+plRYK+U5YNx5J6LbMCtyr5iWgnVA8l/Y1kJ2gMgE/oVuqd9H1g5Aer482+I+FqXB9fgzOn60/reIxJF2oOXWn5GfdrnsCO2LRjtxpRP3Sg1bdxrGpYsxtz x-ms-office365-filtering-correlation-id: a5b9fcd6-a5f8-4929-8802-08d61fce1b0a x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7153060)(7193020); SRVR:DM6PR12MB2651; x-ms-traffictypediagnostic: DM6PR12MB2651: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(85827821059158)(767451399110); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(823301075)(93006095)(93001095)(3002001)(3231355)(944501410)(52105095)(10201501046)(6055026)(149027)(150027)(6041310)(20161123564045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123558120)(20161123560045)(201708071742011)(7699051); SRVR:DM6PR12MB2651; BCL:0; PCL:0; RULEID:; SRVR:DM6PR12MB2651; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(396003)(136003)(39860400002)(366004)(346002)(376002)(199004)(189003)(6512007)(81166006)(5250100002)(2501003)(14444005)(256004)(486006)(11346002)(446003)(3846002)(39060400002)(8676002)(2351001)(186003)(8936002)(6116002)(2616005)(5640700003)(2906002)(53936002)(66066001)(81156014)(25786009)(6436002)(99286004)(68736007)(105586002)(476003)(6486002)(575784001)(86362001)(6916009)(305945005)(2900100001)(5660300001)(316002)(7736002)(106356001)(26005)(478600001)(76176011)(36756003)(386003)(52116002)(6506007)(54906003)(4326008)(102836004)(14454004)(71190400001)(97736004)(71200400001); DIR:OUT; SFP:1101; SCL:1; SRVR:DM6PR12MB2651; H:DM6PR12MB2682.namprd12.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: amd.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: ivBFw8EMS7RTX66RFz5Syg1DPCrTLPvlvpbG4r+Jsf2BreSOEVVq4pGljLUzvcUpcCeJshzMff8hTmDqIe2AO7Xv+fjO9MYRxzkUmEaTlIfMJaCEdcYwSLE8TFUAXwBvF/k9DMj+szoXz0/HJXw2uTdnY6wr7dw3ywhgjArvgF2jw2mRUZqBloR1JlWZb4Y8+cyQFcjoJFejBxCzWr7jWUoC1Z9G0KSn0RrpScb9mS7r0az//BaXAMCfVIGIAwhmbCohdt+uBDjz81eMOHI/udQBChpAu+cWDVcQDtlkrhy1ujKNY05n8BdoYvwKOgUaG5QnKxVQsnSmAxr3Khu2UuxAYD+c7UnQHUZxjbNd5O4= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-Network-Message-Id: a5b9fcd6-a5f8-4929-8802-08d61fce1b0a X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 14:25:40.2059 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR12MB2651 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.33.80 Subject: [Qemu-devel] [PATCH v3 6/9] x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "Lendacky, Thomas" , "Singh, Brijesh" , Eduardo Habkost , "Michael S. Tsirkin" , Peter Xu , Paolo Bonzini , "Suthikulpanit, Suravee" , Richard Henderson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Emulate the interrupt remapping support when guest virtual APIC is not enabled. For more info Refer: AMD IOMMU spec Rev 3.0 - section 2.2.5.1 When VAPIC is not enabled, it uses interrupt remapping as defined in Table 20 and Figure 15 from IOMMU spec. Signed-off-by: Brijesh Singh Cc: Peter Xu Cc: "Michael S. Tsirkin" Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: Marcel Apfelbaum Cc: Tom Lendacky Cc: Suravee Suthikulpanit --- hw/i386/amd_iommu.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++- hw/i386/amd_iommu.h | 46 +++++++++++- hw/i386/trace-events | 7 ++ 3 files changed, 252 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index dcf0bfb..7a6bbb5 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -28,6 +28,7 @@ #include "qemu/error-report.h" #include "hw/i386/apic_internal.h" #include "trace.h" +#include "hw/i386/apic-msidef.h" /* used AMD-Vi MMIO registers */ const char *amdvi_mmio_low[] = { @@ -1029,17 +1030,144 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr, return ret; } +static int amdvi_get_irte(AMDVIState *s, MSIMessage *origin, uint64_t *dte, + union irte *irte, uint16_t devid) +{ + uint64_t irte_root, offset; + + irte_root = dte[2] & AMDVI_IR_PHYS_ADDR_MASK; + offset = (origin->data & AMDVI_IRTE_OFFSET) << 2; + + trace_amdvi_ir_irte(irte_root, offset); + + if (dma_memory_read(&address_space_memory, irte_root + offset, + irte, sizeof(*irte))) { + trace_amdvi_ir_err("failed to get irte"); + return -AMDVI_IR_GET_IRTE; + } + + trace_amdvi_ir_irte_val(irte->val); + + return 0; +} + +static int amdvi_int_remap_legacy(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint64_t *dte, + X86IOMMUIrq *irq, + uint16_t sid) +{ + int ret; + union irte irte; + + /* get interrupt remapping table */ + ret = amdvi_get_irte(iommu, origin, dte, &irte, sid); + if (ret < 0) { + return ret; + } + + if (!irte.fields.valid) { + trace_amdvi_ir_target_abort("RemapEn is disabled"); + return -AMDVI_IR_TARGET_ABORT; + } + + if (irte.fields.guest_mode) { + trace_amdvi_ir_err("guest mode is not zero"); + return -AMDVI_IR_ERR; + } + + if (irte.fields.int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) { + trace_amdvi_ir_err("reserved int_type"); + return -AMDVI_IR_ERR; + } + + irq->delivery_mode = irte.fields.int_type; + irq->vector = irte.fields.vector; + irq->dest_mode = irte.fields.dm; + irq->redir_hint = irte.fields.rq_eoi; + irq->dest = irte.fields.destination; + + return 0; +} + +static int __amdvi_int_remap_msi(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint64_t *dte, + X86IOMMUIrq *irq, + uint16_t sid) +{ + uint8_t int_ctl; + + int_ctl = (dte[2] >> AMDVI_IR_INTCTL_SHIFT) & 3; + trace_amdvi_ir_intctl(int_ctl); + + switch (int_ctl) { + case AMDVI_IR_INTCTL_PASS: + memcpy(translated, origin, sizeof(*origin)); + return 0; + case AMDVI_IR_INTCTL_REMAP: + break; + case AMDVI_IR_INTCTL_ABORT: + trace_amdvi_ir_target_abort("int_ctl abort"); + return -AMDVI_IR_TARGET_ABORT; + default: + trace_amdvi_ir_err("int_ctl reserved"); + return -AMDVI_IR_ERR; + } + + return amdvi_int_remap_legacy(iommu, origin, translated, dte, irq, sid); +} + +static bool amdvi_validate_int_remap(AMDVIState *s, uint64_t *dte) +{ + /* Check if IR is enabled in DTE */ + if (!(dte[2] & AMDVI_IR_REMAP_ENABLE)) { + return false; + } + + /* validate that we are configure with intremap=on */ + if (!X86_IOMMU_DEVICE(s)->intr_supported) { + error_report("Interrupt remapping is enabled in the guest but " + "not in the host. Use intremap=on to enable interrupt " + "remapping in amd-iommu."); + return false; + } + + return true; +} + /* Interrupt remapping for MSI/MSI-X entry */ static int amdvi_int_remap_msi(AMDVIState *iommu, MSIMessage *origin, MSIMessage *translated, uint16_t sid) { + int ret = 0; + uint64_t pass = 0; + uint64_t dte[4] = { 0 }; + X86IOMMUIrq irq = { 0 }; + uint8_t dest_mode, delivery_mode; + assert(origin && translated); + /* + * When IOMMU is enabled, interrupt remap request will come either from + * IO-APIC or PCI device. If interrupt is from PCI device then it will + * have a valid requester id but if the interrupt is from IO-APIC + * then requester id will be invalid. + */ + if (sid == X86_IOMMU_SID_INVALID) { + sid = AMDVI_IOAPIC_SB_DEVID; + } + trace_amdvi_ir_remap_msi_req(origin->address, origin->data, sid); - if (!iommu || !X86_IOMMU_DEVICE(iommu)->intr_supported) { + /* verify that interrupt remapping is enabled before going further. */ + if (!iommu || + !amdvi_get_dte(iommu, sid, dte) || + !amdvi_validate_int_remap(iommu, dte)) { memcpy(translated, origin, sizeof(*origin)); goto out; } @@ -1055,10 +1183,81 @@ static int amdvi_int_remap_msi(AMDVIState *iommu, return -AMDVI_IR_ERR; } + /* + * The MSI data register [10:8] are used to get the upstream interrupt type. + * + * amd-iommu device does not emulate the HyperTransport hence use the + * IO-APIC encoding definition (IO-APIC spec 3.2.4) instead of the + * HyperTransport (IOMMU spec Table 19). + */ + delivery_mode = (origin->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 7; + + switch (delivery_mode) { + case AMDVI_IOAPIC_INT_TYPE_FIXED: + case AMDVI_IOAPIC_INT_TYPE_ARBITRATED: + trace_amdvi_ir_delivery_mode("fixed/arbitrated"); + ret = __amdvi_int_remap_msi(iommu, origin, translated, dte, &irq, sid); + if (ret < 0) { + goto remap_fail; + } else { + /* Translate IRQ to MSI messages */ + x86_iommu_irq_to_msi_message(&irq, translated); + goto out; + } + break; + case AMDVI_IOAPIC_INT_TYPE_SMI: + error_report("SMI is not supported!"); + ret = -AMDVI_IR_ERR; + break; + case AMDVI_IOAPIC_INT_TYPE_NMI: + pass = dte[3] & AMDVI_DEV_NMI_PASS_MASK; + trace_amdvi_ir_delivery_mode("nmi"); + break; + case AMDVI_IOAPIC_INT_TYPE_INIT: + pass = dte[3] & AMDVI_DEV_INT_PASS_MASK; + trace_amdvi_ir_delivery_mode("init"); + break; + case AMDVI_IOAPIC_INT_TYPE_EINT: + pass = dte[3] & AMDVI_DEV_EINT_PASS_MASK; + trace_amdvi_ir_delivery_mode("eint"); + break; + default: + trace_amdvi_ir_delivery_mode("unsupported delivery_mode"); + ret = -AMDVI_IR_ERR; + break; + } + + if (ret < 0) { + goto remap_fail; + } + + /* + * The MSI address register bit[2] is used to get the destination + * mode. The dest_mode 1 is valid for fixed and arbitrated interrupts + * only. + */ + dest_mode = (origin->address >> MSI_ADDR_DEST_MODE_SHIFT) & 1; + if (dest_mode) { + trace_amdvi_ir_err("invalid dest_mode"); + ret = -AMDVI_IR_ERR; + goto remap_fail; + } + + if (pass) { + memcpy(translated, origin, sizeof(*origin)); + } else { + trace_amdvi_ir_err("passthrough is not enabled"); + ret = -AMDVI_IR_ERR; + goto remap_fail; + } + out: trace_amdvi_ir_remap_msi(origin->address, origin->data, translated->address, translated->data); return 0; + +remap_fail: + return ret; } static int amdvi_int_remap(X86IOMMUState *iommu, diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 4e7cc27..f73be48 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -217,7 +217,51 @@ /* Interrupt remapping errors */ #define AMDVI_IR_ERR 0x1 - +#define AMDVI_IR_GET_IRTE 0x2 +#define AMDVI_IR_TARGET_ABORT 0x3 + +/* Interrupt remapping */ +#define AMDVI_IR_REMAP_ENABLE 1ULL +#define AMDVI_IR_INTCTL_SHIFT 60 +#define AMDVI_IR_INTCTL_ABORT 0 +#define AMDVI_IR_INTCTL_PASS 1 +#define AMDVI_IR_INTCTL_REMAP 2 + +#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6) + +/* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */ +#define AMDVI_IRTE_OFFSET 0x7ff + +/* Delivery mode of MSI data (same as IOAPIC deilver mode encoding) */ +#define AMDVI_IOAPIC_INT_TYPE_FIXED 0x0 +#define AMDVI_IOAPIC_INT_TYPE_ARBITRATED 0x1 +#define AMDVI_IOAPIC_INT_TYPE_SMI 0x2 +#define AMDVI_IOAPIC_INT_TYPE_NMI 0x4 +#define AMDVI_IOAPIC_INT_TYPE_INIT 0x5 +#define AMDVI_IOAPIC_INT_TYPE_EINT 0x7 + +/* Pass through interrupt */ +#define AMDVI_DEV_INT_PASS_MASK (1UL << 56) +#define AMDVI_DEV_EINT_PASS_MASK (1UL << 57) +#define AMDVI_DEV_NMI_PASS_MASK (1UL << 58) +#define AMDVI_DEV_LINT0_PASS_MASK (1UL << 62) +#define AMDVI_DEV_LINT1_PASS_MASK (1UL << 63) + +/* Interrupt remapping table fields (Guest VAPIC not enabled) */ +union irte { + uint32_t val; + struct { + uint32_t valid:1, + no_fault:1, + int_type:3, + rq_eoi:1, + dm:1, + guest_mode:1, + destination:8, + vector:8, + rsvd:8; + } fields; +}; #define TYPE_AMD_IOMMU_DEVICE "amd-iommu" #define AMD_IOMMU_DEVICE(obj)\ diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 41d533c..98150c9 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -106,6 +106,13 @@ amdvi_mem_ir_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" data 0x%"PRIx6 amdvi_ir_remap_msi_req(uint64_t addr, uint64_t data, uint8_t devid) "addr 0x%"PRIx64" data 0x%"PRIx64" devid 0x%"PRIx8 amdvi_ir_remap_msi(uint64_t addr, uint64_t data, uint64_t addr2, uint64_t data2) "(addr 0x%"PRIx64", data 0x%"PRIx64") -> (addr 0x%"PRIx64", data 0x%"PRIx64")" amdvi_err(const char *str) "%s" +amdvi_ir_irte(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" offset 0x%"PRIx64 +amdvi_ir_irte_val(uint32_t data) "data 0x%"PRIx32 +amdvi_ir_err(const char *str) "%s" +amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8 +amdvi_ir_target_abort(const char *str) "%s" +amdvi_ir_delivery_mode(const char *str) "%s" +amdvi_ir_generate_msi_message(uint8_t vector, uint8_t delivery_mode, uint8_t dest_mode, uint8_t dest, uint8_t rh) "vector %d delivery-mode %d dest-mode %d dest-id %d rh %d" # hw/i386/vmport.c vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"