Message ID | 20220209164420.8894-10-varad.gautam@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add #VC exception handling for AMD SEV-ES | expand |
On Wed, Feb 9, 2022 at 8:44 AM Varad Gautam <varad.gautam@suse.com> wrote: > > Using Linux's IOIO #VC processing logic. > > Signed-off-by: Varad Gautam <varad.gautam@suse.com> > --- > lib/x86/amd_sev_vc.c | 146 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 146 insertions(+) > > diff --git a/lib/x86/amd_sev_vc.c b/lib/x86/amd_sev_vc.c > index 401cb29..88c95e1 100644 > --- a/lib/x86/amd_sev_vc.c > +++ b/lib/x86/amd_sev_vc.c > @@ -172,6 +172,149 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) > return ret; > } > > +#define IOIO_TYPE_STR BIT(2) > +#define IOIO_TYPE_IN 1 > +#define IOIO_TYPE_INS (IOIO_TYPE_IN | IOIO_TYPE_STR) > +#define IOIO_TYPE_OUT 0 > +#define IOIO_TYPE_OUTS (IOIO_TYPE_OUT | IOIO_TYPE_STR) > + > +#define IOIO_REP BIT(3) > + > +#define IOIO_ADDR_64 BIT(9) > +#define IOIO_ADDR_32 BIT(8) > +#define IOIO_ADDR_16 BIT(7) > + > +#define IOIO_DATA_32 BIT(6) > +#define IOIO_DATA_16 BIT(5) > +#define IOIO_DATA_8 BIT(4) > + > +#define IOIO_SEG_ES (0 << 10) > +#define IOIO_SEG_DS (3 << 10) > + > +static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo) > +{ > + struct insn *insn = &ctxt->insn; > + *exitinfo = 0; > + > + switch (insn->opcode.bytes[0]) { > + /* INS opcodes */ > + case 0x6c: > + case 0x6d: > + *exitinfo |= IOIO_TYPE_INS; > + *exitinfo |= IOIO_SEG_ES; > + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; > + break; > + > + /* OUTS opcodes */ > + case 0x6e: > + case 0x6f: > + *exitinfo |= IOIO_TYPE_OUTS; > + *exitinfo |= IOIO_SEG_DS; > + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; > + break; > + > + /* IN immediate opcodes */ > + case 0xe4: > + case 0xe5: > + *exitinfo |= IOIO_TYPE_IN; > + *exitinfo |= (u8)insn->immediate.value << 16; > + break; > + > + /* OUT immediate opcodes */ > + case 0xe6: > + case 0xe7: > + *exitinfo |= IOIO_TYPE_OUT; > + *exitinfo |= (u8)insn->immediate.value << 16; > + break; > + > + /* IN register opcodes */ > + case 0xec: > + case 0xed: > + *exitinfo |= IOIO_TYPE_IN; > + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; > + break; > + > + /* OUT register opcodes */ > + case 0xee: > + case 0xef: > + *exitinfo |= IOIO_TYPE_OUT; > + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; > + break; > + > + default: > + return ES_DECODE_FAILED; > + } > + > + switch (insn->opcode.bytes[0]) { > + case 0x6c: > + case 0x6e: > + case 0xe4: > + case 0xe6: > + case 0xec: > + case 0xee: > + /* Single byte opcodes */ > + *exitinfo |= IOIO_DATA_8; > + break; > + default: > + /* Length determined by instruction parsing */ > + *exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16 > + : IOIO_DATA_32; > + } > + switch (insn->addr_bytes) { > + case 2: > + *exitinfo |= IOIO_ADDR_16; > + break; > + case 4: > + *exitinfo |= IOIO_ADDR_32; > + break; > + case 8: > + *exitinfo |= IOIO_ADDR_64; > + break; > + } > + > + if (insn_has_rep_prefix(insn)) > + *exitinfo |= IOIO_REP; > + > + return ES_OK; > +} > + > +static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt) > +{ > + struct ex_regs *regs = ctxt->regs; > + u64 exit_info_1; > + enum es_result ret; > + > + ret = vc_ioio_exitinfo(ctxt, &exit_info_1); > + if (ret != ES_OK) > + return ret; > + > + if (exit_info_1 & IOIO_TYPE_STR) { > + ret = ES_VMM_ERROR; > + } else { > + /* IN/OUT into/from rAX */ > + > + int bits = (exit_info_1 & 0x70) >> 1; > + u64 rax = 0; > + > + if (!(exit_info_1 & IOIO_TYPE_IN)) > + rax = lower_bits(regs->rax, bits); > + > + ghcb_set_rax(ghcb, rax); > + > + ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, exit_info_1, 0); > + if (ret != ES_OK) > + return ret; > + > + if (exit_info_1 & IOIO_TYPE_IN) { > + if (!ghcb_rax_is_valid(ghcb)) > + return ES_VMM_ERROR; > + regs->rax = lower_bits(ghcb->save.rax, bits); > + } > + } > + > + return ret; > +} > + > static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, > struct ghcb *ghcb, > unsigned long exit_code) > @@ -185,6 +328,9 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, > case SVM_EXIT_MSR: > result = vc_handle_msr(ghcb, ctxt); > break; > + case SVM_EXIT_IOIO: > + result = vc_handle_ioio(ghcb, ctxt); > + break; > default: > /* > * Unexpected #VC exception > -- > 2.32.0 > Reviewed-by: Marc Orr <marcorr@google.com>
diff --git a/lib/x86/amd_sev_vc.c b/lib/x86/amd_sev_vc.c index 401cb29..88c95e1 100644 --- a/lib/x86/amd_sev_vc.c +++ b/lib/x86/amd_sev_vc.c @@ -172,6 +172,149 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) return ret; } +#define IOIO_TYPE_STR BIT(2) +#define IOIO_TYPE_IN 1 +#define IOIO_TYPE_INS (IOIO_TYPE_IN | IOIO_TYPE_STR) +#define IOIO_TYPE_OUT 0 +#define IOIO_TYPE_OUTS (IOIO_TYPE_OUT | IOIO_TYPE_STR) + +#define IOIO_REP BIT(3) + +#define IOIO_ADDR_64 BIT(9) +#define IOIO_ADDR_32 BIT(8) +#define IOIO_ADDR_16 BIT(7) + +#define IOIO_DATA_32 BIT(6) +#define IOIO_DATA_16 BIT(5) +#define IOIO_DATA_8 BIT(4) + +#define IOIO_SEG_ES (0 << 10) +#define IOIO_SEG_DS (3 << 10) + +static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo) +{ + struct insn *insn = &ctxt->insn; + *exitinfo = 0; + + switch (insn->opcode.bytes[0]) { + /* INS opcodes */ + case 0x6c: + case 0x6d: + *exitinfo |= IOIO_TYPE_INS; + *exitinfo |= IOIO_SEG_ES; + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; + break; + + /* OUTS opcodes */ + case 0x6e: + case 0x6f: + *exitinfo |= IOIO_TYPE_OUTS; + *exitinfo |= IOIO_SEG_DS; + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; + break; + + /* IN immediate opcodes */ + case 0xe4: + case 0xe5: + *exitinfo |= IOIO_TYPE_IN; + *exitinfo |= (u8)insn->immediate.value << 16; + break; + + /* OUT immediate opcodes */ + case 0xe6: + case 0xe7: + *exitinfo |= IOIO_TYPE_OUT; + *exitinfo |= (u8)insn->immediate.value << 16; + break; + + /* IN register opcodes */ + case 0xec: + case 0xed: + *exitinfo |= IOIO_TYPE_IN; + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; + break; + + /* OUT register opcodes */ + case 0xee: + case 0xef: + *exitinfo |= IOIO_TYPE_OUT; + *exitinfo |= (ctxt->regs->rdx & 0xffff) << 16; + break; + + default: + return ES_DECODE_FAILED; + } + + switch (insn->opcode.bytes[0]) { + case 0x6c: + case 0x6e: + case 0xe4: + case 0xe6: + case 0xec: + case 0xee: + /* Single byte opcodes */ + *exitinfo |= IOIO_DATA_8; + break; + default: + /* Length determined by instruction parsing */ + *exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16 + : IOIO_DATA_32; + } + switch (insn->addr_bytes) { + case 2: + *exitinfo |= IOIO_ADDR_16; + break; + case 4: + *exitinfo |= IOIO_ADDR_32; + break; + case 8: + *exitinfo |= IOIO_ADDR_64; + break; + } + + if (insn_has_rep_prefix(insn)) + *exitinfo |= IOIO_REP; + + return ES_OK; +} + +static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt) +{ + struct ex_regs *regs = ctxt->regs; + u64 exit_info_1; + enum es_result ret; + + ret = vc_ioio_exitinfo(ctxt, &exit_info_1); + if (ret != ES_OK) + return ret; + + if (exit_info_1 & IOIO_TYPE_STR) { + ret = ES_VMM_ERROR; + } else { + /* IN/OUT into/from rAX */ + + int bits = (exit_info_1 & 0x70) >> 1; + u64 rax = 0; + + if (!(exit_info_1 & IOIO_TYPE_IN)) + rax = lower_bits(regs->rax, bits); + + ghcb_set_rax(ghcb, rax); + + ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, exit_info_1, 0); + if (ret != ES_OK) + return ret; + + if (exit_info_1 & IOIO_TYPE_IN) { + if (!ghcb_rax_is_valid(ghcb)) + return ES_VMM_ERROR; + regs->rax = lower_bits(ghcb->save.rax, bits); + } + } + + return ret; +} + static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, struct ghcb *ghcb, unsigned long exit_code) @@ -185,6 +328,9 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, case SVM_EXIT_MSR: result = vc_handle_msr(ghcb, ctxt); break; + case SVM_EXIT_IOIO: + result = vc_handle_ioio(ghcb, ctxt); + break; default: /* * Unexpected #VC exception
Using Linux's IOIO #VC processing logic. Signed-off-by: Varad Gautam <varad.gautam@suse.com> --- lib/x86/amd_sev_vc.c | 146 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+)