Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions arch/x86/boot/compressed/sev.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
if (result != ES_OK)
goto finish;

result = vc_check_opcode_bytes(&ctxt, exit_code);
if (result != ES_OK)
goto finish;

switch (exit_code) {
case SVM_EXIT_RDTSC:
case SVM_EXIT_RDTSCP:
Expand Down
105 changes: 103 additions & 2 deletions arch/x86/kernel/sev-shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
*/

#ifndef __BOOT_COMPRESSED
#define error(v) pr_err(v)
#define has_cpuflag(f) boot_cpu_has(f)
#define error(v) pr_err(v)
#define has_cpuflag(f) boot_cpu_has(f)
#define sev_printk(fmt, ...) printk(fmt, ##__VA_ARGS__)
#define sev_printk_rtl(fmt, ...) printk_ratelimited(fmt, ##__VA_ARGS__)
#else
#define sev_printk(fmt, ...)
#define sev_printk_rtl(fmt, ...)
#endif

static bool __init sev_es_check_cpu_features(void)
Expand Down Expand Up @@ -144,12 +149,17 @@ static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
{
unsigned int fn = lower_bits(regs->ax, 32);
u16 opcode = *(unsigned short *)regs->ip;
unsigned long val;

/* Only CPUID is supported via MSR protocol */
if (exit_code != SVM_EXIT_CPUID)
goto fail;

/* Is it really a CPUID insn? */
if (opcode != 0xa20f)
goto fail;

sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EAX));
VMGEXIT();
val = sev_es_rd_ghcb_msr();
Expand Down Expand Up @@ -527,3 +537,94 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,

return ES_OK;
}

static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
unsigned long exit_code)
{
unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
u8 modrm = ctxt->insn.modrm.value;

switch (exit_code) {

case SVM_EXIT_IOIO:
case SVM_EXIT_NPF:
/* handled separately */
return ES_OK;

case SVM_EXIT_CPUID:
if (opcode == 0xa20f)
return ES_OK;
break;

case SVM_EXIT_INVD:
if (opcode == 0x080f)
return ES_OK;
break;

case SVM_EXIT_MONITOR:
/* MONITOR and MONITORX instructions generate the same error code */
if (opcode == 0x010f && (modrm == 0xc8 || modrm == 0xfa))
return ES_OK;
break;

case SVM_EXIT_MWAIT:
/* MWAIT and MWAITX instructions generate the same error code */
if (opcode == 0x010f && (modrm == 0xc9 || modrm == 0xfb))
return ES_OK;
break;

case SVM_EXIT_MSR:
/* RDMSR */
if (opcode == 0x320f ||
/* WRMSR */
opcode == 0x300f)
return ES_OK;
break;

case SVM_EXIT_RDPMC:
if (opcode == 0x330f)
return ES_OK;
break;

case SVM_EXIT_RDTSC:
if (opcode == 0x310f)
return ES_OK;
break;

case SVM_EXIT_RDTSCP:
if (opcode == 0x010f && modrm == 0xf9)
return ES_OK;
break;

case SVM_EXIT_READ_DR7:
if (opcode == 0x210f &&
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
return ES_OK;
break;

case SVM_EXIT_VMMCALL:
if (opcode == 0x010f && modrm == 0xd9)
return ES_OK;

break;

case SVM_EXIT_WRITE_DR7:
if (opcode == 0x230f &&
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
return ES_OK;
break;

case SVM_EXIT_WBINVD:
if (opcode == 0x90f)
return ES_OK;
break;

default:
break;
}

sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
opcode, exit_code, ctxt->regs->ip);

return ES_UNSUPPORTED;
}
5 changes: 4 additions & 1 deletion arch/x86/kernel/sev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
struct ghcb *ghcb,
unsigned long exit_code)
{
enum es_result result;
enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);

if (result != ES_OK)
return result;

switch (exit_code) {
case SVM_EXIT_READ_DR7:
Expand Down