x86/sev-es: Use insn_decode_mmio() for MMIO implementation
authorKirill A. Shutemov <kirill@shutemov.name>
Tue, 30 Nov 2021 18:49:33 +0000 (21:49 +0300)
committerDave Hansen <dave.hansen@linux.intel.com>
Tue, 30 Nov 2021 22:53:30 +0000 (14:53 -0800)
Switch SEV implementation to insn_decode_mmio(). The helper is going
to be used by TDX too.

No functional changes.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Tested-by: Joerg Roedel <jroedel@suse.de>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://lkml.kernel.org/r/20211130184933.31005-5-kirill.shutemov@linux.intel.com
arch/x86/kernel/sev.c

index 74f0ec9..09c06c0 100644 (file)
@@ -776,22 +776,6 @@ static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt)
        do_early_exception(ctxt->regs, trapnr);
 }
 
-static long *vc_insn_get_reg(struct es_em_ctxt *ctxt)
-{
-       long *reg_array;
-       int offset;
-
-       reg_array = (long *)ctxt->regs;
-       offset    = insn_get_modrm_reg_off(&ctxt->insn, ctxt->regs);
-
-       if (offset < 0)
-               return NULL;
-
-       offset /= sizeof(long);
-
-       return reg_array + offset;
-}
-
 static long *vc_insn_get_rm(struct es_em_ctxt *ctxt)
 {
        long *reg_array;
@@ -839,76 +823,6 @@ static enum es_result vc_do_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
        return sev_es_ghcb_hv_call(ghcb, true, ctxt, exit_code, exit_info_1, exit_info_2);
 }
 
-static enum es_result vc_handle_mmio_twobyte_ops(struct ghcb *ghcb,
-                                                struct es_em_ctxt *ctxt)
-{
-       struct insn *insn = &ctxt->insn;
-       unsigned int bytes = 0;
-       enum es_result ret;
-       int sign_byte;
-       long *reg_data;
-
-       switch (insn->opcode.bytes[1]) {
-               /* MMIO Read w/ zero-extension */
-       case 0xb6:
-               bytes = 1;
-               fallthrough;
-       case 0xb7:
-               if (!bytes)
-                       bytes = 2;
-
-               ret = vc_do_mmio(ghcb, ctxt, bytes, true);
-               if (ret)
-                       break;
-
-               /* Zero extend based on operand size */
-               reg_data = vc_insn_get_reg(ctxt);
-               if (!reg_data)
-                       return ES_DECODE_FAILED;
-
-               memset(reg_data, 0, insn->opnd_bytes);
-
-               memcpy(reg_data, ghcb->shared_buffer, bytes);
-               break;
-
-               /* MMIO Read w/ sign-extension */
-       case 0xbe:
-               bytes = 1;
-               fallthrough;
-       case 0xbf:
-               if (!bytes)
-                       bytes = 2;
-
-               ret = vc_do_mmio(ghcb, ctxt, bytes, true);
-               if (ret)
-                       break;
-
-               /* Sign extend based on operand size */
-               reg_data = vc_insn_get_reg(ctxt);
-               if (!reg_data)
-                       return ES_DECODE_FAILED;
-
-               if (bytes == 1) {
-                       u8 *val = (u8 *)ghcb->shared_buffer;
-
-                       sign_byte = (*val & 0x80) ? 0xff : 0x00;
-               } else {
-                       u16 *val = (u16 *)ghcb->shared_buffer;
-
-                       sign_byte = (*val & 0x8000) ? 0xff : 0x00;
-               }
-               memset(reg_data, sign_byte, insn->opnd_bytes);
-
-               memcpy(reg_data, ghcb->shared_buffer, bytes);
-               break;
-
-       default:
-               ret = ES_UNSUPPORTED;
-       }
-
-       return ret;
-}
-
 /*
  * The MOVS instruction has two memory operands, which raises the
  * problem that it is not known whether the access to the source or the
@@ -976,83 +890,79 @@ static enum es_result vc_handle_mmio_movs(struct es_em_ctxt *ctxt,
                return ES_RETRY;
 }
 
-static enum es_result vc_handle_mmio(struct ghcb *ghcb,
-                                    struct es_em_ctxt *ctxt)
+static enum es_result vc_handle_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
 {
        struct insn *insn = &ctxt->insn;
        unsigned int bytes = 0;
+       enum mmio_type mmio;
        enum es_result ret;
+       u8 sign_byte;
        long *reg_data;
 
-       switch (insn->opcode.bytes[0]) {
-       /* MMIO Write */
-       case 0x88:
-               bytes = 1;
-               fallthrough;
-       case 0x89:
-               if (!bytes)
-                       bytes = insn->opnd_bytes;
+       mmio = insn_decode_mmio(insn, &bytes);
+       if (mmio == MMIO_DECODE_FAILED)
+               return ES_DECODE_FAILED;
 
-               reg_data = vc_insn_get_reg(ctxt);
+       if (mmio != MMIO_WRITE_IMM && mmio != MMIO_MOVS) {
+               reg_data = insn_get_modrm_reg_ptr(insn, ctxt->regs);
                if (!reg_data)
                        return ES_DECODE_FAILED;
+       }
 
+       switch (mmio) {
+       case MMIO_WRITE:
                memcpy(ghcb->shared_buffer, reg_data, bytes);
-
                ret = vc_do_mmio(ghcb, ctxt, bytes, false);
                break;
-
-       case 0xc6:
-               bytes = 1;
-               fallthrough;
-       case 0xc7:
-               if (!bytes)
-                       bytes = insn->opnd_bytes;
-
+       case MMIO_WRITE_IMM:
                memcpy(ghcb->shared_buffer, insn->immediate1.bytes, bytes);
-
                ret = vc_do_mmio(ghcb, ctxt, bytes, false);
                break;
-
-               /* MMIO Read */
-       case 0x8a:
-               bytes = 1;
-               fallthrough;
-       case 0x8b:
-               if (!bytes)
-                       bytes = insn->opnd_bytes;
-
+       case MMIO_READ:
                ret = vc_do_mmio(ghcb, ctxt, bytes, true);
                if (ret)
                        break;
 
-               reg_data = vc_insn_get_reg(ctxt);
-               if (!reg_data)
-                       return ES_DECODE_FAILED;
-
                /* Zero-extend for 32-bit operation */
                if (bytes == 4)
                        *reg_data = 0;
 
                memcpy(reg_data, ghcb->shared_buffer, bytes);
                break;
+       case MMIO_READ_ZERO_EXTEND:
+               ret = vc_do_mmio(ghcb, ctxt, bytes, true);
+               if (ret)
+                       break;
+
+               /* Zero extend based on operand size */
+               memset(reg_data, 0, insn->opnd_bytes);
+               memcpy(reg_data, ghcb->shared_buffer, bytes);
+               break;
+       case MMIO_READ_SIGN_EXTEND:
+               ret = vc_do_mmio(ghcb, ctxt, bytes, true);
+               if (ret)
+                       break;
 
-               /* MOVS instruction */
-       case 0xa4:
-               bytes = 1;
-               fallthrough;
-       case 0xa5:
-               if (!bytes)
-                       bytes = insn->opnd_bytes;
+               if (bytes == 1) {
+                       u8 *val = (u8 *)ghcb->shared_buffer;
 
-               ret = vc_handle_mmio_movs(ctxt, bytes);
+                       sign_byte = (*val & 0x80) ? 0xff : 0x00;
+               } else {
+                       u16 *val = (u16 *)ghcb->shared_buffer;
+
+                       sign_byte = (*val & 0x8000) ? 0xff : 0x00;
+               }
+
+               /* Sign extend based on operand size */
+               memset(reg_data, sign_byte, insn->opnd_bytes);
+               memcpy(reg_data, ghcb->shared_buffer, bytes);
                break;
-               /* Two-Byte Opcodes */
-       case 0x0f:
-               ret = vc_handle_mmio_twobyte_ops(ghcb, ctxt);
+       case MMIO_MOVS:
+               ret = vc_handle_mmio_movs(ctxt, bytes);
                break;
        default:
                ret = ES_UNSUPPORTED;
+               break;
        }
 
        return ret;