[v3,59/75] x86/sev-es: Handle MONITOR/MONITORX Events
diff mbox series

Message ID 20200428151725.31091-60-joro@8bytes.org
State New
Headers show
Series
  • x86: SEV-ES Guest Support
Related show

Commit Message

Joerg Roedel April 28, 2020, 3:17 p.m. UTC
From: Tom Lendacky <thomas.lendacky@amd.com>

Implement a handler for #VC exceptions caused by MONITOR and MONITORX
instructions.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
[ jroedel@suse.de: Adapt to #VC handling infrastructure ]
Co-developed-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
---
 arch/x86/kernel/sev-es.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

Comments

Sean Christopherson May 20, 2020, 6:38 a.m. UTC | #1
On Tue, Apr 28, 2020 at 05:17:09PM +0200, Joerg Roedel wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Implement a handler for #VC exceptions caused by MONITOR and MONITORX
> instructions.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> [ jroedel@suse.de: Adapt to #VC handling infrastructure ]
> Co-developed-by: Joerg Roedel <jroedel@suse.de>
> Signed-off-by: Joerg Roedel <jroedel@suse.de>
> ---
>  arch/x86/kernel/sev-es.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c
> index 601554e6360f..1a961714cd1b 100644
> --- a/arch/x86/kernel/sev-es.c
> +++ b/arch/x86/kernel/sev-es.c
> @@ -824,6 +824,22 @@ static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt
>  	return ES_OK;
>  }
>  
> +static enum es_result vc_handle_monitor(struct ghcb *ghcb,
> +					struct es_em_ctxt *ctxt)
> +{
> +	phys_addr_t monitor_pa;
> +	pgd_t *pgd;
> +
> +	pgd = __va(read_cr3_pa());
> +	monitor_pa = vc_slow_virt_to_phys(ghcb, ctxt->regs->ax);
> +
> +	ghcb_set_rax(ghcb, monitor_pa);
> +	ghcb_set_rcx(ghcb, ctxt->regs->cx);
> +	ghcb_set_rdx(ghcb, ctxt->regs->dx);
> +
> +	return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MONITOR, 0, 0);

Why?  If SVM has the same behavior as VMX, the MONITOR will be disarmed on
VM-Enter, i.e. the VMM can't do anything useful for MONITOR/MWAIT.  I
assume that's the case given that KVM emulates MONITOR/MWAIT as NOPs on
SVM.

> +}
> +
>  static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
>  					 struct ghcb *ghcb,
>  					 unsigned long exit_code)
> @@ -860,6 +876,9 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
>  	case SVM_EXIT_WBINVD:
>  		result = vc_handle_wbinvd(ghcb, ctxt);
>  		break;
> +	case SVM_EXIT_MONITOR:
> +		result = vc_handle_monitor(ghcb, ctxt);
> +		break;
>  	case SVM_EXIT_NPF:
>  		result = vc_handle_mmio(ghcb, ctxt);
>  		break;
> -- 
> 2.17.1
>
Joerg Roedel June 11, 2020, 1:10 p.m. UTC | #2
On Tue, May 19, 2020 at 11:38:45PM -0700, Sean Christopherson wrote:
> On Tue, Apr 28, 2020 at 05:17:09PM +0200, Joerg Roedel wrote:
> > +static enum es_result vc_handle_monitor(struct ghcb *ghcb,
> > +					struct es_em_ctxt *ctxt)
> > +{
> > +	phys_addr_t monitor_pa;
> > +	pgd_t *pgd;
> > +
> > +	pgd = __va(read_cr3_pa());
> > +	monitor_pa = vc_slow_virt_to_phys(ghcb, ctxt->regs->ax);
> > +
> > +	ghcb_set_rax(ghcb, monitor_pa);
> > +	ghcb_set_rcx(ghcb, ctxt->regs->cx);
> > +	ghcb_set_rdx(ghcb, ctxt->regs->dx);
> > +
> > +	return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MONITOR, 0, 0);
> 
> Why?  If SVM has the same behavior as VMX, the MONITOR will be disarmed on
> VM-Enter, i.e. the VMM can't do anything useful for MONITOR/MWAIT.  I
> assume that's the case given that KVM emulates MONITOR/MWAIT as NOPs on
> SVM.

Not sure if it is disarmed on VMRUN, but the MONITOR/MWAIT instructions
are part of the GHCB spec, so they are implemented here.


	Joerg
Sean Christopherson June 11, 2020, 5:13 p.m. UTC | #3
On Thu, Jun 11, 2020 at 03:10:45PM +0200, Joerg Roedel wrote:
> On Tue, May 19, 2020 at 11:38:45PM -0700, Sean Christopherson wrote:
> > On Tue, Apr 28, 2020 at 05:17:09PM +0200, Joerg Roedel wrote:
> > > +static enum es_result vc_handle_monitor(struct ghcb *ghcb,
> > > +					struct es_em_ctxt *ctxt)
> > > +{
> > > +	phys_addr_t monitor_pa;
> > > +	pgd_t *pgd;
> > > +
> > > +	pgd = __va(read_cr3_pa());
> > > +	monitor_pa = vc_slow_virt_to_phys(ghcb, ctxt->regs->ax);
> > > +
> > > +	ghcb_set_rax(ghcb, monitor_pa);
> > > +	ghcb_set_rcx(ghcb, ctxt->regs->cx);
> > > +	ghcb_set_rdx(ghcb, ctxt->regs->dx);
> > > +
> > > +	return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MONITOR, 0, 0);
> > 
> > Why?  If SVM has the same behavior as VMX, the MONITOR will be disarmed on
> > VM-Enter, i.e. the VMM can't do anything useful for MONITOR/MWAIT.  I
> > assume that's the case given that KVM emulates MONITOR/MWAIT as NOPs on
> > SVM.
> 
> Not sure if it is disarmed on VMRUN, but the MONITOR/MWAIT instructions
> are part of the GHCB spec, so they are implemented here.

Even if MONITOR/MWAIT somehow works across VMRUN I'm not sure it's something
the guest should enable by default as it leaks GPAs to the untrusted host,
with no benefit to the guest except in specific configurations.  Yeah, the
VMM can muck with page tables to trace guest to the some extent, but the
guest shouldn't be unnecessarily volunteering information to the host.

If MONITOR/MWAIT is effectively a NOP then removing this code is a no
brainer.

Can someone from AMD chime in?
Tom Lendacky June 11, 2020, 7:33 p.m. UTC | #4
On 6/11/20 12:13 PM, Sean Christopherson wrote:
> On Thu, Jun 11, 2020 at 03:10:45PM +0200, Joerg Roedel wrote:
>> On Tue, May 19, 2020 at 11:38:45PM -0700, Sean Christopherson wrote:
>>> On Tue, Apr 28, 2020 at 05:17:09PM +0200, Joerg Roedel wrote:
>>>> +static enum es_result vc_handle_monitor(struct ghcb *ghcb,
>>>> +					struct es_em_ctxt *ctxt)
>>>> +{
>>>> +	phys_addr_t monitor_pa;
>>>> +	pgd_t *pgd;
>>>> +
>>>> +	pgd = __va(read_cr3_pa());
>>>> +	monitor_pa = vc_slow_virt_to_phys(ghcb, ctxt->regs->ax);
>>>> +
>>>> +	ghcb_set_rax(ghcb, monitor_pa);
>>>> +	ghcb_set_rcx(ghcb, ctxt->regs->cx);
>>>> +	ghcb_set_rdx(ghcb, ctxt->regs->dx);
>>>> +
>>>> +	return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MONITOR, 0, 0);
>>>
>>> Why?  If SVM has the same behavior as VMX, the MONITOR will be disarmed on
>>> VM-Enter, i.e. the VMM can't do anything useful for MONITOR/MWAIT.  I
>>> assume that's the case given that KVM emulates MONITOR/MWAIT as NOPs on
>>> SVM.
>>
>> Not sure if it is disarmed on VMRUN, but the MONITOR/MWAIT instructions
>> are part of the GHCB spec, so they are implemented here.
> 
> Even if MONITOR/MWAIT somehow works across VMRUN I'm not sure it's something
> the guest should enable by default as it leaks GPAs to the untrusted host,
> with no benefit to the guest except in specific configurations.  Yeah, the
> VMM can muck with page tables to trace guest to the some extent, but the
> guest shouldn't be unnecessarily volunteering information to the host.
> 
> If MONITOR/MWAIT is effectively a NOP then removing this code is a no
> brainer.
> 
> Can someone from AMD chime in?

I don't think there is any guarantee that MONITOR/MWAIT would work within 
a guest (I'd have to dig some more on that to get a definitive answer, but 
probably not necessary to do). As you say, if KVM emulates it as a NOP, 
there's no sense in exposing the GPA - make it a NOP in the handler. I 
just need to poke some other hypervisor vendors and hear what they have to 
say.

Thanks,
Tom


>
Joerg Roedel June 12, 2020, 9:25 a.m. UTC | #5
On Thu, Jun 11, 2020 at 02:33:12PM -0500, Tom Lendacky wrote:
> I don't think there is any guarantee that MONITOR/MWAIT would work within a
> guest (I'd have to dig some more on that to get a definitive answer, but
> probably not necessary to do). As you say, if KVM emulates it as a NOP,
> there's no sense in exposing the GPA - make it a NOP in the handler. I just
> need to poke some other hypervisor vendors and hear what they have to say.

Okay, makes sense. I made monitor/mwait nops in the patch-set.

Regards,

	Joerg

Patch
diff mbox series

diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c
index 601554e6360f..1a961714cd1b 100644
--- a/arch/x86/kernel/sev-es.c
+++ b/arch/x86/kernel/sev-es.c
@@ -824,6 +824,22 @@  static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt
 	return ES_OK;
 }
 
+static enum es_result vc_handle_monitor(struct ghcb *ghcb,
+					struct es_em_ctxt *ctxt)
+{
+	phys_addr_t monitor_pa;
+	pgd_t *pgd;
+
+	pgd = __va(read_cr3_pa());
+	monitor_pa = vc_slow_virt_to_phys(ghcb, ctxt->regs->ax);
+
+	ghcb_set_rax(ghcb, monitor_pa);
+	ghcb_set_rcx(ghcb, ctxt->regs->cx);
+	ghcb_set_rdx(ghcb, ctxt->regs->dx);
+
+	return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MONITOR, 0, 0);
+}
+
 static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
 					 struct ghcb *ghcb,
 					 unsigned long exit_code)
@@ -860,6 +876,9 @@  static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
 	case SVM_EXIT_WBINVD:
 		result = vc_handle_wbinvd(ghcb, ctxt);
 		break;
+	case SVM_EXIT_MONITOR:
+		result = vc_handle_monitor(ghcb, ctxt);
+		break;
 	case SVM_EXIT_NPF:
 		result = vc_handle_mmio(ghcb, ctxt);
 		break;