Commit 6c0f74d6 authored by Brijesh Singh's avatar Brijesh Singh Committed by Borislav Petkov

x86/sev: Define the Linux-specific guest termination reasons

The GHCB specification defines the reason code for reason set 0. The
reason codes defined in the set 0 do not cover all possible causes for a
guest to request termination.

The reason sets 1 to 255 are reserved for the vendor-specific codes.
Reserve the reason set 1 for the Linux guest. Define the error codes for
reason set 1 so that one can have meaningful termination reasons and thus
better guest failure diagnosis.

While at it, change sev_es_terminate() to accept a reason set parameter.

  [ bp: Massage commit message. ]
Signed-off-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarVenu Busireddy <venu.busireddy@oracle.com>
Link: https://lore.kernel.org/r/20220307213356.2797205-11-brijesh.singh@amd.com
parent f742b90e
...@@ -119,7 +119,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt, ...@@ -119,7 +119,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
static bool early_setup_sev_es(void) static bool early_setup_sev_es(void)
{ {
if (!sev_es_negotiate_protocol()) if (!sev_es_negotiate_protocol())
sev_es_terminate(GHCB_SEV_ES_PROT_UNSUPPORTED); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_PROT_UNSUPPORTED);
if (set_page_decrypted((unsigned long)&boot_ghcb_page)) if (set_page_decrypted((unsigned long)&boot_ghcb_page))
return false; return false;
...@@ -172,7 +172,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code) ...@@ -172,7 +172,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
enum es_result result; enum es_result result;
if (!boot_ghcb && !early_setup_sev_es()) if (!boot_ghcb && !early_setup_sev_es())
sev_es_terminate(GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
vc_ghcb_invalidate(boot_ghcb); vc_ghcb_invalidate(boot_ghcb);
result = vc_init_em_ctxt(&ctxt, regs, exit_code); result = vc_init_em_ctxt(&ctxt, regs, exit_code);
...@@ -199,7 +199,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code) ...@@ -199,7 +199,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
if (result == ES_OK) if (result == ES_OK)
vc_finish_insn(&ctxt); vc_finish_insn(&ctxt);
else if (result != ES_RETRY) else if (result != ES_RETRY)
sev_es_terminate(GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
} }
void sev_enable(struct boot_params *bp) void sev_enable(struct boot_params *bp)
......
...@@ -73,9 +73,17 @@ ...@@ -73,9 +73,17 @@
/* GHCBData[23:16] */ \ /* GHCBData[23:16] */ \
((((u64)reason_val) & 0xff) << 16)) ((((u64)reason_val) & 0xff) << 16))
/* Error codes from reason set 0 */
#define SEV_TERM_SET_GEN 0
#define GHCB_SEV_ES_GEN_REQ 0 #define GHCB_SEV_ES_GEN_REQ 0
#define GHCB_SEV_ES_PROT_UNSUPPORTED 1 #define GHCB_SEV_ES_PROT_UNSUPPORTED 1
/* Linux-specific reason codes (used with reason set 1) */
#define SEV_TERM_SET_LINUX 1
#define GHCB_TERM_REGISTER 0 /* GHCB GPA registration failure */
#define GHCB_TERM_PSC 1 /* Page State Change failure */
#define GHCB_TERM_PVALIDATE 2 /* Pvalidate failure */
#define GHCB_RESP_CODE(v) ((v) & GHCB_MSR_INFO_MASK) #define GHCB_RESP_CODE(v) ((v) & GHCB_MSR_INFO_MASK)
/* /*
......
...@@ -24,15 +24,12 @@ static bool __init sev_es_check_cpu_features(void) ...@@ -24,15 +24,12 @@ static bool __init sev_es_check_cpu_features(void)
return true; return true;
} }
static void __noreturn sev_es_terminate(unsigned int reason) static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason)
{ {
u64 val = GHCB_MSR_TERM_REQ; u64 val = GHCB_MSR_TERM_REQ;
/* /* Tell the hypervisor what went wrong. */
* Tell the hypervisor what went wrong - only reason-set 0 is val |= GHCB_SEV_TERM_REASON(set, reason);
* currently supported.
*/
val |= GHCB_SEV_TERM_REASON(0, reason);
/* Request Guest Termination from Hypvervisor */ /* Request Guest Termination from Hypvervisor */
sev_es_wr_ghcb_msr(val); sev_es_wr_ghcb_msr(val);
...@@ -221,7 +218,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) ...@@ -221,7 +218,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
fail: fail:
/* Terminate the guest */ /* Terminate the guest */
sev_es_terminate(GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
} }
static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt, static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
......
...@@ -1337,7 +1337,7 @@ DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication) ...@@ -1337,7 +1337,7 @@ DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication)
show_regs(regs); show_regs(regs);
/* Ask hypervisor to sev_es_terminate */ /* Ask hypervisor to sev_es_terminate */
sev_es_terminate(GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
/* If that fails and we get here - just panic */ /* If that fails and we get here - just panic */
panic("Returned from Terminate-Request to Hypervisor\n"); panic("Returned from Terminate-Request to Hypervisor\n");
...@@ -1385,7 +1385,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs) ...@@ -1385,7 +1385,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
/* Do initial setup or terminate the guest */ /* Do initial setup or terminate the guest */
if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb())) if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb()))
sev_es_terminate(GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
vc_ghcb_invalidate(boot_ghcb); vc_ghcb_invalidate(boot_ghcb);
......
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