mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
x86/sev: Expose sev_es_ghcb_hv_call() for use by HyperV
Hyper-V needs to issue the GHCB HV call in order to read/write MSRs in Isolation VMs. For that, expose sev_es_ghcb_hv_call(). The Hyper-V Isolation VMs are unenlightened guests and run a paravisor at VMPL0 for communicating. GHCB pages are being allocated and set up by that paravisor. Linux gets the GHCB page's physical address via MSR_AMD64_SEV_ES_GHCB from the paravisor and should not change it. Add a @set_ghcb_msr parameter to sev_es_ghcb_hv_call() to control whether the function should set the GHCB's address prior to the call or not and export that function for use by HyperV. [ bp: - Massage commit message - add a struct ghcb forward declaration to fix randconfig builds. ] Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Link: https://lore.kernel.org/r/20211025122116.264793-6-ltykernel@gmail.com
This commit is contained in:
parent
ce47d0c00f
commit
007faec014
@ -53,6 +53,7 @@ static inline u64 lower_bits(u64 val, unsigned int bits)
|
|||||||
|
|
||||||
struct real_mode_header;
|
struct real_mode_header;
|
||||||
enum stack_type;
|
enum stack_type;
|
||||||
|
struct ghcb;
|
||||||
|
|
||||||
/* Early IDT entry points for #VC handler */
|
/* Early IDT entry points for #VC handler */
|
||||||
extern void vc_no_ghcb(void);
|
extern void vc_no_ghcb(void);
|
||||||
@ -81,6 +82,11 @@ static __always_inline void sev_es_nmi_complete(void)
|
|||||||
__sev_es_nmi_complete();
|
__sev_es_nmi_complete();
|
||||||
}
|
}
|
||||||
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
|
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
|
||||||
|
extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
|
||||||
|
bool set_ghcb_msr,
|
||||||
|
struct es_em_ctxt *ctxt,
|
||||||
|
u64 exit_code, u64 exit_info_1,
|
||||||
|
u64 exit_info_2);
|
||||||
#else
|
#else
|
||||||
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
||||||
static inline void sev_es_ist_exit(void) { }
|
static inline void sev_es_ist_exit(void) { }
|
||||||
|
@ -125,10 +125,9 @@ static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt
|
|||||||
return ES_VMM_ERROR;
|
return ES_VMM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
|
enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr,
|
||||||
struct es_em_ctxt *ctxt,
|
struct es_em_ctxt *ctxt, u64 exit_code,
|
||||||
u64 exit_code, u64 exit_info_1,
|
u64 exit_info_1, u64 exit_info_2)
|
||||||
u64 exit_info_2)
|
|
||||||
{
|
{
|
||||||
/* Fill in protocol and format specifiers */
|
/* Fill in protocol and format specifiers */
|
||||||
ghcb->protocol_version = GHCB_PROTOCOL_MAX;
|
ghcb->protocol_version = GHCB_PROTOCOL_MAX;
|
||||||
@ -138,7 +137,14 @@ static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
|
|||||||
ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
|
ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
|
||||||
ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
|
ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
|
||||||
|
|
||||||
sev_es_wr_ghcb_msr(__pa(ghcb));
|
/*
|
||||||
|
* Hyper-V unenlightened guests use a paravisor for communicating and
|
||||||
|
* GHCB pages are being allocated and set up by that paravisor. Linux
|
||||||
|
* should not change the GHCB page's physical address.
|
||||||
|
*/
|
||||||
|
if (set_ghcb_msr)
|
||||||
|
sev_es_wr_ghcb_msr(__pa(ghcb));
|
||||||
|
|
||||||
VMGEXIT();
|
VMGEXIT();
|
||||||
|
|
||||||
return verify_exception_info(ghcb, ctxt);
|
return verify_exception_info(ghcb, ctxt);
|
||||||
@ -418,7 +424,7 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
|
|||||||
*/
|
*/
|
||||||
sw_scratch = __pa(ghcb) + offsetof(struct ghcb, shared_buffer);
|
sw_scratch = __pa(ghcb) + offsetof(struct ghcb, shared_buffer);
|
||||||
ghcb_set_sw_scratch(ghcb, sw_scratch);
|
ghcb_set_sw_scratch(ghcb, sw_scratch);
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO,
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_IOIO,
|
||||||
exit_info_1, exit_info_2);
|
exit_info_1, exit_info_2);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
@ -460,7 +466,8 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
|
|||||||
|
|
||||||
ghcb_set_rax(ghcb, rax);
|
ghcb_set_rax(ghcb, rax);
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, exit_info_1, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt,
|
||||||
|
SVM_EXIT_IOIO, exit_info_1, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -491,7 +498,7 @@ static enum es_result vc_handle_cpuid(struct ghcb *ghcb,
|
|||||||
/* xgetbv will cause #GP - use reset value for xcr0 */
|
/* xgetbv will cause #GP - use reset value for xcr0 */
|
||||||
ghcb_set_xcr0(ghcb, 1);
|
ghcb_set_xcr0(ghcb, 1);
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_CPUID, 0, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -516,7 +523,7 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,
|
|||||||
bool rdtscp = (exit_code == SVM_EXIT_RDTSCP);
|
bool rdtscp = (exit_code == SVM_EXIT_RDTSCP);
|
||||||
enum es_result ret;
|
enum es_result ret;
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, 0, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, exit_code, 0, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -648,7 +648,8 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
|
|||||||
ghcb_set_rdx(ghcb, regs->dx);
|
ghcb_set_rdx(ghcb, regs->dx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, exit_info_1, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_MSR,
|
||||||
|
exit_info_1, 0);
|
||||||
|
|
||||||
if ((ret == ES_OK) && (!exit_info_1)) {
|
if ((ret == ES_OK) && (!exit_info_1)) {
|
||||||
regs->ax = ghcb->save.rax;
|
regs->ax = ghcb->save.rax;
|
||||||
@ -867,7 +868,7 @@ static enum es_result vc_do_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
|
|||||||
|
|
||||||
ghcb_set_sw_scratch(ghcb, ghcb_pa + offsetof(struct ghcb, shared_buffer));
|
ghcb_set_sw_scratch(ghcb, ghcb_pa + offsetof(struct ghcb, shared_buffer));
|
||||||
|
|
||||||
return sev_es_ghcb_hv_call(ghcb, 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,
|
static enum es_result vc_handle_mmio_twobyte_ops(struct ghcb *ghcb,
|
||||||
@ -1117,7 +1118,7 @@ static enum es_result vc_handle_dr7_write(struct ghcb *ghcb,
|
|||||||
|
|
||||||
/* Using a value of 0 for ExitInfo1 means RAX holds the value */
|
/* Using a value of 0 for ExitInfo1 means RAX holds the value */
|
||||||
ghcb_set_rax(ghcb, val);
|
ghcb_set_rax(ghcb, val);
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WRITE_DR7, 0, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_WRITE_DR7, 0, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1147,7 +1148,7 @@ static enum es_result vc_handle_dr7_read(struct ghcb *ghcb,
|
|||||||
static enum es_result vc_handle_wbinvd(struct ghcb *ghcb,
|
static enum es_result vc_handle_wbinvd(struct ghcb *ghcb,
|
||||||
struct es_em_ctxt *ctxt)
|
struct es_em_ctxt *ctxt)
|
||||||
{
|
{
|
||||||
return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WBINVD, 0, 0);
|
return sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_WBINVD, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
|
static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
|
||||||
@ -1156,7 +1157,7 @@ static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt
|
|||||||
|
|
||||||
ghcb_set_rcx(ghcb, ctxt->regs->cx);
|
ghcb_set_rcx(ghcb, ctxt->regs->cx);
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_RDPMC, 0, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_RDPMC, 0, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1197,7 +1198,7 @@ static enum es_result vc_handle_vmmcall(struct ghcb *ghcb,
|
|||||||
if (x86_platform.hyper.sev_es_hcall_prepare)
|
if (x86_platform.hyper.sev_es_hcall_prepare)
|
||||||
x86_platform.hyper.sev_es_hcall_prepare(ghcb, ctxt->regs);
|
x86_platform.hyper.sev_es_hcall_prepare(ghcb, ctxt->regs);
|
||||||
|
|
||||||
ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_VMMCALL, 0, 0);
|
ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_VMMCALL, 0, 0);
|
||||||
if (ret != ES_OK)
|
if (ret != ES_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user