Skip to content

Commit bbb6b14

Browse files
ardbiesheuvelgregkh
authored andcommitted
x86/boot/sev: Avoid shared GHCB page for early memory acceptance
commit d54d610243a4508183978871e5faff5502786cd4 upstream. Communicating with the hypervisor using the shared GHCB page requires clearing the C bit in the mapping of that page. When executing in the context of the EFI boot services, the page tables are owned by the firmware, and this manipulation is not possible. So switch to a different API for accepting memory in SEV-SNP guests, one which is actually supported at the point during boot where the EFI stub may need to accept memory, but the SEV-SNP init code has not executed yet. For simplicity, also switch the memory acceptance carried out by the decompressor when not booting via EFI - this only involves the allocation for the decompressed kernel, and is generally only called after kexec, as normal boot will jump straight into the kernel from the EFI stub. Fixes: 6c32117 ("x86/sev: Add SNP-specific unaccepted memory support") Tested-by: Tom Lendacky <[email protected]> Co-developed-by: Tom Lendacky <[email protected]> Signed-off-by: Tom Lendacky <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Cc: <[email protected]> Cc: Dionna Amalie Glaze <[email protected]> Cc: Kevin Loughlin <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] # discussion thread #1 Link: https://lore.kernel.org/r/[email protected] # discussion thread #2 Link: https://lore.kernel.org/r/[email protected] # final submission Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 5e03634 commit bbb6b14

File tree

3 files changed

+21
-53
lines changed

3 files changed

+21
-53
lines changed

arch/x86/boot/compressed/mem.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ static bool early_is_tdx_guest(void)
3434

3535
void arch_accept_memory(phys_addr_t start, phys_addr_t end)
3636
{
37+
static bool sevsnp;
38+
3739
/* Platform-specific memory-acceptance call goes here */
3840
if (early_is_tdx_guest()) {
3941
if (!tdx_accept_memory(start, end))
4042
panic("TDX: Failed to accept memory\n");
41-
} else if (sev_snp_enabled()) {
43+
} else if (sevsnp || (sev_get_status() & MSR_AMD64_SEV_SNP_ENABLED)) {
44+
sevsnp = true;
4245
snp_accept_memory(start, end);
4346
} else {
4447
error("Cannot accept memory: unknown platform\n");

arch/x86/boot/compressed/sev.c

Lines changed: 15 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,7 @@ bool sev_snp_enabled(void)
135135

136136
static void __page_state_change(unsigned long paddr, enum psc_op op)
137137
{
138-
u64 val;
139-
140-
if (!sev_snp_enabled())
141-
return;
138+
u64 val, msr;
142139

143140
/*
144141
* If private -> shared then invalidate the page before requesting the
@@ -147,6 +144,9 @@ static void __page_state_change(unsigned long paddr, enum psc_op op)
147144
if (op == SNP_PAGE_STATE_SHARED && pvalidate(paddr, RMP_PG_SIZE_4K, 0))
148145
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
149146

147+
/* Save the current GHCB MSR value */
148+
msr = sev_es_rd_ghcb_msr();
149+
150150
/* Issue VMGEXIT to change the page state in RMP table. */
151151
sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
152152
VMGEXIT();
@@ -156,6 +156,9 @@ static void __page_state_change(unsigned long paddr, enum psc_op op)
156156
if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val))
157157
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
158158

159+
/* Restore the GHCB MSR value */
160+
sev_es_wr_ghcb_msr(msr);
161+
159162
/*
160163
* Now that page state is changed in the RMP table, validate it so that it is
161164
* consistent with the RMP entry.
@@ -166,11 +169,17 @@ static void __page_state_change(unsigned long paddr, enum psc_op op)
166169

167170
void snp_set_page_private(unsigned long paddr)
168171
{
172+
if (!sev_snp_enabled())
173+
return;
174+
169175
__page_state_change(paddr, SNP_PAGE_STATE_PRIVATE);
170176
}
171177

172178
void snp_set_page_shared(unsigned long paddr)
173179
{
180+
if (!sev_snp_enabled())
181+
return;
182+
174183
__page_state_change(paddr, SNP_PAGE_STATE_SHARED);
175184
}
176185

@@ -194,56 +203,10 @@ static bool early_setup_ghcb(void)
194203
return true;
195204
}
196205

197-
static phys_addr_t __snp_accept_memory(struct snp_psc_desc *desc,
198-
phys_addr_t pa, phys_addr_t pa_end)
199-
{
200-
struct psc_hdr *hdr;
201-
struct psc_entry *e;
202-
unsigned int i;
203-
204-
hdr = &desc->hdr;
205-
memset(hdr, 0, sizeof(*hdr));
206-
207-
e = desc->entries;
208-
209-
i = 0;
210-
while (pa < pa_end && i < VMGEXIT_PSC_MAX_ENTRY) {
211-
hdr->end_entry = i;
212-
213-
e->gfn = pa >> PAGE_SHIFT;
214-
e->operation = SNP_PAGE_STATE_PRIVATE;
215-
if (IS_ALIGNED(pa, PMD_SIZE) && (pa_end - pa) >= PMD_SIZE) {
216-
e->pagesize = RMP_PG_SIZE_2M;
217-
pa += PMD_SIZE;
218-
} else {
219-
e->pagesize = RMP_PG_SIZE_4K;
220-
pa += PAGE_SIZE;
221-
}
222-
223-
e++;
224-
i++;
225-
}
226-
227-
if (vmgexit_psc(boot_ghcb, desc))
228-
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
229-
230-
pvalidate_pages(desc);
231-
232-
return pa;
233-
}
234-
235206
void snp_accept_memory(phys_addr_t start, phys_addr_t end)
236207
{
237-
struct snp_psc_desc desc = {};
238-
unsigned int i;
239-
phys_addr_t pa;
240-
241-
if (!boot_ghcb && !early_setup_ghcb())
242-
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
243-
244-
pa = start;
245-
while (pa < end)
246-
pa = __snp_accept_memory(&desc, pa, end);
208+
for (phys_addr_t pa = start; pa < end; pa += PAGE_SIZE)
209+
__page_state_change(pa, SNP_PAGE_STATE_PRIVATE);
247210
}
248211

249212
void sev_es_shutdown_ghcb(void)

arch/x86/boot/compressed/sev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212

1313
bool sev_snp_enabled(void);
1414
void snp_accept_memory(phys_addr_t start, phys_addr_t end);
15+
u64 sev_get_status(void);
1516

1617
#else
1718

1819
static inline bool sev_snp_enabled(void) { return false; }
1920
static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
21+
static inline u64 sev_get_status(void) { return 0; }
2022

2123
#endif
2224

0 commit comments

Comments
 (0)