diff mbox series

[RFC,Part1,04/13] x86/sev-snp: define page state change VMGEXIT structure

Message ID 20210324164424.28124-5-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 March 24, 2021, 4:44 p.m. UTC
An SNP-active guest will use the page state change VNAE MGEXIT defined in
the GHCB specification section 4.1.6 to ask the hypervisor to make the
guest page private or shared in the RMP table. In addition to the
private/shared, the guest can also ask the hypervisor to split or
combine multiple 4K validated pages as a single 2M page or vice versa.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: x86@kernel.org
Cc: kvm@vger.kernel.org
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/include/asm/sev-snp.h  | 34 +++++++++++++++++++++++++++++++++
 arch/x86/include/uapi/asm/svm.h |  1 +
 2 files changed, 35 insertions(+)

Comments

Borislav Petkov April 1, 2021, 10:32 a.m. UTC | #1
On Wed, Mar 24, 2021 at 11:44:15AM -0500, Brijesh Singh wrote:
> An SNP-active guest will use the page state change VNAE MGEXIT defined in

I guess this was supposed to mean "NAE VMGEXIT" but pls write "NAE" out
at least once so that reader can find its way around the spec.

> the GHCB specification section 4.1.6 to ask the hypervisor to make the
> guest page private or shared in the RMP table. In addition to the
> private/shared, the guest can also ask the hypervisor to split or
> combine multiple 4K validated pages as a single 2M page or vice versa.
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Joerg Roedel <jroedel@suse.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Dave Hansen <dave.hansen@intel.com>
> Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Sean Christopherson <seanjc@google.com>
> Cc: x86@kernel.org
> Cc: kvm@vger.kernel.org
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  arch/x86/include/asm/sev-snp.h  | 34 +++++++++++++++++++++++++++++++++
>  arch/x86/include/uapi/asm/svm.h |  1 +
>  2 files changed, 35 insertions(+)
> 
> diff --git a/arch/x86/include/asm/sev-snp.h b/arch/x86/include/asm/sev-snp.h
> index 5a6d1367cab7..f514dad276f2 100644
> --- a/arch/x86/include/asm/sev-snp.h
> +++ b/arch/x86/include/asm/sev-snp.h
> @@ -22,6 +22,40 @@
>  #define RMP_PG_SIZE_2M			1
>  #define RMP_PG_SIZE_4K			0
>  
> +/* Page State Change MSR Protocol */
> +#define GHCB_SNP_PAGE_STATE_CHANGE_REQ	0x0014
> +#define		GHCB_SNP_PAGE_STATE_REQ_GFN(v, o)	(GHCB_SNP_PAGE_STATE_CHANGE_REQ | \
> +							 ((unsigned long)((o) & 0xf) << 52) | \
> +							 (((v) << 12) & 0xffffffffffffff))

This macro needs to be more readable and I'm not sure the masking is
correct. IOW, something like this perhaps:

#define GHCB_SNP_PAGE_STATE_REQ_GFN(va, operation)	\
	((((operation) & 0xf) << 52) | ((va) & GENMASK_ULL(51, 12)) | GHCB_SNP_PAGE_STATE_CHANGE_REQ)

where you have each GHCBData element at the proper place, msb to lsb.
Now, GHCB spec says:

	"GHCBData[51:12] – Guest physical frame number"

and I'm not clear as to what this macro takes: a virtual address or a
pfn. If it is a pfn, then you need to do:

	(((pfn) << 12) & GENMASK_ULL(51, 0))

but if it is a virtual address you need to do what I have above. Since
you do "<< 12" then it must be a pfn already but then you should call
the argument "pfn" so that it is clear what it takes.

Your mask above covers [55:0] but [55:52] is the page operation so the
high bit in that mask needs to be 51.

AFAICT, ofc.

> +#define	SNP_PAGE_STATE_PRIVATE		1
> +#define	SNP_PAGE_STATE_SHARED		2
> +#define	SNP_PAGE_STATE_PSMASH		3
> +#define	SNP_PAGE_STATE_UNSMASH		4
> +
> +#define GHCB_SNP_PAGE_STATE_CHANGE_RESP	0x0015
> +#define		GHCB_SNP_PAGE_STATE_RESP_VAL(val)	((val) >> 32)
	  ^^^^^^^^^^^^

Some stray tabs here and above, pls pay attention to vertical alignment too.

> +
> +/* Page State Change NAE event */
> +#define SNP_PAGE_STATE_CHANGE_MAX_ENTRY		253
> +struct __packed snp_page_state_header {
> +	uint16_t cur_entry;
> +	uint16_t end_entry;
> +	uint32_t reserved;
> +};
> +
> +struct __packed snp_page_state_entry {
> +	uint64_t cur_page:12;
> +	uint64_t gfn:40;
> +	uint64_t operation:4;
> +	uint64_t pagesize:1;
> +	uint64_t reserved:7;
> +};

Any particular reason for the uint<width>_t types or can you use our
shorter u<width> types?

> +
> +struct __packed snp_page_state_change {
> +	struct snp_page_state_header header;
> +	struct snp_page_state_entry entry[SNP_PAGE_STATE_CHANGE_MAX_ENTRY];

Also, looking further into the patchset, I wonder if it would make sense
to do:

s/PAGE_STATE_CHANGE/PSC/g

to avoid breaking lines of huge statements:

+	if ((GHCB_SEV_GHCB_RESP_CODE(val) != GHCB_SNP_PAGE_STATE_CHANGE_RESP) ||
+	    (GHCB_SNP_PAGE_STATE_RESP_VAL(val) != 0))
+		sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);

and turn them into something more readable

+	if ((GHCB_SEV_GHCB_RESP_CODE(val) != GHCB_SNP_PSC_RESP) ||
+	    (GHCB_SNP_PSC_RESP_VAL(val)))
+		sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);

Also, you have GHCB_SEV and GHCB_SNP prefixes and I wonder whether we
even need them and have everything be prefixed simply GHCB_ because that
is the protocol, after all.

Which will then turn the above into:

+	if ((GHCB_RESP_CODE(val) != GHCB_PSC_RESP) || (GHCB_PSC_RESP_VAL(val)))
+		sev_es_terminate(GHCB_REASON_GENERAL_REQUEST);

Oh yeah baby! :-)

Thx.
Brijesh Singh April 1, 2021, 2:11 p.m. UTC | #2
On 4/1/21 5:32 AM, Borislav Petkov wrote:
> On Wed, Mar 24, 2021 at 11:44:15AM -0500, Brijesh Singh wrote:
>> An SNP-active guest will use the page state change VNAE MGEXIT defined in
> I guess this was supposed to mean "NAE VMGEXIT" but pls write "NAE" out
> at least once so that reader can find its way around the spec.


Noted. I will fix in next rev.

>> the GHCB specification section 4.1.6 to ask the hypervisor to make the
>> guest page private or shared in the RMP table. In addition to the
>> private/shared, the guest can also ask the hypervisor to split or
>> combine multiple 4K validated pages as a single 2M page or vice versa.
>>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Cc: Ingo Molnar <mingo@redhat.com>
>> Cc: Borislav Petkov <bp@alien8.de>
>> Cc: Joerg Roedel <jroedel@suse.de>
>> Cc: "H. Peter Anvin" <hpa@zytor.com>
>> Cc: Tony Luck <tony.luck@intel.com>
>> Cc: Dave Hansen <dave.hansen@intel.com>
>> Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Cc: Tom Lendacky <thomas.lendacky@amd.com>
>> Cc: David Rientjes <rientjes@google.com>
>> Cc: Sean Christopherson <seanjc@google.com>
>> Cc: x86@kernel.org
>> Cc: kvm@vger.kernel.org
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>  arch/x86/include/asm/sev-snp.h  | 34 +++++++++++++++++++++++++++++++++
>>  arch/x86/include/uapi/asm/svm.h |  1 +
>>  2 files changed, 35 insertions(+)
>>
>> diff --git a/arch/x86/include/asm/sev-snp.h b/arch/x86/include/asm/sev-snp.h
>> index 5a6d1367cab7..f514dad276f2 100644
>> --- a/arch/x86/include/asm/sev-snp.h
>> +++ b/arch/x86/include/asm/sev-snp.h
>> @@ -22,6 +22,40 @@
>>  #define RMP_PG_SIZE_2M			1
>>  #define RMP_PG_SIZE_4K			0
>>  
>> +/* Page State Change MSR Protocol */
>> +#define GHCB_SNP_PAGE_STATE_CHANGE_REQ	0x0014
>> +#define		GHCB_SNP_PAGE_STATE_REQ_GFN(v, o)	(GHCB_SNP_PAGE_STATE_CHANGE_REQ | \
>> +							 ((unsigned long)((o) & 0xf) << 52) | \
>> +							 (((v) << 12) & 0xffffffffffffff))
> This macro needs to be more readable and I'm not sure the masking is
> correct. IOW, something like this perhaps:
>
> #define GHCB_SNP_PAGE_STATE_REQ_GFN(va, operation)	\
> 	((((operation) & 0xf) << 52) | ((va) & GENMASK_ULL(51, 12)) | GHCB_SNP_PAGE_STATE_CHANGE_REQ)


I guess I was trying to keep it in consistent with sev-es.h macro
definitions in which the command is used before the fields. In next
version, I will use the msb to lsb ordering.


>
> where you have each GHCBData element at the proper place, msb to lsb.
> Now, GHCB spec says:
>
> 	"GHCBData[51:12] – Guest physical frame number"
>
> and I'm not clear as to what this macro takes: a virtual address or a
> pfn. If it is a pfn, then you need to do:
>
> 	(((pfn) << 12) & GENMASK_ULL(51, 0))
>
> but if it is a virtual address you need to do what I have above. Since
> you do "<< 12" then it must be a pfn already but then you should call
> the argument "pfn" so that it is clear what it takes.


Yes, the macro takes the pfn.

> Your mask above covers [55:0] but [55:52] is the page operation so the
> high bit in that mask needs to be 51.

Ack. I will limit the mask to 51 so that we don't go outside the pfn
field width. thank you for pointing it.


> AFAICT, ofc.
>
>> +#define	SNP_PAGE_STATE_PRIVATE		1
>> +#define	SNP_PAGE_STATE_SHARED		2
>> +#define	SNP_PAGE_STATE_PSMASH		3
>> +#define	SNP_PAGE_STATE_UNSMASH		4
>> +
>> +#define GHCB_SNP_PAGE_STATE_CHANGE_RESP	0x0015
>> +#define		GHCB_SNP_PAGE_STATE_RESP_VAL(val)	((val) >> 32)
> 	  ^^^^^^^^^^^^
>
> Some stray tabs here and above, pls pay attention to vertical alignment too.


I noticed that sev-es.h uses tab when defining the macro to build
command. Another example where I tried to keep a bit consistentency with
sev-es.h. I will drop it in next rev.


>
>> +
>> +/* Page State Change NAE event */
>> +#define SNP_PAGE_STATE_CHANGE_MAX_ENTRY		253
>> +struct __packed snp_page_state_header {
>> +	uint16_t cur_entry;
>> +	uint16_t end_entry;
>> +	uint32_t reserved;
>> +};
>> +
>> +struct __packed snp_page_state_entry {
>> +	uint64_t cur_page:12;
>> +	uint64_t gfn:40;
>> +	uint64_t operation:4;
>> +	uint64_t pagesize:1;
>> +	uint64_t reserved:7;
>> +};
> Any particular reason for the uint<width>_t types or can you use our
> shorter u<width> types?

IIRC, the spec structure has uint<width>_t, so I used it as-is. No
strong reason for using it. I will switch to u64 type in the next version.


>
>> +
>> +struct __packed snp_page_state_change {
>> +	struct snp_page_state_header header;
>> +	struct snp_page_state_entry entry[SNP_PAGE_STATE_CHANGE_MAX_ENTRY];
> Also, looking further into the patchset, I wonder if it would make sense
> to do:
>
> s/PAGE_STATE_CHANGE/PSC/g
>
> to avoid breaking lines of huge statements:
>
> +	if ((GHCB_SEV_GHCB_RESP_CODE(val) != GHCB_SNP_PAGE_STATE_CHANGE_RESP) ||
> +	    (GHCB_SNP_PAGE_STATE_RESP_VAL(val) != 0))
> +		sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);
>
> and turn them into something more readable
>
> +	if ((GHCB_SEV_GHCB_RESP_CODE(val) != GHCB_SNP_PSC_RESP) ||
> +	    (GHCB_SNP_PSC_RESP_VAL(val)))
> +		sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);
>
> Also, you have GHCB_SEV and GHCB_SNP prefixes and I wonder whether we
> even need them and have everything be prefixed simply GHCB_ because that
> is the protocol, after all.
>
> Which will then turn the above into:
>
> +	if ((GHCB_RESP_CODE(val) != GHCB_PSC_RESP) || (GHCB_PSC_RESP_VAL(val)))
> +		sev_es_terminate(GHCB_REASON_GENERAL_REQUEST);
>
> Oh yeah baby! :-)

It looks much better :-). I am good with dropping GHCB_{SEV,SNP} prefix,
and also rename the PAGE_STATE_CHANGE to PSC. Thanks.

>
> Thx.
>
Borislav Petkov April 2, 2021, 3:44 p.m. UTC | #3
On Thu, Apr 01, 2021 at 09:11:34AM -0500, Brijesh Singh wrote:
> I guess I was trying to keep it in consistent with sev-es.h macro
> definitions in which the command is used before the fields. In next
> version, I will use the msb to lsb ordering.

Yes pls. And then you could fix the sev-es.h macro too, in a prepatch
maybe or in the same one, to do the same so that when reading the GHCB
doc, it maps directly to the macros.

> IIRC, the spec structure has uint<width>_t, so I used it as-is. No
> strong reason for using it. I will switch to u64 type in the next version.

Yeah, the uint* things are in the C spec but we don't need this
definition outside the kernel, right?

Thx.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/sev-snp.h b/arch/x86/include/asm/sev-snp.h
index 5a6d1367cab7..f514dad276f2 100644
--- a/arch/x86/include/asm/sev-snp.h
+++ b/arch/x86/include/asm/sev-snp.h
@@ -22,6 +22,40 @@ 
 #define RMP_PG_SIZE_2M			1
 #define RMP_PG_SIZE_4K			0
 
+/* Page State Change MSR Protocol */
+#define GHCB_SNP_PAGE_STATE_CHANGE_REQ	0x0014
+#define		GHCB_SNP_PAGE_STATE_REQ_GFN(v, o)	(GHCB_SNP_PAGE_STATE_CHANGE_REQ | \
+							 ((unsigned long)((o) & 0xf) << 52) | \
+							 (((v) << 12) & 0xffffffffffffff))
+#define	SNP_PAGE_STATE_PRIVATE		1
+#define	SNP_PAGE_STATE_SHARED		2
+#define	SNP_PAGE_STATE_PSMASH		3
+#define	SNP_PAGE_STATE_UNSMASH		4
+
+#define GHCB_SNP_PAGE_STATE_CHANGE_RESP	0x0015
+#define		GHCB_SNP_PAGE_STATE_RESP_VAL(val)	((val) >> 32)
+
+/* Page State Change NAE event */
+#define SNP_PAGE_STATE_CHANGE_MAX_ENTRY		253
+struct __packed snp_page_state_header {
+	uint16_t cur_entry;
+	uint16_t end_entry;
+	uint32_t reserved;
+};
+
+struct __packed snp_page_state_entry {
+	uint64_t cur_page:12;
+	uint64_t gfn:40;
+	uint64_t operation:4;
+	uint64_t pagesize:1;
+	uint64_t reserved:7;
+};
+
+struct __packed snp_page_state_change {
+	struct snp_page_state_header header;
+	struct snp_page_state_entry entry[SNP_PAGE_STATE_CHANGE_MAX_ENTRY];
+};
+
 #ifdef CONFIG_AMD_MEM_ENCRYPT
 static inline int __pvalidate(unsigned long vaddr, int rmp_psize, int validate,
 			      unsigned long *rflags)
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index 554f75fe013c..751867aa432f 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -108,6 +108,7 @@ 
 #define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005
 #define SVM_VMGEXIT_SET_AP_JUMP_TABLE		0
 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE		1
+#define SVM_VMGEXIT_PAGE_STATE_CHANGE		0x80000010
 #define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffff
 
 #define SVM_EXIT_ERR           -1