diff mbox series

[Part1,RFC,v2,10/20] x86/sev: Add a helper for the PVALIDATE instruction

Message ID 20210430121616.2295-11-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
An SNP-active guest uses the PVALIDATE instruction to validate or
rescind the validation of a guest page’s RMP entry. Upon completion,
a return code is stored in EAX and rFLAGS bits are set based on the
return code. If the instruction completed successfully, the CF
indicates if the content of the RMP were changed or not.

See AMD APM Volume 3 for additional details.

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

Comments

Brijesh Singh April 30, 2021, 1:05 p.m. UTC | #1
On 4/30/21 7:16 AM, Brijesh Singh wrote:
> An SNP-active guest uses the PVALIDATE instruction to validate or
> rescind the validation of a guest page’s RMP entry. Upon completion,
> a return code is stored in EAX and rFLAGS bits are set based on the
> return code. If the instruction completed successfully, the CF
> indicates if the content of the RMP were changed or not.
>
> See AMD APM Volume 3 for additional details.
>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  arch/x86/include/asm/sev.h | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
>
> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
> index 134a7c9d91b6..48f911a229ba 100644
> --- a/arch/x86/include/asm/sev.h
> +++ b/arch/x86/include/asm/sev.h
> @@ -59,6 +59,16 @@ extern void vc_no_ghcb(void);
>  extern void vc_boot_ghcb(void);
>  extern bool handle_vc_boot_ghcb(struct pt_regs *regs);
>  
> +/* Return code of pvalidate */
> +#define PVALIDATE_SUCCESS		0
> +#define PVALIDATE_FAIL_INPUT		1
> +#define PVALIDATE_FAIL_SIZEMISMATCH	6
> +#define PVALIDATE_FAIL_NOUPDATE		255 /* Software defined (when rFlags.CF = 1) */
> +
> +/* RMP page size */
> +#define RMP_PG_SIZE_2M			1
> +#define RMP_PG_SIZE_4K			0
> +
>  #ifdef CONFIG_AMD_MEM_ENCRYPT
>  extern struct static_key_false sev_es_enable_key;
>  extern void __sev_es_ist_enter(struct pt_regs *regs);
> @@ -81,12 +91,29 @@ static __always_inline void sev_es_nmi_complete(void)
>  		__sev_es_nmi_complete();
>  }
>  extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
> +static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
> +{
> +	unsigned long flags;
> +	int rc = 0;
> +
> +	asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
> +		     CC_SET(c)
> +		     : CC_OUT(c) (flags), "=a"(rc)
> +		     : "a"(vaddr), "c"(rmp_psize), "d"(validate)
> +		     : "memory", "cc");
> +
> +	if (flags & X86_EFLAGS_CF)
> +		return PVALIDATE_FAIL_NOUPDATE;
> +
> +	return rc;
> +}


While generating the patches for part1, I accidentally picked the wrong
version of this patch.

The pvalidate() looks like this

static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool
validate)
{
    bool no_rmpupdate;
    int rc;

    asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
             CC_SET(c)
             : CC_OUT(c) (no_rmpupdate), "=a"(rc)
             : "a"(vaddr), "c"(rmp_psize), "d"(validate)
             : "memory", "cc");

    if (no_rmpupdate)
        return PVALIDATE_FAIL_NOUPDATE;

    return rc;
}

https://github.com/AMDESE/linux/commit/581316923efb4e4833722962b02a0c892aed9505#diff-a9a713d4f58a64b6640506f689940cb077dcb0a3705da0c024145c0c857d6c38


>  #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 int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
>  #endif
>  
>  #endif
Borislav Petkov May 20, 2021, 5:32 p.m. UTC | #2
On Fri, Apr 30, 2021 at 08:05:36AM -0500, Brijesh Singh wrote:
> While generating the patches for part1, I accidentally picked the wrong
> version of this patch.

Adding the right one...

> Author: Brijesh Singh <brijesh.singh@amd.com>
> Date:   Thu Apr 29 16:45:36 2021 -0500
> 
>     x86/sev: Add a helper for the PVALIDATE instruction
>     
>     An SNP-active guest uses the PVALIDATE instruction to validate or
>     rescind the validation of a guest page’s RMP entry. Upon completion,
>     a return code is stored in EAX and rFLAGS bits are set based on the
>     return code. If the instruction completed successfully, the CF
>     indicates if the content of the RMP were changed or not.
> 
>     See AMD APM Volume 3 for additional details.
> 
>     Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> 
> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
> index 134a7c9d91b6..be67d9c70267 100644
> --- a/arch/x86/include/asm/sev.h
> +++ b/arch/x86/include/asm/sev.h
> @@ -59,6 +59,16 @@ extern void vc_no_ghcb(void);
>  extern void vc_boot_ghcb(void);
>  extern bool handle_vc_boot_ghcb(struct pt_regs *regs);
>  
> +/* Return code of pvalidate */
> +#define PVALIDATE_SUCCESS		0
> +#define PVALIDATE_FAIL_INPUT		1
> +#define PVALIDATE_FAIL_SIZEMISMATCH	6

Those are unused. Remove them pls.

> +#define PVALIDATE_FAIL_NOUPDATE		255 /* Software defined (when rFlags.CF = 1) */

Put the comment above the define pls.

> +
> +/* RMP page size */
> +#define RMP_PG_SIZE_2M			1
> +#define RMP_PG_SIZE_4K			0

Add those when you need them - I see

[PATCH Part2 RFC v2 06/37] x86/sev: Add RMP entry lookup helpers

is moving them to some generic header. No need to add them to this patch
here.

>  #ifdef CONFIG_AMD_MEM_ENCRYPT
>  extern struct static_key_false sev_es_enable_key;
>  extern void __sev_es_ist_enter(struct pt_regs *regs);
> @@ -81,12 +91,29 @@ static __always_inline void sev_es_nmi_complete(void)
>  		__sev_es_nmi_complete();
>  }
>  extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
> +static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
> +{
> +	bool no_rmpupdate;
> +	int rc;

Adding this for the mail archives when we find this mail again in the
future so that I don't have to do binutils git archeology again:

Enablement for the "pvalidate" mnemonic is in binutils commit
646cc3e0109e ("Add AMD znver3 processor support"). :-)

Please put over the opcode bytes line:

	/* "pvalidate" mnemonic support in binutils 2.36 and newer */

> +
> +	asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
> +		     CC_SET(c)
> +		     : CC_OUT(c) (no_rmpupdate), "=a"(rc)
> +		     : "a"(vaddr), "c"(rmp_psize), "d"(validate)
> +		     : "memory", "cc");
> +
> +	if (no_rmpupdate)
> +		return PVALIDATE_FAIL_NOUPDATE;
> +
> +	return rc;
> +}

Thx.
Brijesh Singh May 20, 2021, 5:44 p.m. UTC | #3
On 5/20/21 12:32 PM, Borislav Petkov wrote:
> On Fri, Apr 30, 2021 at 08:05:36AM -0500, Brijesh Singh wrote:
>> While generating the patches for part1, I accidentally picked the wrong
>> version of this patch.
> Adding the right one...
>
>> Author: Brijesh Singh <brijesh.singh@amd.com>
>> Date:   Thu Apr 29 16:45:36 2021 -0500
>>
>>     x86/sev: Add a helper for the PVALIDATE instruction
>>     
>>     An SNP-active guest uses the PVALIDATE instruction to validate or
>>     rescind the validation of a guest page’s RMP entry. Upon completion,
>>     a return code is stored in EAX and rFLAGS bits are set based on the
>>     return code. If the instruction completed successfully, the CF
>>     indicates if the content of the RMP were changed or not.
>>
>>     See AMD APM Volume 3 for additional details.
>>
>>     Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>>
>> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
>> index 134a7c9d91b6..be67d9c70267 100644
>> --- a/arch/x86/include/asm/sev.h
>> +++ b/arch/x86/include/asm/sev.h
>> @@ -59,6 +59,16 @@ extern void vc_no_ghcb(void);
>>  extern void vc_boot_ghcb(void);
>>  extern bool handle_vc_boot_ghcb(struct pt_regs *regs);
>>  
>> +/* Return code of pvalidate */
>> +#define PVALIDATE_SUCCESS		0
>> +#define PVALIDATE_FAIL_INPUT		1
>> +#define PVALIDATE_FAIL_SIZEMISMATCH	6
> Those are unused. Remove them pls.

Hmm, I use the SIZEMISMATCH later in the patches. Since I was
introducing the pvalidate in separate patch so decided to define all the
return code.


>> +#define PVALIDATE_FAIL_NOUPDATE		255 /* Software defined (when rFlags.CF = 1) */
> Put the comment above the define pls.

Noted.


>
>> +
>> +/* RMP page size */
>> +#define RMP_PG_SIZE_2M			1
>> +#define RMP_PG_SIZE_4K			0
> Add those when you need them - I see
>
> [PATCH Part2 RFC v2 06/37] x86/sev: Add RMP entry lookup helpers
>
> is moving them to some generic header. No need to add them to this patch
> here.

Noted.


>>  #ifdef CONFIG_AMD_MEM_ENCRYPT
>>  extern struct static_key_false sev_es_enable_key;
>>  extern void __sev_es_ist_enter(struct pt_regs *regs);
>> @@ -81,12 +91,29 @@ static __always_inline void sev_es_nmi_complete(void)
>>  		__sev_es_nmi_complete();
>>  }
>>  extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
>> +static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
>> +{
>> +	bool no_rmpupdate;
>> +	int rc;
> Adding this for the mail archives when we find this mail again in the
> future so that I don't have to do binutils git archeology again:
>
> Enablement for the "pvalidate" mnemonic is in binutils commit
> 646cc3e0109e ("Add AMD znver3 processor support"). :-)
>
> Please put over the opcode bytes line:

Noted.


> 	/* "pvalidate" mnemonic support in binutils 2.36 and newer */
>
>> +
>> +	asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
>> +		     CC_SET(c)
>> +		     : CC_OUT(c) (no_rmpupdate), "=a"(rc)
>> +		     : "a"(vaddr), "c"(rmp_psize), "d"(validate)
>> +		     : "memory", "cc");
>> +
>> +	if (no_rmpupdate)
>> +		return PVALIDATE_FAIL_NOUPDATE;
>> +
>> +	return rc;
>> +}
> Thx.
>
Borislav Petkov May 20, 2021, 5:51 p.m. UTC | #4
On Thu, May 20, 2021 at 12:44:50PM -0500, Brijesh Singh wrote:
> Hmm, I use the SIZEMISMATCH later in the patches.

You do, where? Maybe I don't see it.

> Since I was introducing the pvalidate in separate patch so decided to
> define all the return code.

You can define them in a comment so that it is clear what PVALIDATE
returns but not as defines when they're unused.

Thx.
Brijesh Singh May 20, 2021, 5:57 p.m. UTC | #5
On 5/20/21 12:51 PM, Borislav Petkov wrote:
> On Thu, May 20, 2021 at 12:44:50PM -0500, Brijesh Singh wrote:
>> Hmm, I use the SIZEMISMATCH later in the patches.
> You do, where? Maybe I don't see it.

Sorry, my bad. Currently all the pages are pre-validated, and guest
kernel uses 4K in the page state change VMGEXIT. So, we should *not* see
the SIZEMISMATCH. This will happen when we move to lazy validation. I
mixed up with OVMF in which I validate pages as a large. I will drop the
macro.


>
>> Since I was introducing the pvalidate in separate patch so decided to
>> define all the return code.
> You can define them in a comment so that it is clear what PVALIDATE
> returns but not as defines when they're unused.

Got it.


>
> Thx.
>
diff mbox series

Patch

diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 134a7c9d91b6..48f911a229ba 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -59,6 +59,16 @@  extern void vc_no_ghcb(void);
 extern void vc_boot_ghcb(void);
 extern bool handle_vc_boot_ghcb(struct pt_regs *regs);
 
+/* Return code of pvalidate */
+#define PVALIDATE_SUCCESS		0
+#define PVALIDATE_FAIL_INPUT		1
+#define PVALIDATE_FAIL_SIZEMISMATCH	6
+#define PVALIDATE_FAIL_NOUPDATE		255 /* Software defined (when rFlags.CF = 1) */
+
+/* RMP page size */
+#define RMP_PG_SIZE_2M			1
+#define RMP_PG_SIZE_4K			0
+
 #ifdef CONFIG_AMD_MEM_ENCRYPT
 extern struct static_key_false sev_es_enable_key;
 extern void __sev_es_ist_enter(struct pt_regs *regs);
@@ -81,12 +91,29 @@  static __always_inline void sev_es_nmi_complete(void)
 		__sev_es_nmi_complete();
 }
 extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
+static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
+		     CC_SET(c)
+		     : CC_OUT(c) (flags), "=a"(rc)
+		     : "a"(vaddr), "c"(rmp_psize), "d"(validate)
+		     : "memory", "cc");
+
+	if (flags & X86_EFLAGS_CF)
+		return PVALIDATE_FAIL_NOUPDATE;
+
+	return rc;
+}
 #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 int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
 #endif
 
 #endif