diff mbox series

[Part1,RFC,v2,13/20] x86/sev: Register GHCB memory when SEV-SNP is active

Message ID 20210430121616.2295-14-brijesh.singh@amd.com (mailing list archive)
State New, archived
Headers show
Series Add AMD Secure Nested Paging (SEV-SNP) Guest Support | expand

Commit Message

Brijesh Singh April 30, 2021, 12:16 p.m. UTC
The SEV-SNP guest is required to perform GHCB GPA registration. This is
because the hypervisor may prefer that a guest use a consistent and/or
specific GPA for the GHCB associated with a vCPU. For more information,
see the GHCB specification section GHCB GPA Registration.

During the boot, init_ghcb() allocates a per-cpu GHCB page. On very first
VC exception, the exception handler switch to using the per-cpu GHCB page
allocated during the init_ghcb(). The GHCB page must be registered in
the current vcpu context.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/kernel/sev.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

Comments

Borislav Petkov May 25, 2021, 11:11 a.m. UTC | #1
On Fri, Apr 30, 2021 at 07:16:09AM -0500, Brijesh Singh wrote:
> The SEV-SNP guest is required to perform GHCB GPA registration. This is
> because the hypervisor may prefer that a guest use a consistent and/or
> specific GPA for the GHCB associated with a vCPU. For more information,
> see the GHCB specification section GHCB GPA Registration.
> 
> During the boot, init_ghcb() allocates a per-cpu GHCB page. On very first
> VC exception, the exception handler switch to using the per-cpu GHCB page
> allocated during the init_ghcb(). The GHCB page must be registered in
> the current vcpu context.
> 
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  arch/x86/kernel/sev.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
> index 8c8c939a1754..e6819f170ec4 100644
> --- a/arch/x86/kernel/sev.c
> +++ b/arch/x86/kernel/sev.c
> @@ -88,6 +88,13 @@ struct sev_es_runtime_data {
>  	 * is currently unsupported in SEV-ES guests.
>  	 */
>  	unsigned long dr7;
> +
> +	/*
> +	 * SEV-SNP requires that the GHCB must be registered before using it.
> +	 * The flag below will indicate whether the GHCB is registered, if its
> +	 * not registered then sev_es_get_ghcb() will perform the registration.
> +	 */
> +	bool snp_ghcb_registered;
>  };
>  
>  struct ghcb_state {
> @@ -100,6 +107,9 @@ DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
>  /* Needed in vc_early_forward_exception */
>  void do_early_exception(struct pt_regs *regs, int trapnr);
>  
> +/* Defined in sev-shared.c */
> +static void snp_register_ghcb(unsigned long paddr);

Can we get rid of those forward declarations pls? Due to sev-shared.c
this file is starting to spawn those and that's ugly.

Either through a code reorg or even defining a sev-internal.h header
which contains all those so that they don't pollute the code?

Thx.

> +
>  static void __init setup_vc_stacks(int cpu)
>  {
>  	struct sev_es_runtime_data *data;
> @@ -218,6 +228,12 @@ static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
>  		data->ghcb_active = true;
>  	}
>  
> +	/* SEV-SNP guest requires that GHCB must be registered before using it. */
> +	if (sev_snp_active() && !data->snp_ghcb_registered) {
> +		snp_register_ghcb(__pa(ghcb));
> +		data->snp_ghcb_registered = true;
> +	}

More missed review from last time:

"This needs to be set to true in the function itself, in the success
case."

Can you please be more careful and go through all review comments so
that I don't have to do the same work twice?

Thx.
Brijesh Singh May 25, 2021, 2:28 p.m. UTC | #2
On 5/25/21 6:11 AM, Borislav Petkov wrote:
> On Fri, Apr 30, 2021 at 07:16:09AM -0500, Brijesh Singh wrote:
>> The SEV-SNP guest is required to perform GHCB GPA registration. This is
>> because the hypervisor may prefer that a guest use a consistent and/or
>> specific GPA for the GHCB associated with a vCPU. For more information,
>> see the GHCB specification section GHCB GPA Registration.
>>
>> During the boot, init_ghcb() allocates a per-cpu GHCB page. On very first
>> VC exception, the exception handler switch to using the per-cpu GHCB page
>> allocated during the init_ghcb(). The GHCB page must be registered in
>> the current vcpu context.
>>
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>  arch/x86/kernel/sev.c | 21 +++++++++++++++++++++
>>  1 file changed, 21 insertions(+)
>>
>> diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
>> index 8c8c939a1754..e6819f170ec4 100644
>> --- a/arch/x86/kernel/sev.c
>> +++ b/arch/x86/kernel/sev.c
>> @@ -88,6 +88,13 @@ struct sev_es_runtime_data {
>>  	 * is currently unsupported in SEV-ES guests.
>>  	 */
>>  	unsigned long dr7;
>> +
>> +	/*
>> +	 * SEV-SNP requires that the GHCB must be registered before using it.
>> +	 * The flag below will indicate whether the GHCB is registered, if its
>> +	 * not registered then sev_es_get_ghcb() will perform the registration.
>> +	 */
>> +	bool snp_ghcb_registered;
>>  };
>>  
>>  struct ghcb_state {
>> @@ -100,6 +107,9 @@ DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
>>  /* Needed in vc_early_forward_exception */
>>  void do_early_exception(struct pt_regs *regs, int trapnr);
>>  
>> +/* Defined in sev-shared.c */
>> +static void snp_register_ghcb(unsigned long paddr);
> Can we get rid of those forward declarations pls? Due to sev-shared.c
> this file is starting to spawn those and that's ugly.
>
> Either through a code reorg or even defining a sev-internal.h header
> which contains all those so that they don't pollute the code?

Okay, I will see what I can do to avoid the forward declarations.


> Thx.
>
>> +
>>  static void __init setup_vc_stacks(int cpu)
>>  {
>>  	struct sev_es_runtime_data *data;
>> @@ -218,6 +228,12 @@ static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
>>  		data->ghcb_active = true;
>>  	}
>>  
>> +	/* SEV-SNP guest requires that GHCB must be registered before using it. */
>> +	if (sev_snp_active() && !data->snp_ghcb_registered) {
>> +		snp_register_ghcb(__pa(ghcb));
>> +		data->snp_ghcb_registered = true;
>> +	}
> More missed review from last time:
>
> "This needs to be set to true in the function itself, in the success
> case."
>
> Can you please be more careful and go through all review comments so
> that I don't have to do the same work twice?

I am not ignoring your valuable feedback; I am sorry if I came across
like that.

In this particular case, the snp_register_ghcb() is shared between the
decompress and main kernel. The variable data->snp_ghcb_registered is
not visible in the decompressed path, so I choose not to set it to true
inside the function itself.


> Thx.
>
Borislav Petkov May 25, 2021, 2:35 p.m. UTC | #3
On Tue, May 25, 2021 at 09:28:14AM -0500, Brijesh Singh wrote:
> I am not ignoring your valuable feedback; I am sorry if I came across
> like that.

Sure, no worries, but you have to say something when you don't agree
with the feedback. How am I supposed to know?

> In this particular case, the snp_register_ghcb() is shared between the
> decompress and main kernel. The variable data->snp_ghcb_registered is
> not visible in the decompressed path,

Why is it not visible?
Brijesh Singh May 25, 2021, 2:47 p.m. UTC | #4
On 5/25/21 9:35 AM, Borislav Petkov wrote:
>> In this particular case, the snp_register_ghcb() is shared between the
>> decompress and main kernel. The variable data->snp_ghcb_registered is
>> not visible in the decompressed path,
> Why is it not visible?

Maybe I should have said, its not applicable in the decompressed path.

The snp_ghcb_register is defined in the per-CPU structure, and used in
the per-CPU #VC handler. We don't have the per-CPU #VC handler in the
decompression code path.

Please see the arch/x86/kernel/sev.c

/* #VC handler runtime per-CPU data */

struct sev_es_runtime_data {

 ...

 ...

 bool snp_ghcb_registered;

}
Borislav Petkov May 26, 2021, 9:57 a.m. UTC | #5
On Tue, May 25, 2021 at 09:47:24AM -0500, Brijesh Singh wrote:
> Maybe I should have said, its not applicable in the decompressed path.

Aha, ok. How's that, ontop of yours:

---
diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 07b9529d7d95..c9dd98b9dcdf 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -208,7 +208,7 @@ static bool early_setup_sev_es(void)
 
 	/* SEV-SNP guest requires the GHCB GPA must be registered */
 	if (sev_snp_enabled())
-		snp_register_ghcb(__pa(&boot_ghcb_page));
+		snp_register_ghcb_early(__pa(&boot_ghcb_page));
 
 	return true;
 }
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index 37a23c524f8c..7200f44d6b6b 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -81,7 +81,7 @@ static bool ghcb_get_hv_features(void)
 	return true;
 }
 
-static void snp_register_ghcb(unsigned long paddr)
+static void snp_register_ghcb_early(unsigned long paddr)
 {
 	unsigned long pfn = paddr >> PAGE_SHIFT;
 	u64 val;
diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 5544557d9fb6..144c20479cae 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -108,7 +108,18 @@ DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
 void do_early_exception(struct pt_regs *regs, int trapnr);
 
 /* Defined in sev-shared.c */
-static void snp_register_ghcb(unsigned long paddr);
+static void snp_register_ghcb_early(unsigned long paddr);
+
+static void snp_register_ghcb(struct sev_es_runtime_data *data,
+			      unsigned long paddr)
+{
+	if (data->snp_ghcb_registered)
+		return;
+
+	snp_register_ghcb_early(paddr);
+
+	data->snp_ghcb_registered = true;
+}
 
 static void __init setup_vc_stacks(int cpu)
 {
@@ -239,10 +250,8 @@ static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
 	}
 
 	/* SEV-SNP guest requires that GHCB must be registered before using it. */
-	if (sev_snp_active() && !data->snp_ghcb_registered) {
-		snp_register_ghcb(__pa(ghcb));
-		data->snp_ghcb_registered = true;
-	}
+	if (sev_snp_active())
+		snp_register_ghcb(data, __pa(ghcb));
 
 	return ghcb;
 }
@@ -681,7 +690,7 @@ static bool __init sev_es_setup_ghcb(void)
 
 	/* SEV-SNP guest requires that GHCB GPA must be registered */
 	if (sev_snp_active())
-		snp_register_ghcb(__pa(&boot_ghcb_page));
+		snp_register_ghcb_early(__pa(&boot_ghcb_page));
 
 	return true;
 }
Brijesh Singh May 26, 2021, 1:23 p.m. UTC | #6
On 5/26/21 4:57 AM, Borislav Petkov wrote:
> On Tue, May 25, 2021 at 09:47:24AM -0500, Brijesh Singh wrote:
>> Maybe I should have said, its not applicable in the decompressed path.
> Aha, ok. How's that, ontop of yours:

Sure, its fine with me. I will apply this change.

-Birjesh


> ---
> diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
> index 07b9529d7d95..c9dd98b9dcdf 100644
> --- a/arch/x86/boot/compressed/sev.c
> +++ b/arch/x86/boot/compressed/sev.c
> @@ -208,7 +208,7 @@ static bool early_setup_sev_es(void)
>  
>  	/* SEV-SNP guest requires the GHCB GPA must be registered */
>  	if (sev_snp_enabled())
> -		snp_register_ghcb(__pa(&boot_ghcb_page));
> +		snp_register_ghcb_early(__pa(&boot_ghcb_page));
>  
>  	return true;
>  }
> diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
> index 37a23c524f8c..7200f44d6b6b 100644
> --- a/arch/x86/kernel/sev-shared.c
> +++ b/arch/x86/kernel/sev-shared.c
> @@ -81,7 +81,7 @@ static bool ghcb_get_hv_features(void)
>  	return true;
>  }
>  
> -static void snp_register_ghcb(unsigned long paddr)
> +static void snp_register_ghcb_early(unsigned long paddr)
>  {
>  	unsigned long pfn = paddr >> PAGE_SHIFT;
>  	u64 val;
> diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
> index 5544557d9fb6..144c20479cae 100644
> --- a/arch/x86/kernel/sev.c
> +++ b/arch/x86/kernel/sev.c
> @@ -108,7 +108,18 @@ DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
>  void do_early_exception(struct pt_regs *regs, int trapnr);
>  
>  /* Defined in sev-shared.c */
> -static void snp_register_ghcb(unsigned long paddr);
> +static void snp_register_ghcb_early(unsigned long paddr);
> +
> +static void snp_register_ghcb(struct sev_es_runtime_data *data,
> +			      unsigned long paddr)
> +{
> +	if (data->snp_ghcb_registered)
> +		return;
> +
> +	snp_register_ghcb_early(paddr);
> +
> +	data->snp_ghcb_registered = true;
> +}
>  
>  static void __init setup_vc_stacks(int cpu)
>  {
> @@ -239,10 +250,8 @@ static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
>  	}
>  
>  	/* SEV-SNP guest requires that GHCB must be registered before using it. */
> -	if (sev_snp_active() && !data->snp_ghcb_registered) {
> -		snp_register_ghcb(__pa(ghcb));
> -		data->snp_ghcb_registered = true;
> -	}
> +	if (sev_snp_active())
> +		snp_register_ghcb(data, __pa(ghcb));
>  
>  	return ghcb;
>  }
> @@ -681,7 +690,7 @@ static bool __init sev_es_setup_ghcb(void)
>  
>  	/* SEV-SNP guest requires that GHCB GPA must be registered */
>  	if (sev_snp_active())
> -		snp_register_ghcb(__pa(&boot_ghcb_page));
> +		snp_register_ghcb_early(__pa(&boot_ghcb_page));
>  
>  	return true;
>  }
>
diff mbox series

Patch

diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 8c8c939a1754..e6819f170ec4 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -88,6 +88,13 @@  struct sev_es_runtime_data {
 	 * is currently unsupported in SEV-ES guests.
 	 */
 	unsigned long dr7;
+
+	/*
+	 * SEV-SNP requires that the GHCB must be registered before using it.
+	 * The flag below will indicate whether the GHCB is registered, if its
+	 * not registered then sev_es_get_ghcb() will perform the registration.
+	 */
+	bool snp_ghcb_registered;
 };
 
 struct ghcb_state {
@@ -100,6 +107,9 @@  DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
 /* Needed in vc_early_forward_exception */
 void do_early_exception(struct pt_regs *regs, int trapnr);
 
+/* Defined in sev-shared.c */
+static void snp_register_ghcb(unsigned long paddr);
+
 static void __init setup_vc_stacks(int cpu)
 {
 	struct sev_es_runtime_data *data;
@@ -218,6 +228,12 @@  static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
 		data->ghcb_active = true;
 	}
 
+	/* SEV-SNP guest requires that GHCB must be registered before using it. */
+	if (sev_snp_active() && !data->snp_ghcb_registered) {
+		snp_register_ghcb(__pa(ghcb));
+		data->snp_ghcb_registered = true;
+	}
+
 	return ghcb;
 }
 
@@ -622,6 +638,10 @@  static bool __init sev_es_setup_ghcb(void)
 	/* Alright - Make the boot-ghcb public */
 	boot_ghcb = &boot_ghcb_page;
 
+	/* SEV-SNP guest requires that GHCB GPA must be registered */
+	if (sev_snp_active())
+		snp_register_ghcb(__pa(&boot_ghcb_page));
+
 	return true;
 }
 
@@ -711,6 +731,7 @@  static void __init init_ghcb(int cpu)
 
 	data->ghcb_active = false;
 	data->backup_ghcb_active = false;
+	data->snp_ghcb_registered = false;
 }
 
 void __init sev_es_init_vc_handling(void)