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: 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
This commit is contained in:
parent
70a81f99e4
commit
c494eb366d
@ -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;
|
||||
|
||||
reg_data = vc_insn_get_reg(ctxt);
|
||||
if (!reg_data)
|
||||
mmio = insn_decode_mmio(insn, &bytes);
|
||||
if (mmio == MMIO_DECODE_FAILED)
|
||||
return ES_DECODE_FAILED;
|
||||
|
||||
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;
|
||||
|
||||
/* MOVS instruction */
|
||||
case 0xa4:
|
||||
bytes = 1;
|
||||
fallthrough;
|
||||
case 0xa5:
|
||||
if (!bytes)
|
||||
bytes = insn->opnd_bytes;
|
||||
|
||||
ret = vc_handle_mmio_movs(ctxt, bytes);
|
||||
case MMIO_READ_ZERO_EXTEND:
|
||||
ret = vc_do_mmio(ghcb, ctxt, bytes, true);
|
||||
if (ret)
|
||||
break;
|
||||
/* Two-Byte Opcodes */
|
||||
case 0x0f:
|
||||
ret = vc_handle_mmio_twobyte_ops(ghcb, ctxt);
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Sign extend based on operand size */
|
||||
memset(reg_data, sign_byte, insn->opnd_bytes);
|
||||
memcpy(reg_data, ghcb->shared_buffer, bytes);
|
||||
break;
|
||||
case MMIO_MOVS:
|
||||
ret = vc_handle_mmio_movs(ctxt, bytes);
|
||||
break;
|
||||
default:
|
||||
ret = ES_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user