The ENQCMD implicitly accesses the PASID_MSR to fill in the pasid field
of the descriptor being submitted to an accelerator. But there is no
precise (and stable across kernel changes) point at which the PASID_MSR
is updated from the value for one task to the next.

Kernel code that uses accelerators must always use the ENQCMDS instruction
which does not access the PASID_MSR.

Check for use of the ENQCMD instruction in the kernel and warn on its
usage.

Checking the invalid instruction is a relatively new use of objtool and
I'm open to feedback about the approach.

Signed-off-by: Fenghua Yu <fenghua...@intel.com>
Reviewed-by: Tony Luck <tony.l...@intel.com>
---
 tools/objtool/arch/x86/decode.c      | 10 +++++++++-
 tools/objtool/check.c                | 20 ++++++++++++++++++++
 tools/objtool/include/objtool/arch.h |  1 +
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index bc821056aba9..e63b44ba3bd4 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -110,7 +110,7 @@ int arch_decode_instruction(const struct elf *elf, const 
struct section *sec,
 {
        struct insn insn;
        int x86_64, ret;
-       unsigned char op1, op2,
+       unsigned char op1, op2, op3,
                      rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
                      modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
                      sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0;
@@ -137,6 +137,7 @@ int arch_decode_instruction(const struct elf *elf, const 
struct section *sec,
 
        op1 = insn.opcode.bytes[0];
        op2 = insn.opcode.bytes[1];
+       op3 = insn.opcode.bytes[2];
 
        if (insn.rex_prefix.nbytes) {
                rex = insn.rex_prefix.bytes[0];
@@ -489,6 +490,13 @@ int arch_decode_instruction(const struct elf *elf, const 
struct section *sec,
                        /* nopl/nopw */
                        *type = INSN_NOP;
 
+               } else if (op2 == 0x38 && op3 == 0xf8) {
+                       if (insn.prefixes.nbytes == 1 &&
+                           insn.prefixes.bytes[0] == 0xf2) {
+                               /* enqcmd */
+                               *type = INSN_ENQCMD;
+                       }
+
                } else if (op2 == 0xa0 || op2 == 0xa8) {
 
                        /* push fs/gs */
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e5947fbb9e7a..91d13521d9d6 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3133,6 +3133,21 @@ static int validate_reachable_instructions(struct 
objtool_file *file)
        return 0;
 }
 
+static int validate_enqcmd(struct objtool_file *file)
+{
+       struct instruction *insn;
+
+       for_each_insn(file, insn) {
+               if (insn->type == INSN_ENQCMD) {
+                       WARN_FUNC("enqcmd instruction", insn->sec,
+                                 insn->offset);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 int check(struct objtool_file *file)
 {
        int ret, warnings = 0;
@@ -3147,6 +3162,11 @@ int check(struct objtool_file *file)
        if (list_empty(&file->insn_list))
                goto out;
 
+       ret = validate_enqcmd(file);
+       if (ret < 0)
+               goto out;
+       warnings += ret;
+
        if (vmlinux && !validate_dup) {
                ret = validate_vmlinux_functions(file);
                if (ret < 0)
diff --git a/tools/objtool/include/objtool/arch.h 
b/tools/objtool/include/objtool/arch.h
index 062bb6e9b865..5147c0762b49 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -26,6 +26,7 @@ enum insn_type {
        INSN_CLAC,
        INSN_STD,
        INSN_CLD,
+       INSN_ENQCMD,
        INSN_OTHER,
 };
 
-- 
2.33.0

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

Reply via email to