Received: by 2002:a25:e74b:0:0:0:0:0 with SMTP id e72csp1353015ybh; Mon, 13 Jul 2020 16:49:45 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzNycQntBmO0w9Bs8ELjrdho4/dVtbH18zOAfYP5x+Hm+WwoiCT82sF55TljwhtfJ/IsUzU X-Received: by 2002:a05:6402:1bdd:: with SMTP id ch29mr1832494edb.134.1594684185009; Mon, 13 Jul 2020 16:49:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594684185; cv=none; d=google.com; s=arc-20160816; b=T7lp+n4IiQ9S5MzyB4NPwOf1mzgXeb3rj0pFnmbe+uYg1+UDL/x8viNgX1MQnaWYJy fm8j7fpFGFjj6vErG2oQo1Xca27QYSUP56v3ige3VaWRK2qiVbt7JWMVbBnDocgiksUP UPKbjDAe/lyhTPG4hidWrf72k8MFl1rOPS3U7DELJmcgzZeUywJi9YvFxEUU0lLDFOVn Hn+YnUvcsNurnulOTFmA0ZUYBdcZDezLmiBXQLLJKTARE9HvtpoU0w21y0gGCpfOrfxy qfjkZ9KYTJvEUypSAttAN4YDEwaE1A/gBcdmXfgLohuLthxBJl2ofdtzzruaIJU7x6vx k1iA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:ironport-sdr:ironport-sdr; bh=qLrVKcq29FgEkMgP4Yf76gwKojmT0wTDrzp+17tqI/M=; b=dnuG3SyVk13vCHhI6dWhRzNgcCp5Ngp4xSSzF7+fFb+kxV160mW8LOagrgsNyVAv1e 8u6mxvA/CjufeX/KnBwKrDKg6ZAb7w7C1jco+5t090xZVoEVpcarnO9M9SiBECQpQHuB XPvJs5BPi9vkvMxyoeZFp5dCZ9/ttAX4wYBlUMGrEFfaMmZyZCo1vcxBpiJluTcHSGmv GsEl5JZkkj8Qbt1DZS3GDhvNVTRUlZvnGLwKZrX+t5bWUIZE875yxodPMDfckknwv/dc kgH/WrL6dweHOxgGCsscBl3dVOuSlgB3LynZWaVRtyRXC2LDY9TkAnR1Lt00xifW0xDK A8Kw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v14si10320221eje.123.2020.07.13.16.49.21; Mon, 13 Jul 2020 16:49:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727120AbgGMXs4 (ORCPT + 99 others); Mon, 13 Jul 2020 19:48:56 -0400 Received: from mga03.intel.com ([134.134.136.65]:36776 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727107AbgGMXsw (ORCPT ); Mon, 13 Jul 2020 19:48:52 -0400 IronPort-SDR: e8/FZbIDC+f3ZKFYQZmgh8Uq6422amzdGgf5uyhkUPnXmZ195iyVdmmDiNvC3ZieTjsj9RDPr2 y0cgbdCRzCNA== X-IronPort-AV: E=McAfee;i="6000,8403,9681"; a="148748428" X-IronPort-AV: E=Sophos;i="5.75,349,1589266800"; d="scan'208";a="148748428" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jul 2020 16:48:47 -0700 IronPort-SDR: wts/axlb4IyjrzaEcE8dC+Qws3YgEdAbvoWMlljqE+HrbsoGXlwHiTuI29SbfXc+enz6vEwAgb AQ7vvtr2HSPg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.75,349,1589266800"; d="scan'208";a="281570479" Received: from romley-ivt3.sc.intel.com ([172.25.110.60]) by orsmga003.jf.intel.com with ESMTP; 13 Jul 2020 16:48:47 -0700 From: Fenghua Yu To: "Thomas Gleixner" , "Joerg Roedel" , "Ingo Molnar" , "Borislav Petkov" , "Peter Zijlstra" , "H Peter Anvin" , "David Woodhouse" , "Lu Baolu" , "Felix Kuehling" , "Dave Hansen" , "Tony Luck" , "Jean-Philippe Brucker" , "Christoph Hellwig" , "Ashok Raj" , "Jacob Jun Pan" , "Dave Jiang" , "Sohil Mehta" , "Ravi V Shankar" Cc: "linux-kernel" , "x86" , iommu@lists.linux-foundation.org, "amd-gfx" , Fenghua Yu Subject: [PATCH v6 12/12] x86/traps: Fix up invalid PASID Date: Mon, 13 Jul 2020 16:48:07 -0700 Message-Id: <1594684087-61184-13-git-send-email-fenghua.yu@intel.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1594684087-61184-1-git-send-email-fenghua.yu@intel.com> References: <1594684087-61184-1-git-send-email-fenghua.yu@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org A #GP fault is generated when ENQCMD instruction is executed without a valid PASID value programmed in the current thread's PASID MSR. The #GP fault handler will initialize the MSR if a PASID has been allocated for this process. Decoding the user instruction is ugly and sets a bad architecture precedent. It may not function if the faulting instruction is modified after #GP. Thomas suggested to provide a reason for the #GP caused by executing ENQCMD without a valid PASID value programmed. #GP error codes are 16 bits and all 16 bits are taken. Refer to SDM Vol 3, Chapter 16.13 for details. The other choice was to reflect the error code in an MSR. ENQCMD can also cause #GP when loading from the source operand, so its not fully comprehending all the reasons. Rather than special case the ENQCMD, in future Intel may choose a different fault mechanism for such cases if recovery is needed on #GP. The following heuristic is used to avoid decoding the user instructions to determine the precise reason for the #GP fault: 1) If the mm for the process has not been allocated a PASID, this #GP cannot be fixed. 2) If the PASID MSR is already initialized, then the #GP was for some other reason 3) Try initializing the PASID MSR and returning. If the #GP was from an ENQCMD this will fix it. If not, the #GP fault will be repeated and will hit case "2". Suggested-by: Thomas Gleixner Signed-off-by: Fenghua Yu Reviewed-by: Tony Luck Reviewed-by: Lu Baolu --- v5: - Use cpu_feature_enabled() and remove redundant CONFIG_INTEL_IOMMU_SVM check which is included in cpu_feature_enabled() in fixup_pasid_exception() (PeterZ and Dave Hansen) - Reviewed by Lu Baolu v4: - Change PASID type to u32 (Christoph) v3: - Check and set current->has_valid_pasid in fixup() (PeterZ) - Add fpu__pasid_write() to update the MSR (PeterZ) - Add ioasid_find() sanity check in fixup() v2: - Update the first paragraph of the commit message (Thomas) - Add reasons why don't decode the user instruction and don't use #GP error code (Thomas) - Change get_task_mm() to current->mm (Thomas) - Add comments on why IRQ is disabled during PASID fixup (Thomas) - Add comment in fixup() that the function is called when #GP is from user (so mm is not NULL) (Dave Hansen) arch/x86/include/asm/iommu.h | 1 + arch/x86/kernel/traps.c | 12 ++++++ drivers/iommu/intel/svm.c | 78 ++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index ed41259fe7ac..e9365a5d6f7d 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -27,5 +27,6 @@ arch_rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr) } void __free_pasid(struct mm_struct *mm); +bool __fixup_pasid_exception(void); #endif /* _ASM_X86_IOMMU_H */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index f58679e487f6..fe0f7d00523b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 #include @@ -518,6 +519,14 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs, return GP_CANONICAL; } +static bool fixup_pasid_exception(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_ENQCMD)) + return false; + + return __fixup_pasid_exception(); +} + #define GPFSTR "general protection fault" DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) @@ -530,6 +539,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) cond_local_irq_enable(regs); + if (user_mode(regs) && fixup_pasid_exception()) + goto exit; + if (static_cpu_has(X86_FEATURE_UMIP)) { if (user_mode(regs) && fixup_umip_exception(regs)) goto exit; diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 4c788880b037..4a84c82a4f8c 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -1105,3 +1105,81 @@ void __free_pasid(struct mm_struct *mm) */ ioasid_free(pasid); } + +/* + * Write the current task's PASID MSR/state. This is called only when PASID + * is enabled. + */ +static void fpu__pasid_write(u32 pasid) +{ + u64 msr_val = pasid | MSR_IA32_PASID_VALID; + + fpregs_lock(); + + /* + * If the MSR is active and owned by the current task's FPU, it can + * be directly written. + * + * Otherwise, write the fpstate. + */ + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { + wrmsrl(MSR_IA32_PASID, msr_val); + } else { + struct ia32_pasid_state *ppasid_state; + + ppasid_state = get_xsave_addr(¤t->thread.fpu.state.xsave, + XFEATURE_PASID); + /* + * ppasid_state shouldn't be NULL because XFEATURE_PASID + * is enabled. + */ + WARN_ON_ONCE(!ppasid_state); + ppasid_state->pasid = msr_val; + } + fpregs_unlock(); +} + +/* + * Apply some heuristics to see if the #GP fault was caused by a thread + * that hasn't had the IA32_PASID MSR initialized. If it looks like that + * is the problem, try initializing the IA32_PASID MSR. If the heuristic + * guesses incorrectly, take one more #GP fault. + */ +bool __fixup_pasid_exception(void) +{ + struct intel_svm *svm; + struct mm_struct *mm; + u32 pasid; + + /* + * If the current task already has a valid PASID in the MSR, + * the #GP must be for some other reason. + */ + if (current->has_valid_pasid) + return false; + + /* + * This function is called only when this #GP was triggered from user + * space. So the mm cannot be NULL. + */ + mm = current->mm; + pasid = mm->pasid; + + /* + * If the PASID isn't found, cannot help. + * + * Don't care if the PASID is bound to the mm here. #PF will handle the + * case that the MSR is fixed up by an unbound PASID. + */ + svm = ioasid_find(NULL, pasid, NULL); + if (IS_ERR_OR_NULL(svm)) + return false; + + /* Fix up the MSR by the PASID in the mm. */ + fpu__pasid_write(pasid); + + /* Now the current task has a valid PASID in the MSR. */ + current->has_valid_pasid = 1; + + return true; +} -- 2.19.1