Skip to content

Commit 8c29f01

Browse files
nikunjadbp3tk0v
authored andcommitted
x86/sev: Add SEV-SNP guest feature negotiation support
The hypervisor can enable various new features (SEV_FEATURES[1:63]) and start a SNP guest. Some of these features need guest side implementation. If any of these features are enabled without it, the behavior of the SNP guest will be undefined. It may fail booting in a non-obvious way making it difficult to debug. Instead of allowing the guest to continue and have it fail randomly later, detect this early and fail gracefully. The SEV_STATUS MSR indicates features which the hypervisor has enabled. While booting, SNP guests should ascertain that all the enabled features have guest side implementation. In case a feature is not implemented in the guest, the guest terminates booting with GHCB protocol Non-Automatic Exit(NAE) termination request event, see "SEV-ES Guest-Hypervisor Communication Block Standardization" document (currently at https://developer.amd.com/wp-content/resources/56421.pdf), section "Termination Request". Populate SW_EXITINFO2 with mask of unsupported features that the hypervisor can easily report to the user. More details in the AMD64 APM Vol 2, Section "SEV_STATUS MSR". [ bp: - Massage. - Move snp_check_features() call to C code. Note: the CC:stable@ aspect here is to be able to protect older, stable kernels when running on newer hypervisors. Or not "running" but fail reliably and in a well-defined manner instead of randomly. ] Fixes: cbd3d4f ("x86/sev: Check SEV-SNP features support") Signed-off-by: Nikunj A Dadhania <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Tom Lendacky <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6c79699 commit 8c29f01

File tree

6 files changed

+140
-0
lines changed

6 files changed

+140
-0
lines changed

Documentation/x86/amd-memory-encryption.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,39 @@ by supplying mem_encrypt=on on the kernel command line. However, if BIOS does
9595
not enable SME, then Linux will not be able to activate memory encryption, even
9696
if configured to do so by default or the mem_encrypt=on command line parameter
9797
is specified.
98+
99+
Secure Nested Paging (SNP)
100+
==========================
101+
102+
SEV-SNP introduces new features (SEV_FEATURES[1:63]) which can be enabled
103+
by the hypervisor for security enhancements. Some of these features need
104+
guest side implementation to function correctly. The below table lists the
105+
expected guest behavior with various possible scenarios of guest/hypervisor
106+
SNP feature support.
107+
108+
+-----------------+---------------+---------------+------------------+
109+
| Feature Enabled | Guest needs | Guest has | Guest boot |
110+
| by the HV | implementation| implementation| behaviour |
111+
+=================+===============+===============+==================+
112+
| No | No | No | Boot |
113+
| | | | |
114+
+-----------------+---------------+---------------+------------------+
115+
| No | Yes | No | Boot |
116+
| | | | |
117+
+-----------------+---------------+---------------+------------------+
118+
| No | Yes | Yes | Boot |
119+
| | | | |
120+
+-----------------+---------------+---------------+------------------+
121+
| Yes | No | No | Boot with |
122+
| | | | feature enabled |
123+
+-----------------+---------------+---------------+------------------+
124+
| Yes | Yes | No | Graceful boot |
125+
| | | | failure |
126+
+-----------------+---------------+---------------+------------------+
127+
| Yes | Yes | Yes | Boot with |
128+
| | | | feature enabled |
129+
+-----------------+---------------+---------------+------------------+
130+
131+
More details in AMD64 APM[1] Vol 2: 15.34.10 SEV_STATUS MSR
132+
133+
[1] https://www.amd.com/system/files/TechDocs/40332.pdf

arch/x86/boot/compressed/ident_map_64.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ void initialize_identity_maps(void *rmode)
180180

181181
/* Load the new page-table. */
182182
write_cr3(top_level_pgt);
183+
184+
/*
185+
* Now that the required page table mappings are established and a
186+
* GHCB can be used, check for SNP guest/HV feature compatibility.
187+
*/
188+
snp_check_features();
183189
}
184190

185191
static pte_t *split_large_pmd(struct x86_mapping_info *info,

arch/x86/boot/compressed/misc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ static inline void console_init(void)
126126

127127
#ifdef CONFIG_AMD_MEM_ENCRYPT
128128
void sev_enable(struct boot_params *bp);
129+
void snp_check_features(void);
129130
void sev_es_shutdown_ghcb(void);
130131
extern bool sev_es_check_ghcb_fault(unsigned long address);
131132
void snp_set_page_private(unsigned long paddr);
@@ -143,6 +144,7 @@ static inline void sev_enable(struct boot_params *bp)
143144
if (bp)
144145
bp->cc_blob_address = 0;
145146
}
147+
static inline void snp_check_features(void) { }
146148
static inline void sev_es_shutdown_ghcb(void) { }
147149
static inline bool sev_es_check_ghcb_fault(unsigned long address)
148150
{

arch/x86/boot/compressed/sev.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ void sev_es_shutdown_ghcb(void)
208208
error("Can't unmap GHCB page");
209209
}
210210

211+
static void __noreturn sev_es_ghcb_terminate(struct ghcb *ghcb, unsigned int set,
212+
unsigned int reason, u64 exit_info_2)
213+
{
214+
u64 exit_info_1 = SVM_VMGEXIT_TERM_REASON(set, reason);
215+
216+
vc_ghcb_invalidate(ghcb);
217+
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_TERM_REQUEST);
218+
ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
219+
ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
220+
221+
sev_es_wr_ghcb_msr(__pa(ghcb));
222+
VMGEXIT();
223+
224+
while (true)
225+
asm volatile("hlt\n" : : : "memory");
226+
}
227+
211228
bool sev_es_check_ghcb_fault(unsigned long address)
212229
{
213230
/* Check whether the fault was on the GHCB page */
@@ -270,6 +287,59 @@ static void enforce_vmpl0(void)
270287
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
271288
}
272289

290+
/*
291+
* SNP_FEATURES_IMPL_REQ is the mask of SNP features that will need
292+
* guest side implementation for proper functioning of the guest. If any
293+
* of these features are enabled in the hypervisor but are lacking guest
294+
* side implementation, the behavior of the guest will be undefined. The
295+
* guest could fail in non-obvious way making it difficult to debug.
296+
*
297+
* As the behavior of reserved feature bits is unknown to be on the
298+
* safe side add them to the required features mask.
299+
*/
300+
#define SNP_FEATURES_IMPL_REQ (MSR_AMD64_SNP_VTOM | \
301+
MSR_AMD64_SNP_REFLECT_VC | \
302+
MSR_AMD64_SNP_RESTRICTED_INJ | \
303+
MSR_AMD64_SNP_ALT_INJ | \
304+
MSR_AMD64_SNP_DEBUG_SWAP | \
305+
MSR_AMD64_SNP_VMPL_SSS | \
306+
MSR_AMD64_SNP_SECURE_TSC | \
307+
MSR_AMD64_SNP_VMGEXIT_PARAM | \
308+
MSR_AMD64_SNP_VMSA_REG_PROTECTION | \
309+
MSR_AMD64_SNP_RESERVED_BIT13 | \
310+
MSR_AMD64_SNP_RESERVED_BIT15 | \
311+
MSR_AMD64_SNP_RESERVED_MASK)
312+
313+
/*
314+
* SNP_FEATURES_PRESENT is the mask of SNP features that are implemented
315+
* by the guest kernel. As and when a new feature is implemented in the
316+
* guest kernel, a corresponding bit should be added to the mask.
317+
*/
318+
#define SNP_FEATURES_PRESENT (0)
319+
320+
void snp_check_features(void)
321+
{
322+
u64 unsupported;
323+
324+
if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
325+
return;
326+
327+
/*
328+
* Terminate the boot if hypervisor has enabled any feature lacking
329+
* guest side implementation. Pass on the unsupported features mask through
330+
* EXIT_INFO_2 of the GHCB protocol so that those features can be reported
331+
* as part of the guest boot failure.
332+
*/
333+
unsupported = sev_status & SNP_FEATURES_IMPL_REQ & ~SNP_FEATURES_PRESENT;
334+
if (unsupported) {
335+
if (ghcb_version < 2 || (!boot_ghcb && !early_setup_ghcb()))
336+
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
337+
338+
sev_es_ghcb_terminate(boot_ghcb, SEV_TERM_SET_GEN,
339+
GHCB_SNP_UNSUPPORTED, unsupported);
340+
}
341+
}
342+
273343
void sev_enable(struct boot_params *bp)
274344
{
275345
unsigned int eax, ebx, ecx, edx;

arch/x86/include/asm/msr-index.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,26 @@
566566
#define MSR_AMD64_SEV_ES_ENABLED BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT)
567567
#define MSR_AMD64_SEV_SNP_ENABLED BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)
568568

569+
/* SNP feature bits enabled by the hypervisor */
570+
#define MSR_AMD64_SNP_VTOM BIT_ULL(3)
571+
#define MSR_AMD64_SNP_REFLECT_VC BIT_ULL(4)
572+
#define MSR_AMD64_SNP_RESTRICTED_INJ BIT_ULL(5)
573+
#define MSR_AMD64_SNP_ALT_INJ BIT_ULL(6)
574+
#define MSR_AMD64_SNP_DEBUG_SWAP BIT_ULL(7)
575+
#define MSR_AMD64_SNP_PREVENT_HOST_IBS BIT_ULL(8)
576+
#define MSR_AMD64_SNP_BTB_ISOLATION BIT_ULL(9)
577+
#define MSR_AMD64_SNP_VMPL_SSS BIT_ULL(10)
578+
#define MSR_AMD64_SNP_SECURE_TSC BIT_ULL(11)
579+
#define MSR_AMD64_SNP_VMGEXIT_PARAM BIT_ULL(12)
580+
#define MSR_AMD64_SNP_IBS_VIRT BIT_ULL(14)
581+
#define MSR_AMD64_SNP_VMSA_REG_PROTECTION BIT_ULL(16)
582+
#define MSR_AMD64_SNP_SMT_PROTECTION BIT_ULL(17)
583+
584+
/* SNP feature bits reserved for future use. */
585+
#define MSR_AMD64_SNP_RESERVED_BIT13 BIT_ULL(13)
586+
#define MSR_AMD64_SNP_RESERVED_BIT15 BIT_ULL(15)
587+
#define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, 18)
588+
569589
#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f
570590

571591
/* AMD Collaborative Processor Performance Control MSRs */

arch/x86/include/uapi/asm/svm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@
116116
#define SVM_VMGEXIT_AP_CREATE 1
117117
#define SVM_VMGEXIT_AP_DESTROY 2
118118
#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd
119+
#define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe
120+
#define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code) \
121+
/* SW_EXITINFO1[3:0] */ \
122+
(((((u64)reason_set) & 0xf)) | \
123+
/* SW_EXITINFO1[11:4] */ \
124+
((((u64)reason_code) & 0xff) << 4))
119125
#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
120126

121127
/* Exit code reserved for hypervisor/software use */

0 commit comments

Comments
 (0)