Commit c494eb36 authored by Kirill A. Shutemov's avatar Kirill A. Shutemov Committed by Dave Hansen

x86/sev-es: Use insn_decode_mmio() for MMIO implementation

Switch SEV implementation to insn_decode_mmio(). The helper is going
to be used by TDX too.

No functional changes.
Signed-off-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: default avatarAndi Kleen <ak@linux.intel.com>
Reviewed-by: default avatarTony Luck <tony.luck@intel.com>
Tested-by: default avatarJoerg Roedel <jroedel@suse.de>
Acked-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Link: https://lkml.kernel.org/r/20211130184933.31005-5-kirill.shutemov@linux.intel.com
parent 70a81f99
...@@ -776,22 +776,6 @@ static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt) ...@@ -776,22 +776,6 @@ static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt)
do_early_exception(ctxt->regs, trapnr); 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) static long *vc_insn_get_rm(struct es_em_ctxt *ctxt)
{ {
long *reg_array; long *reg_array;
...@@ -839,76 +823,6 @@ static enum es_result vc_do_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt, ...@@ -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); 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 * The MOVS instruction has two memory operands, which raises the
* problem that it is not known whether the access to the source or 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, ...@@ -976,83 +890,79 @@ static enum es_result vc_handle_mmio_movs(struct es_em_ctxt *ctxt,
return ES_RETRY; return ES_RETRY;
} }
static enum es_result vc_handle_mmio(struct ghcb *ghcb, static enum es_result vc_handle_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
struct es_em_ctxt *ctxt)
{ {
struct insn *insn = &ctxt->insn; struct insn *insn = &ctxt->insn;
unsigned int bytes = 0; unsigned int bytes = 0;
enum mmio_type mmio;
enum es_result ret; enum es_result ret;
u8 sign_byte;
long *reg_data; long *reg_data;
switch (insn->opcode.bytes[0]) { mmio = insn_decode_mmio(insn, &bytes);
/* MMIO Write */ if (mmio == MMIO_DECODE_FAILED)
case 0x88: return ES_DECODE_FAILED;
bytes = 1;
fallthrough;
case 0x89:
if (!bytes)
bytes = insn->opnd_bytes;
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) if (!reg_data)
return ES_DECODE_FAILED; return ES_DECODE_FAILED;
}
switch (mmio) {
case MMIO_WRITE:
memcpy(ghcb->shared_buffer, reg_data, bytes); memcpy(ghcb->shared_buffer, reg_data, bytes);
ret = vc_do_mmio(ghcb, ctxt, bytes, false); ret = vc_do_mmio(ghcb, ctxt, bytes, false);
break; break;
case MMIO_WRITE_IMM:
case 0xc6:
bytes = 1;
fallthrough;
case 0xc7:
if (!bytes)
bytes = insn->opnd_bytes;
memcpy(ghcb->shared_buffer, insn->immediate1.bytes, bytes); memcpy(ghcb->shared_buffer, insn->immediate1.bytes, bytes);
ret = vc_do_mmio(ghcb, ctxt, bytes, false); ret = vc_do_mmio(ghcb, ctxt, bytes, false);
break; break;
case MMIO_READ:
/* MMIO Read */
case 0x8a:
bytes = 1;
fallthrough;
case 0x8b:
if (!bytes)
bytes = insn->opnd_bytes;
ret = vc_do_mmio(ghcb, ctxt, bytes, true); ret = vc_do_mmio(ghcb, ctxt, bytes, true);
if (ret) if (ret)
break; break;
reg_data = vc_insn_get_reg(ctxt);
if (!reg_data)
return ES_DECODE_FAILED;
/* Zero-extend for 32-bit operation */ /* Zero-extend for 32-bit operation */
if (bytes == 4) if (bytes == 4)
*reg_data = 0; *reg_data = 0;
memcpy(reg_data, ghcb->shared_buffer, bytes); memcpy(reg_data, ghcb->shared_buffer, bytes);
break; 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 */ if (bytes == 1) {
case 0xa4: u8 *val = (u8 *)ghcb->shared_buffer;
bytes = 1;
fallthrough;
case 0xa5:
if (!bytes)
bytes = insn->opnd_bytes;
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; break;
/* Two-Byte Opcodes */ case MMIO_MOVS:
case 0x0f: ret = vc_handle_mmio_movs(ctxt, bytes);
ret = vc_handle_mmio_twobyte_ops(ghcb, ctxt);
break; break;
default: default:
ret = ES_UNSUPPORTED; ret = ES_UNSUPPORTED;
break;
} }
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment