Skip to content

Commit fa6af69

Browse files
Fenghua Yusuryasaimadhu
authored andcommitted
x86/traps: Demand-populate PASID MSR via #GP
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 <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Reviewed-by: Tony Luck <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a3d29e8 commit fa6af69

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

arch/x86/kernel/traps.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <linux/io.h>
4040
#include <linux/hardirq.h>
4141
#include <linux/atomic.h>
42+
#include <linux/ioasid.h>
4243

4344
#include <asm/stacktrace.h>
4445
#include <asm/processor.h>
@@ -559,6 +560,57 @@ static bool fixup_iopl_exception(struct pt_regs *regs)
559560
return true;
560561
}
561562

563+
/*
564+
* The unprivileged ENQCMD instruction generates #GPs if the
565+
* IA32_PASID MSR has not been populated. If possible, populate
566+
* the MSR from a PASID previously allocated to the mm.
567+
*/
568+
static bool try_fixup_enqcmd_gp(void)
569+
{
570+
#ifdef CONFIG_IOMMU_SVA
571+
u32 pasid;
572+
573+
/*
574+
* MSR_IA32_PASID is managed using XSAVE. Directly
575+
* writing to the MSR is only possible when fpregs
576+
* are valid and the fpstate is not. This is
577+
* guaranteed when handling a userspace exception
578+
* in *before* interrupts are re-enabled.
579+
*/
580+
lockdep_assert_irqs_disabled();
581+
582+
/*
583+
* Hardware without ENQCMD will not generate
584+
* #GPs that can be fixed up here.
585+
*/
586+
if (!cpu_feature_enabled(X86_FEATURE_ENQCMD))
587+
return false;
588+
589+
pasid = current->mm->pasid;
590+
591+
/*
592+
* If the mm has not been allocated a
593+
* PASID, the #GP can not be fixed up.
594+
*/
595+
if (!pasid_valid(pasid))
596+
return false;
597+
598+
/*
599+
* Did this thread already have its PASID activated?
600+
* If so, the #GP must be from something else.
601+
*/
602+
if (current->pasid_activated)
603+
return false;
604+
605+
wrmsrl(MSR_IA32_PASID, pasid | MSR_IA32_PASID_VALID);
606+
current->pasid_activated = 1;
607+
608+
return true;
609+
#else
610+
return false;
611+
#endif
612+
}
613+
562614
DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
563615
{
564616
char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
@@ -567,6 +619,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
567619
unsigned long gp_addr;
568620
int ret;
569621

622+
if (user_mode(regs) && try_fixup_enqcmd_gp())
623+
return;
624+
570625
cond_local_irq_enable(regs);
571626

572627
if (static_cpu_has(X86_FEATURE_UMIP)) {

0 commit comments

Comments
 (0)