diff mbox series

x86/sev-es: Expose __sev_es_ghcb_hv_call() to call ghcb hv call out of sev code

Message ID 20211020062321.3581158-1-ltykernel@gmail.com (mailing list archive)
State Not Applicable
Headers show
Series x86/sev-es: Expose __sev_es_ghcb_hv_call() to call ghcb hv call out of sev code | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Tianyu Lan Oct. 20, 2021, 6:23 a.m. UTC
From: Tianyu Lan <Tianyu.Lan@microsoft.com>


Hyper-V also needs to call ghcb hv call to write/read MSR in Isolation VM.
So expose __sev_es_ghcb_hv_call() to call it in the Hyper-V code.

Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
---
 arch/x86/include/asm/sev.h   | 11 +++++++++++
 arch/x86/kernel/sev-shared.c | 24 +++++++++++++++++++-----
 2 files changed, 30 insertions(+), 5 deletions(-)

Comments

Borislav Petkov Oct. 20, 2021, 9:59 a.m. UTC | #1
On Wed, Oct 20, 2021 at 02:23:16AM -0400, Tianyu Lan wrote:
> From: Tianyu Lan <Tianyu.Lan@microsoft.com>
> 
> 
> Hyper-V also needs to call ghcb hv call to write/read MSR in Isolation VM.
> So expose __sev_es_ghcb_hv_call() to call it in the Hyper-V code.
> 
> Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
> ---
>  arch/x86/include/asm/sev.h   | 11 +++++++++++
>  arch/x86/kernel/sev-shared.c | 24 +++++++++++++++++++-----
>  2 files changed, 30 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
> index fa5cd05d3b5b..295c847c3cd4 100644
> --- a/arch/x86/include/asm/sev.h
> +++ b/arch/x86/include/asm/sev.h
> @@ -81,12 +81,23 @@ static __always_inline void sev_es_nmi_complete(void)
>  		__sev_es_nmi_complete();
>  }
>  extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
> +extern enum es_result __sev_es_ghcb_hv_call(struct ghcb *ghcb,
> +					    struct es_em_ctxt *ctxt,
> +					    u64 exit_code, u64 exit_info_1,
> +					    u64 exit_info_2);

You can do here:

static inline enum es_result
__sev_es_ghcb_hv_call(struct ghcb *ghcb, u64 exit_code, u64 exit_info_1, u64 exit_info_2) { return ES_VMM_ERROR; }

> @@ -137,12 +141,22 @@ 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_2(ghcb, exit_info_2);
>  
> -	sev_es_wr_ghcb_msr(__pa(ghcb));
>  	VMGEXIT();
>  
>  	return verify_exception_info(ghcb, ctxt);
>  }
>  
> +static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
> +					  struct es_em_ctxt *ctxt,
> +					  u64 exit_code, u64 exit_info_1,
> +					  u64 exit_info_2)
> +{
> +	sev_es_wr_ghcb_msr(__pa(ghcb));
> +
> +	return __sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, exit_info_1,
> +				     exit_info_2);
> +}

Well, why does Hyper-V need this thing a bit differently, without the
setting of the GHCB's physical address?

What if another hypervisor does yet another SEV implementation and yet
another HV call needs to be defined?

If stuff is going to be exported to other users, then stuff better be
defined properly so that it is used by multiple hypervisors.
Tianyu Lan Oct. 20, 2021, 12:39 p.m. UTC | #2
On 10/20/2021 5:59 PM, Borislav Petkov wrote:
> On Wed, Oct 20, 2021 at 02:23:16AM -0400, Tianyu Lan wrote:
>> From: Tianyu Lan <Tianyu.Lan@microsoft.com>
>>
>>
>> Hyper-V also needs to call ghcb hv call to write/read MSR in Isolation VM.
>> So expose __sev_es_ghcb_hv_call() to call it in the Hyper-V code.
>>
>> Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
>> ---
>>   arch/x86/include/asm/sev.h   | 11 +++++++++++
>>   arch/x86/kernel/sev-shared.c | 24 +++++++++++++++++++-----
>>   2 files changed, 30 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
>> index fa5cd05d3b5b..295c847c3cd4 100644
>> --- a/arch/x86/include/asm/sev.h
>> +++ b/arch/x86/include/asm/sev.h
>> @@ -81,12 +81,23 @@ static __always_inline void sev_es_nmi_complete(void)
>>   		__sev_es_nmi_complete();
>>   }
>>   extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
>> +extern enum es_result __sev_es_ghcb_hv_call(struct ghcb *ghcb,
>> +					    struct es_em_ctxt *ctxt,
>> +					    u64 exit_code, u64 exit_info_1,
>> +					    u64 exit_info_2);
> 
> You can do here:
> 
> static inline enum es_result
> __sev_es_ghcb_hv_call(struct ghcb *ghcb, u64 exit_code, u64 exit_info_1, u64 exit_info_2) { return ES_VMM_ERROR; }
> 
>> @@ -137,12 +141,22 @@ 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_2(ghcb, exit_info_2);
>>   
>> -	sev_es_wr_ghcb_msr(__pa(ghcb));
>>   	VMGEXIT();
>>   
>>   	return verify_exception_info(ghcb, ctxt);
>>   }
>>   
>> +static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
>> +					  struct es_em_ctxt *ctxt,
>> +					  u64 exit_code, u64 exit_info_1,
>> +					  u64 exit_info_2)
>> +{
>> +	sev_es_wr_ghcb_msr(__pa(ghcb));
>> +
>> +	return __sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, exit_info_1,
>> +				     exit_info_2);
>> +}
> 
> Well, why does Hyper-V need this thing a bit differently, without the
> setting of the GHCB's physical address?

Hyper-V runs paravisor in guest VMPL0 which emulates some functions
(e.g, timer, tsc, serial console and so on) via handling VC exception.
GHCB pages are allocated and set up by the paravisor and report to Linux
guest via MSR register.Hyper-V SEV implementation is unenlightened guest
case which doesn't Linux doesn't handle VC and paravisor in the VMPL0
handle it.


> 
> What if another hypervisor does yet another SEV implementation and yet
> another HV call needs to be defined?

In the early version, these ghcb operations are implemented in Hyper-V 
code and get comments to use existing code in the SEV ES as much as 
possible. So latter versions expose the API to re-use code.

Current two cases: enlightened guest and un-enlightened guest. Tom and
brjesh pushed enlightened case. Hyper-V is un-enlightened case and a
paravisor runs in VMPL0 to handle VC to emulate devices inside VM. GHCB
is allocated and set up by paravisor in the un-enlightened case. The new
__sev_es_ghcb_hv_call() is to handle these two cases.
Borislav Petkov Oct. 20, 2021, 1:39 p.m. UTC | #3
On Wed, Oct 20, 2021 at 08:39:59PM +0800, Tianyu Lan wrote:
> Hyper-V runs paravisor in guest VMPL0 which emulates some functions
> (e.g, timer, tsc, serial console and so on) via handling VC exception.
> GHCB pages are allocated and set up by the paravisor and report to Linux
> guest via MSR register.Hyper-V SEV implementation is unenlightened guest
> case which doesn't Linux doesn't handle VC and paravisor in the VMPL0
> handle it.

Aha, unenlightened.

So why don't you export the original function by doing this (only
partial diff to show intent only):

---
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index f1d513897baf..bfe82f58508f 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -125,7 +125,7 @@ static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt
 	return ES_VMM_ERROR;
 }
 
-static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
+static 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)
@@ -138,7 +138,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_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 by that paravisor which uses a
+	 * different MSR and protocol.
+	 */
+	if (set_ghcb_msr)
+		sev_es_wr_ghcb_msr(__pa(ghcb));
+
 	VMGEXIT();
 
 	return verify_exception_info(ghcb, ctxt);
Tom Lendacky Oct. 20, 2021, 1:56 p.m. UTC | #4
On 10/20/21 8:39 AM, Borislav Petkov wrote:
> On Wed, Oct 20, 2021 at 08:39:59PM +0800, Tianyu Lan wrote:
>> Hyper-V runs paravisor in guest VMPL0 which emulates some functions
>> (e.g, timer, tsc, serial console and so on) via handling VC exception.
>> GHCB pages are allocated and set up by the paravisor and report to Linux
>> guest via MSR register.Hyper-V SEV implementation is unenlightened guest
>> case which doesn't Linux doesn't handle VC and paravisor in the VMPL0
>> handle it.
> 
> Aha, unenlightened.
> 
> So why don't you export the original function by doing this (only
> partial diff to show intent only):
> 
> ---
> diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
> index f1d513897baf..bfe82f58508f 100644
> --- a/arch/x86/kernel/sev-shared.c
> +++ b/arch/x86/kernel/sev-shared.c
> @@ -125,7 +125,7 @@ static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt
>   	return ES_VMM_ERROR;
>   }
>   
> -static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
> +static 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)
> @@ -138,7 +138,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_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 by that paravisor which uses a
> +	 * different MSR and protocol.

Just to clarify the comment, the paravisor uses the same GHCB MSR and GHCB 
protocol, it just can't use __pa() to get the address of the GHCB. So I 
expect that the Hyper-V support sets the address properly before calling 
this function.

Thanks,
Tom

> +	 */
> +	if (set_ghcb_msr)
> +		sev_es_wr_ghcb_msr(__pa(ghcb));
> +
>   	VMGEXIT();
>   
>   	return verify_exception_info(ghcb, ctxt);
> 
>
Tianyu Lan Oct. 20, 2021, 2:23 p.m. UTC | #5
On 10/20/2021 9:56 PM, Tom Lendacky wrote:
> On 10/20/21 8:39 AM, Borislav Petkov wrote:
>> On Wed, Oct 20, 2021 at 08:39:59PM +0800, Tianyu Lan wrote:
>>> Hyper-V runs paravisor in guest VMPL0 which emulates some functions
>>> (e.g, timer, tsc, serial console and so on) via handling VC exception.
>>> GHCB pages are allocated and set up by the paravisor and report to Linux
>>> guest via MSR register.Hyper-V SEV implementation is unenlightened guest
>>> case which doesn't Linux doesn't handle VC and paravisor in the VMPL0
>>> handle it.
>>
>> Aha, unenlightened.
>>
>> So why don't you export the original function by doing this (only
>> partial diff to show intent only):

This follows Joreg's previous comment and I implemented similar version 
in the V! patchset([PATCH 05/13] HV: Add Write/Read MSR registers via 
ghcb page https://lkml.org/lkml/2021/7/28/668).
"Instead, factor out a helper function which contains what Hyper-V needs 
and use that in sev_es_ghcb_hv_call() and Hyper-V code."

https://lkml.org/lkml/2021/8/2/375

>>
>> ---
>> diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
>> index f1d513897baf..bfe82f58508f 100644
>> --- a/arch/x86/kernel/sev-shared.c
>> +++ b/arch/x86/kernel/sev-shared.c
>> @@ -125,7 +125,7 @@ static enum es_result verify_exception_info(struct 
>> ghcb *ghcb, struct es_em_ctxt
>>       return ES_VMM_ERROR;
>>   }
>> -static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
>> +static 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)
>> @@ -138,7 +138,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_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 by that paravisor which uses a
>> +     * different MSR and protocol.
> 
> Just to clarify the comment, the paravisor uses the same GHCB MSR and 
> GHCB protocol, it just can't use __pa() to get the address of the GHCB. 
> So I expect that the Hyper-V support sets the address properly before 
> calling this function.
> 
> Thanks,
> Tom
> 
>> +     */
>> +    if (set_ghcb_msr)
>> +        sev_es_wr_ghcb_msr(__pa(ghcb));
>> +
>>       VMGEXIT();
>>       return verify_exception_info(ghcb, ctxt);
>>
>>
Borislav Petkov Oct. 20, 2021, 2:39 p.m. UTC | #6
On Wed, Oct 20, 2021 at 10:23:06PM +0800, Tianyu Lan wrote:
> This follows Joreg's previous comment and I implemented similar version in
> the V! patchset([PATCH 05/13] HV: Add Write/Read MSR registers via ghcb page
> https://lkml.org/lkml/2021/7/28/668).
> "Instead, factor out a helper function which contains what Hyper-V needs and
> use that in sev_es_ghcb_hv_call() and Hyper-V code."
> 
> https://lkml.org/lkml/2021/8/2/375

If you wanna point to mails on a mailing list, you simply do

https://lore.kernel.org/r/<Message-id>

No need to use some random, unreliable web pages.

As to Joerg's suggestion, in the version I'm seeing, you're checking the
*context* - and the one you sent today, avoids the __pa(ghcb) MSR write.

So which is it?

Because your current version will look at the context too, see

	return verify_exception_info(ghcb, ctxt);

at the end of the function.

So is the issue what Tom said that "the paravisor uses the same GHCB MSR
and GHCB protocol, it just can't use __pa() to get the address of the
GHCB."?

If that is the case and the only thing you want is to avoid the GHCB PA
write, then, in the future, we might drop that MSR write altogether on
the enlightened Linux guests too and then the same function will be used
by your paravisor and the Linux guest.

So please explain in detail what exactly you want to avoid from
sev_es_ghcb_hv_call()'s current version and why.

As I said before, I don't want to export any random details of the SEV
implementation in the kernel without any justification for it.

Thx.
Tianyu Lan Oct. 20, 2021, 3:09 p.m. UTC | #7
On 10/20/2021 10:39 PM, Borislav Petkov wrote:
> On Wed, Oct 20, 2021 at 10:23:06PM +0800, Tianyu Lan wrote:
>> This follows Joreg's previous comment and I implemented similar version in
>> the V! patchset([PATCH 05/13] HV: Add Write/Read MSR registers via ghcb page
>> https://lkml.org/lkml/2021/7/28/668).
>> "Instead, factor out a helper function which contains what Hyper-V needs and
>> use that in sev_es_ghcb_hv_call() and Hyper-V code."
>>
>> https://lkml.org/lkml/2021/8/2/375
> 
> If you wanna point to mails on a mailing list, you simply do
> 
> https://lore.kernel.org/r/<Message-id>
> 
> No need to use some random, unreliable web pages.

OK. Thanks for suggestion.

> 
> As to Joerg's suggestion, in the version I'm seeing, you're checking the
> *context* - and the one you sent today, avoids the __pa(ghcb) MSR write.
> 
> So which is it?
> 
> Because your current version will look at the context too, see
> 
> 	return verify_exception_info(ghcb, ctxt);
> 
> at the end of the function.
Both old and new patches are to avoid setting GHCB page address via MSR.
Paravisor is in charge of doing that and un-enlightened guest should not 
change it. The old one was in the patchset v1 "x86/Hyper-V: Add Hyper-V
Isolation VM support". The patch I sent today is based on your clean up 
patch and for review first. It should be in patchset "x86/Hyper-V: Add 
Hyper-V Isolation VM support."

> 
> So is the issue what Tom said that "the paravisor uses the same GHCB MSR
> and GHCB protocol, it just can't use __pa() to get the address of the
> GHCB."?

Yes, hyper-V enables vTOM in the CVM and GHCB page PA reported by 
paravisor contains vTOM bit. We need to use memremap() to map ghcb page 
before accessing GHCB page. __pa() doesn't work for PA with vTOM bit.
Otherwise, guest should not set GHCB page address and avoid conflict 
with paravisor.

> 
> If that is the case and the only thing you want is to avoid the GHCB PA
> write, then, in the future, we might drop that MSR write altogether on
> the enlightened Linux guests too and then the same function will be used
> by your paravisor and the Linux guest.

Yes, this is the target of the patch. Can we put the change in the 
Hyper-V patchset? Other patch has been fully reviewed.

Thanks.
Borislav Petkov Oct. 20, 2021, 4:24 p.m. UTC | #8
On Wed, Oct 20, 2021 at 11:09:03PM +0800, Tianyu Lan wrote:
> Yes, this is the target of the patch. Can we put the change in the
> Hyper-V patchset?

If you're asking about this version:

https://lore.kernel.org/r/20211020062321.3581158-1-ltykernel@gmail.com

then, no. I'd prefer if you did this:

https://lore.kernel.org/r/YXAcGtxe08XiHBFH@zn.tnic

for reasons which I already explained.

Thx.
Tianyu Lan Oct. 21, 2021, 3:42 p.m. UTC | #9
On 10/21/2021 12:24 AM, Borislav Petkov wrote:
> On Wed, Oct 20, 2021 at 11:09:03PM +0800, Tianyu Lan wrote:
>> Yes, this is the target of the patch. Can we put the change in the
>> Hyper-V patchset?
> 
> If you're asking about this version:
> 
> https://lore.kernel.org/r/20211020062321.3581158-1-ltykernel@gmail.com
> 
> then, no. I'd prefer if you did this:
> 
> https://lore.kernel.org/r/YXAcGtxe08XiHBFH@zn.tnic
> 
> for reasons which I already explained.
> 

Thanks for your suggestion. I just sent out v8 version according to your 
guide. Please have a look.


Thanks.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index fa5cd05d3b5b..295c847c3cd4 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -81,12 +81,23 @@  static __always_inline void sev_es_nmi_complete(void)
 		__sev_es_nmi_complete();
 }
 extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
+extern enum es_result __sev_es_ghcb_hv_call(struct ghcb *ghcb,
+					    struct es_em_ctxt *ctxt,
+					    u64 exit_code, u64 exit_info_1,
+					    u64 exit_info_2);
 #else
 static inline void sev_es_ist_enter(struct pt_regs *regs) { }
 static inline void sev_es_ist_exit(void) { }
 static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
 static inline void sev_es_nmi_complete(void) { }
 static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
+static inline enum es_result
+__sev_es_ghcb_hv_call(struct ghcb *ghcb,
+		      u64 exit_code, u64 exit_info_1,
+		      u64 exit_info_2)
+{
+	return ES_VMM_ERROR;
+}
 #endif
 
 #endif
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index ea9abd69237e..08c97cb057fa 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -124,10 +124,14 @@  static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt
 	return ES_VMM_ERROR;
 }
 
-static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
-					  struct es_em_ctxt *ctxt,
-					  u64 exit_code, u64 exit_info_1,
-					  u64 exit_info_2)
+/*
+ * __sev_es_ghcb_hv_call() is also used in the other platform code(e.g
+ * Hyper-V).
+ */
+enum es_result __sev_es_ghcb_hv_call(struct ghcb *ghcb,
+				     struct es_em_ctxt *ctxt,
+				     u64 exit_code, u64 exit_info_1,
+				     u64 exit_info_2)
 {
 	/* Fill in protocol and format specifiers */
 	ghcb->protocol_version = GHCB_PROTOCOL_MAX;
@@ -137,12 +141,22 @@  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_2(ghcb, exit_info_2);
 
-	sev_es_wr_ghcb_msr(__pa(ghcb));
 	VMGEXIT();
 
 	return verify_exception_info(ghcb, ctxt);
 }
 
+static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
+					  struct es_em_ctxt *ctxt,
+					  u64 exit_code, u64 exit_info_1,
+					  u64 exit_info_2)
+{
+	sev_es_wr_ghcb_msr(__pa(ghcb));
+
+	return __sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, exit_info_1,
+				     exit_info_2);
+}
+
 /*
  * Boot VC Handler - This is the first VC handler during boot, there is no GHCB
  * page yet, so it only supports the MSR based communication with the