Re: [PATCH v3 08/11] x86/traps: Demand-populate PASID MSR via #GP

2022-02-04 Thread Thomas Gleixner
On Fri, Jan 28 2022 at 12:29, Fenghua Yu wrote:

> All tasks start with PASID state disabled. This means that the first
> time they execute an ENQCMD instruction they will take a #GP fault.
>
> Modify the #GP fault handler to check if the "mm" for the task has
> already been allocated a PASID. If so, try to fix the #GP fault by
> loading the IA32_PASID MSR.
>
> Signed-off-by: Fenghua Yu 
> Reviewed-by: Tony Luck 

Reviewed-by: Thomas Gleixner 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 08/11] x86/traps: Demand-populate PASID MSR via #GP

2022-01-28 Thread Fenghua Yu
All tasks start with PASID state disabled. This means that the first
time they execute an ENQCMD instruction they will take a #GP fault.

Modify the #GP fault handler to check if the "mm" for the task has
already been allocated a PASID. If so, try to fix the #GP fault by
loading the IA32_PASID MSR.

Signed-off-by: Fenghua Yu 
Reviewed-by: Tony Luck 
---
v2:
- Directly write IA32_PASID MSR in fixup while local IRQ is still disabled
  (Thomas)
- Move #ifdef over to CONFIG_IOMMU_SVA since it is what
  defines mm->pasid and ->pasid_activated (Dave Hansen).
- Rename try_fixup_pasid() -> try_fixup_enqcmd_gp(). This
  code really is highly specific to ENQCMD, not PASIDs (Dave Hansen).
- Add lockdep assert and comment about context (Dave Hansen).
- Re-flow the if() mess (Dave Hansen).

 arch/x86/kernel/traps.c | 55 +
 1 file changed, 55 insertions(+)

diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index c9d566dcf89a..7ef00dee35be 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -559,6 +560,57 @@ static bool fixup_iopl_exception(struct pt_regs *regs)
return true;
 }
 
+/*
+ * The unprivileged ENQCMD instruction generates #GPs if the
+ * IA32_PASID MSR has not been populated.  If possible, populate
+ * the MSR from a PASID previously allocated to the mm.
+ */
+static bool try_fixup_enqcmd_gp(void)
+{
+#ifdef CONFIG_IOMMU_SVA
+   u32 pasid;
+
+   /*
+* MSR_IA32_PASID is managed using XSAVE.  Directly
+* writing to the MSR is only possible when fpregs
+* are valid and the fpstate is not.  This is
+* guaranteed when handling a userspace exception
+* in *before* interrupts are re-enabled.
+*/
+   lockdep_assert_irqs_disabled();
+
+   /*
+* Hardware without ENQCMD will not generate
+* #GPs that can be fixed up here.
+*/
+   if (!cpu_feature_enabled(X86_FEATURE_ENQCMD))
+   return false;
+
+   pasid = current->mm->pasid;
+
+   /*
+* If the mm has not been allocated a
+* PASID, the #GP can not be fixed up.
+*/
+   if (!pasid_valid(pasid))
+   return false;
+
+   /*
+* Did this thread already have its PASID activated?
+* If so, the #GP must be from something else.
+*/
+   if (current->pasid_activated)
+   return false;
+
+   wrmsrl(MSR_IA32_PASID, pasid | MSR_IA32_PASID_VALID);
+   current->pasid_activated = 1;
+
+   return true;
+#else
+   return false;
+#endif
+}
+
 DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
 {
char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
@@ -567,6 +619,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
unsigned long gp_addr;
int ret;
 
+   if (user_mode(regs) && try_fixup_enqcmd_gp())
+   return;
+
cond_local_irq_enable(regs);
 
if (static_cpu_has(X86_FEATURE_UMIP)) {
-- 
2.35.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu