Skip to content

Commit 2a78306

Browse files
ashkalrabp3tk0v
authored andcommitted
x86/mm: Refactor __set_clr_pte_enc()
Refactor __set_clr_pte_enc() and add two new helper functions to set/clear PTE C-bit from early SEV/SNP initialization code and later during shutdown/kexec especially when all CPUs are stopped and interrupts are disabled and set_memory_xx() interfaces can't be used. Co-developed-by: Borislav Petkov (AMD) <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Signed-off-by: Ashish Kalra <[email protected]> Reviewed-by: Tom Lendacky <[email protected]> Link: https://lore.kernel.org/r/5df4aa450447f28294d1c5a890e27b63ed4ded36.1722520012.git.ashish.kalra@amd.com
1 parent f30470c commit 2a78306

File tree

2 files changed

+69
-26
lines changed

2 files changed

+69
-26
lines changed

arch/x86/include/asm/sev.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,22 @@ struct svsm_attest_call {
322322
u8 rsvd[4];
323323
};
324324

325+
/* PTE descriptor used for the prepare_pte_enc() operations. */
326+
struct pte_enc_desc {
327+
pte_t *kpte;
328+
int pte_level;
329+
bool encrypt;
330+
/* pfn of the kpte above */
331+
unsigned long pfn;
332+
/* physical address of @pfn */
333+
unsigned long pa;
334+
/* virtual address of @pfn */
335+
void *va;
336+
/* memory covered by the pte */
337+
unsigned long size;
338+
pgprot_t new_pgprot;
339+
};
340+
325341
/*
326342
* SVSM protocol structure
327343
*/
@@ -437,6 +453,8 @@ u64 snp_get_unsupported_features(u64 status);
437453
u64 sev_get_status(void);
438454
void sev_show_status(void);
439455
void snp_update_svsm_ca(void);
456+
int prepare_pte_enc(struct pte_enc_desc *d);
457+
void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot);
440458

441459
#else /* !CONFIG_AMD_MEM_ENCRYPT */
442460

@@ -474,6 +492,8 @@ static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
474492
static inline u64 sev_get_status(void) { return 0; }
475493
static inline void sev_show_status(void) { }
476494
static inline void snp_update_svsm_ca(void) { }
495+
static inline int prepare_pte_enc(struct pte_enc_desc *d) { return 0; }
496+
static inline void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot) { }
477497

478498
#endif /* CONFIG_AMD_MEM_ENCRYPT */
479499

arch/x86/mm/mem_encrypt_amd.c

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -311,59 +311,82 @@ static int amd_enc_status_change_finish(unsigned long vaddr, int npages, bool en
311311
return 0;
312312
}
313313

314-
static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
314+
int prepare_pte_enc(struct pte_enc_desc *d)
315315
{
316-
pgprot_t old_prot, new_prot;
317-
unsigned long pfn, pa, size;
318-
pte_t new_pte;
316+
pgprot_t old_prot;
319317

320-
pfn = pg_level_to_pfn(level, kpte, &old_prot);
321-
if (!pfn)
322-
return;
318+
d->pfn = pg_level_to_pfn(d->pte_level, d->kpte, &old_prot);
319+
if (!d->pfn)
320+
return 1;
323321

324-
new_prot = old_prot;
325-
if (enc)
326-
pgprot_val(new_prot) |= _PAGE_ENC;
322+
d->new_pgprot = old_prot;
323+
if (d->encrypt)
324+
pgprot_val(d->new_pgprot) |= _PAGE_ENC;
327325
else
328-
pgprot_val(new_prot) &= ~_PAGE_ENC;
326+
pgprot_val(d->new_pgprot) &= ~_PAGE_ENC;
329327

330328
/* If prot is same then do nothing. */
331-
if (pgprot_val(old_prot) == pgprot_val(new_prot))
332-
return;
329+
if (pgprot_val(old_prot) == pgprot_val(d->new_pgprot))
330+
return 1;
333331

334-
pa = pfn << PAGE_SHIFT;
335-
size = page_level_size(level);
332+
d->pa = d->pfn << PAGE_SHIFT;
333+
d->size = page_level_size(d->pte_level);
336334

337335
/*
338-
* We are going to perform in-place en-/decryption and change the
339-
* physical page attribute from C=1 to C=0 or vice versa. Flush the
340-
* caches to ensure that data gets accessed with the correct C-bit.
336+
* In-place en-/decryption and physical page attribute change
337+
* from C=1 to C=0 or vice versa will be performed. Flush the
338+
* caches to ensure that data gets accessed with the correct
339+
* C-bit.
341340
*/
342-
clflush_cache_range(__va(pa), size);
341+
if (d->va)
342+
clflush_cache_range(d->va, d->size);
343+
else
344+
clflush_cache_range(__va(d->pa), d->size);
345+
346+
return 0;
347+
}
348+
349+
void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot)
350+
{
351+
pte_t new_pte;
352+
353+
/* Change the page encryption mask. */
354+
new_pte = pfn_pte(pfn, new_prot);
355+
set_pte_atomic(kpte, new_pte);
356+
}
357+
358+
static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
359+
{
360+
struct pte_enc_desc d = {
361+
.kpte = kpte,
362+
.pte_level = level,
363+
.encrypt = enc
364+
};
365+
366+
if (prepare_pte_enc(&d))
367+
return;
343368

344369
/* Encrypt/decrypt the contents in-place */
345370
if (enc) {
346-
sme_early_encrypt(pa, size);
371+
sme_early_encrypt(d.pa, d.size);
347372
} else {
348-
sme_early_decrypt(pa, size);
373+
sme_early_decrypt(d.pa, d.size);
349374

350375
/*
351376
* ON SNP, the page state in the RMP table must happen
352377
* before the page table updates.
353378
*/
354-
early_snp_set_memory_shared((unsigned long)__va(pa), pa, 1);
379+
early_snp_set_memory_shared((unsigned long)__va(d.pa), d.pa, 1);
355380
}
356381

357-
/* Change the page encryption mask. */
358-
new_pte = pfn_pte(pfn, new_prot);
359-
set_pte_atomic(kpte, new_pte);
382+
set_pte_enc_mask(kpte, d.pfn, d.new_pgprot);
360383

361384
/*
362385
* If page is set encrypted in the page table, then update the RMP table to
363386
* add this page as private.
364387
*/
365388
if (enc)
366-
early_snp_set_memory_private((unsigned long)__va(pa), pa, 1);
389+
early_snp_set_memory_private((unsigned long)__va(d.pa), d.pa, 1);
367390
}
368391

369392
static int __init early_set_memory_enc_dec(unsigned long vaddr,

0 commit comments

Comments
 (0)